
Triage offengelegter Anmeldeinformationen und sensibler Daten in Dateifreigaben
Triage von offengelegten Zugangsdaten und sensiblen Daten in Dateifreigaben.
Wenn eine offene Freigabe auftaucht, lautet die Frage nie „Hat dieses Repository einen geleakten Schlüssel?“, sondern „Was wurde gerade offengelegt, und was muss ich noch vor Feierabend rotieren?“ Genau für diese Frage ist sift gebaut: hoher Recall, eine schnelle Review-Warteschlange und eine Feedback-Schleife, damit aus allem, was du mit bloßem Auge entdeckst, eine Regel wird, die die anderen zweihundert Kopien findet.

Python 3.11+, nur Standardbibliothek. Kein pip install, kein Internet, kein Build-Schritt. Es läuft auf einem abgeriegelten IR-Laptop – genau dort, wo du es brauchst.```bash sift survey \fileserver\openshare # how big is this thing sift copy \fileserver\openshare C:\IR\case-4471 # take a throttled copy sift scan C:\IR\case-4471 # scan it, opens the triage UI
Auch das Scannen an Ort und Stelle funktioniert. Probieren Sie es zuerst mit einer Freigabe mit erfundenen Anmeldedaten aus:```bash
sift demo C:\temp\demoshare
sift.cmd ist ein Launcher, der aus jedem Verzeichnis funktioniert. Um sift statt
des vollständigen Pfads einzugeben, fügen Sie C:\Dev\sift zum PATH hinzu:```bash
setx PATH "%PATH%;C:\Dev\sift"
Für eine Maschine ganz ohne Python erstellt `python build_portable.py` `dist/sift-secrets-<version>-portable-win64.zip`: die offizielle embeddable Laufzeitumgebung von python.org plus diesen Quellbaum, entpacken und ausführen über das gebündelte `sift.cmd`. ~11 MB, keine Installation, keine Admin-Rechte, und nichts darin ist kompiliert oder neu verpackt – siehe den Docstring in `build_portable.py` für die Begründung, warum das einem eingefrorenen .exe auf einem abgesicherten IR-Laptop überlegen ist.
---
## Warum nicht einfach gitleaks oder trufflehog
Beide sind gute Werkzeuge, die ein anderes Problem lösen.
Sie sind **Präzisions**werkzeuge, die für CI gebaut wurden, wo ein False Positive einem Entwickler den Nachmittag kostet – sie feuern also hauptsächlich auf Dinge, die wie ein bekannter Vendor-API-Schlüssel geformt sind. trufflehog geht noch weiter und bevorzugt Geheimnisse, die es *verifizieren* kann, indem es die API des Anbieters aufruft, ein wirklich exzellentes Signal, das Regex nicht reproduzieren kann.
Die Triage auf Dateifreigaben kehrt die Ökonomie um. Ein Mensch liest ohnehin jeden Treffer, ein False Positive kostet also drei Sekunden. Was dich etwas kostet, ist ein **Übersehen**.
Vendor-API-Schlüssel lecken definitiv auf Freigaben – ein Web-Root-Backup, ein Deployment-Skript, der Projektordner von jemandem aufs Abteilungslaufwerk kopiert, und da ist eine `.env` mit einem aktiven Stripe-Schlüssel drin. Die zu fangen lohnt sich, und sift fängt sie. Aber das ist auch der Teil, den gitleaks und trufflehog bereits gut abdecken. Die Lücke ist alles andere, und auf einer Dateifreigabe ist es der Großteil:
| Was die CI-Scanner übersehen | Warum sie daran vorbeigehen |
|---|---|
| `web.config` mit einer SQL-Verbindungszeichenfolge | Kein bekanntes Schlüsselformat, kein Anbieter zum Verifizieren |
| `Map-Drives.ps1` mit `net use ... /user:` | Nur ein Shell-Befehl mit einem Wort dahinter |
| `New Hire Setup Guide.docx` | Office-Datei, wird als Binärdaten gelesen, komplett übersprungen |
| `unattend.xml`, GPP `Groups.xml` | Windows-Deployment-Artefakte, für die niemand einen Detektor geschrieben hat |
| `confCons.xml`, `.rdg`, WinSCP.ini | Umkehrbar gespeicherte Passwörter, aber kein „geheimes Format“ |
| `passwords.xlsx` | Es ist eine ZIP. Klartext-Scanner sehen Binärdaten und machen weiter |
| `.kdbx`, `.pfx`, `id_rsa` | Undurchsichtige Bytes – der *Dateiname* ist der Fund |
| Eine `.bak` mit einer Verbindungszeichenfolge darin | Binär, also nie gelesen |
sift deckt diese ab, bringt eigene Vendor-Key-Regeln mit und **importiert die Regelpakete und Funde anderer Werkzeuge** – gitleaks-TOML, Kingfisher/Titus-YAML und trufflehog-JSON – du musst dich also nicht zwischen den Werkzeugen entscheiden.
Der nächste verwandte Ansatz ist [Snaffler](https://github.com/SnaffCon/Snaffler), der bei der Dateinamen-und-Klassifizierungs-Hälfte davon exzellent ist und die direkte Inspiration für die Dateinamen-Regeln darstellt. Was er nicht hat – und was sich als der eigentliche Engpass herausstellt, sobald du 400 Treffer hast – ist eine Review-Schleife.
---
## Die Schleife
1. **Scanne** die Freigabe.
2. **Arbeite die Warteschlange ab.** Jeder Fund zeigt die umgebenden Zeilen mit hervorgehobenem Treffer. Pfeiltasten erweitern den Kontext; ein Klick öffnet die gesamte Datei in VS Code an dieser Zeile, oder in Notepad.
3. **Entdecke einen übersehenen Fund.** Das wirst du. Markiere ihn in der Vorschau und drücke `r`.
4. **sift schlägt Muster vor** und zeigt dir live, wie oft jedes Muster auf alles bereits Gelesene passen würde.
5. **Speichere es.** Der gecachte Rescan dauert etwa eine Sekunde, und die neuen Treffer erscheinen in der Warteschlange, während deine bestehenden Triage-Entscheidungen unangetastet bleiben.
Schritt 5 ist der Teil, der den Rest lohnenswert macht. Funde sind auf `(path, rule, line, value-hash)` geschlüsselt, sodass ein Rescan dieselben Zeilen wieder einfügt und dein Status, deine Notizen und der Besitzer mitwandern. Ohne das würdest du bei jeder Iteration dieselben 300 Treffer erneut prüfen und beim dritten Mal aufgeben.
---
## Befehle```bash
# size it up first: file count, total bytes, biggest folders, transfer estimates
sift survey \\fileserver\share
# take a rate-limited local copy (resumable; gentle = 5 MB/s by default)
sift copy \\fileserver\share C:\IR\case-4471 --speed gentle
# scan a share and open the triage UI
sift scan \\fileserver\share
# maximum recall: more noise, but a human is reading anyway
sift scan D:\dfs\dept --tier 3
# re-open the UI over the most recent scan
sift ui
# build a share of fabricated credentials, scan it, open the UI
sift demo C:\temp\demoshare
# inherit other tools' vendor-key rules, then use them in the live rescan loop
sift import-rules gitleaks.toml # gitleaks TOML
sift import-rules path/to/kingfisher/data/rules # a directory of YAML
# pull in what the other scanners found, into the same queue
trufflehog filesystem \\fileserver\share --json > th.json
sift import-findings th.json
# hand off to the incident record (redacted unless you say otherwise)
sift export --fmt pdf --status confirmed --out ir-4471.pdf
sift export --fmt csv --out ir-4471.csv
sift export --fmt pdf --no-redact # plaintext; handle as evidence
sift rules # what is loaded
sift selftest # detection tests against a synthetic share
# ask vendors whether confirmed findings are still live. NETWORK. Opt-in.
sift validate --status confirmed
Überall, wo sift steht, kannst du stattdessen python -m sift verwenden, und zwar aus dem Verzeichnis C:\Dev\sift.
Befunde gehen in einen pro Ziel angelegten Ordner unter %LOCALAPPDATA%\sift\, niemals in das Arbeitsverzeichnis – die Datenbank enthält Klartext-Zugangsdaten, und wenn du das Tool aus deinem Home-Verzeichnis ausführst, sollte es dort nicht stillschweigend eine ablegen. Jede Freigabe erhält ihren eigenen Store, sodass zwei Einsätze nie eine Triage-Warteschlange teilen. sift ui ohne Argumente öffnet den zuletzt verwendeten wieder; --data DIR setzt das außer Kraft.
Benutzerdefinierte Regeln sind global und liegen unter %LOCALAPPDATA%\sift\user-rules.json. Ein Muster, das du während eines Einsatzes schreibst, hilft also bei der nächsten Freigabe, die du dir ansiehst.
Beide befinden sich im Kopfbereich der UI, neben dem Pfadfeld, sowie in der CLI.
Größe prüfen ist ein reiner Stat-Durchlauf. Es wird nichts geöffnet, daher ist er selbst über SMB günstig, und er zeigt dir die Dateianzahl, Gesamtbytes, größte Ordner, die Aufteilung nach Dateiendung, wie viel sift tatsächlich lesen würde und wie lange eine Kopie bei jeder Geschwindigkeit dauern würde. Einen Scanner auf eine unbekannte DFS-Wurzel zu richten und zu warten, ist der schnellste Weg, einen Nachmittag zu verlieren.
Lokal kopieren zieht die Freigabe zunächst in einen lokalen Ordner. Das lohnt sich, weil:
Die Übertragung ist ratenbegrenzt und wird standardmäßig mit 5 MB/s durchgeführt. Den Link zu einem Produktions-Dateiserver um 14 Uhr zu sättigen, verwandelt deine Untersuchung in einen zweiten Vorfall. Erhöhe das Limit, wenn du weißt, dass der Pfad ungenutzt ist.
| Geschwindigkeit | Rate |
|---|---|
| sanft (Standard) | 5 MB/s |
| normal | 25 MB/s |
| schnell | 100 MB/s |
| unbegrenzt | was die Verbindung hergibt |
Übertragungen setzen fort: Eine Zieldatei mit gleicher Größe und mtime wird übersprungen, sodass eine bei 80 % unterbrochene Erfassung genau dort weitermacht, wo sie aufgehört hat. Dateien, die gesperrt oder verweigert sind, werden protokolliert und übersprungen, statt den Lauf abzubrechen.
PDF, CSV, MD und JSON, über den UI-Kopfbereich oder sift export --fmt.
Das PDF ist dasjenige, das man zu einer Vorfallakte legt: eine Titelseite mit dem Ziel, Summen nach Schweregrad und Triage-Status, die häufigsten Regeln, über Dateien hinweg wiederverwendete Werte, dann die Befunde nach Schweregrad gruppiert. Es wird direkt erzeugt, ohne PDF-Bibliothek, und funktioniert daher auf einem Rechner, der noch nie pip gesehen hat.
Exporte sind standardmäßig geschwärzt. Werte werden maskiert, jede Seite ist mit einem Banner gekennzeichnet, und der Endpunkt deaktiviert die Maskierung nur bei einem expliziten redact=0 – eine abgeschnittene oder fehlerhafte Anfrage kann nichts leaken. Das Deaktivieren der Schwärzung in der UI erfordert das Bestätigen eines Warndialogs, und die resultierende Datei ist auf jeder Seite mit dem Banner UNREDACTED - CONTAINS PLAINTEXT CREDENTIALS gekennzeichnet.
Die Befund-Datenbank enthält weiterhin die echten Werte, denn ein Analyst muss wissen, welches Passwort geleakt ist, um zu wissen, was er rotieren muss. Die Grenze ist das, was das Tool verlässt.
Alles ist klickbar. Das Sortier-Element oben in der Ergebnisliste sortiert nach Schweregrad, Dateipfad, Regel, Triage-Status oder zuletzt geändert, mit einer Schaltfläche zum Umkehren. Die Facetten in der Seitenleiste filtern nach Schweregrad, Kategorie, Regel und wiederverwendetem Wert. Triage, Kontexterweiterung, Öffnen einer Datei und Erstellen einer Regel sind allesamt Schaltflächen.
Die Tastenkürzel unten sind Beschleuniger für eine lange Warteschlange, nicht der einzige Weg, sie zu bedienen.
Die Schaltfläche Schnappschuss rendert den hervorgehobenen Ausschnitt als PNG zum Einfügen in ein Vorfall-Ticket; Ausschnitt kopieren macht dasselbe als Markdown.
Die UI rendert live Klartext-Zugangsdaten in einem Browserfenster, daher:
127.0.0.1 und verweigert ohne --unsafe-bind alles andere;SameSite=Strict-Cookie gehalten wird;Host-Header, sodass eine feindliche Seite kein DNS-Rebinding darauf machen kann;/api/context kein beliebiges Dateilesen ist und /api/open kein beliebiger Prozessstart.Die Befund-Datenbank enthält bewusst Klartext-Zugangsdaten – ein IR-Analyst muss wissen, welches Passwort geleakt ist, um zu wissen, was er rotieren muss. Behandle %LOCALAPPDATA%\sift\<target>\findings.db wie Beweismaterial: gleiche Behandlung wie die Freigabe selbst, und lösche sie, wenn der Einsatz abgeschlossen ist. Verwende --redact, wenn sie den Vorfallbereich verlassen wird.
Und das Offensichtliche: Führe sift nur gegen Systeme aus, auf die du zugreifen darfst.
sift/rules_builtin.py – Inhaltsregeln. sift/rules_filename.py – Dateinamenregeln. Beides ist einfaches Python mit Raw-String-Mustern, sodass sie lesbar und diffbar sind; Benutzerregeln liegen als JSON unter .sift/user-rules.json.
Drei Stufen ermöglichen den Tausch von Präzision gegen Recall:
cpassword, NTLM-Dumps, LDAP-Bind-Passwörter. Schon die Form ist der Beweis.Eine Regel kann außerdem min_digits, min_lowercase, min_uppercase und min_special tragen, sodass eine einzelne laute Regel verschärft werden kann, ohne den Rest anzufassen, sowie examples – Zeichenketten, die sie weiterhin matchen muss.
examples ist die nützliche Hälfte. sift selftest führt jede Regel gegen die Zeichenketten aus, für die sie geschrieben wurde, und zwar über den gesamten Pfad: Matchen, Extrahieren, dann die Unterdrückungsfilter. Dieser letzte Schritt ist der entscheidende, denn die Regression, die tatsächlich vorkommt, ist kein Muster, das nicht mehr matcht – sondern ein Noise-Filter, der anderswo aus guten Gründen verschärft wurde und dabei auf dem Weg nach draußen stillschweigend einen echten Befund verschluckt.
Das zahlt sich sofort aus. Das Hinzufügen von Beispielen zu den bestehenden Regeln förderte eine echte Lücke zutage: Ein Unterstrich ist ein Wortzeichen, daher weigerte sich das führende \b in der generischen Zuweisungsregel, innerhalb von DB_PASSWORD, MYSQL_PASSWORD oder REDIS_PASSWORD zu matchen – drei der häufigsten Variablemannen für Zugangsdaten überhaupt, stillschweigend übersehen. Das Beispiel sah offensichtlich korrekt aus und matchte nicht – genau dafür ist es da.
Regeln, die du in der UI schreibst, bekommen das gratis: Die Zeile, die du ausgewählt hast, wird als Beispiel der Regel gespeichert. So zeigt dir eine Regel, die du sechs Monate später bearbeitest, wann sie aufgehört hat, das zu matchen, weswegen du sie geschrieben hast.
sift import-rules akzeptiert ein gitleaks-.toml, ein .yml im Kingfisher/Titus-Stil oder ein Verzeichnis davon. Gegenüber Kingfishers Pack sind das 1.073 von 1.082 importierte Regeln, samt ihren Entropie-Untergrenzen, Digit- und Groß-/Kleinschreibungs-Anforderungen sowie Beispielen. YAML wird von sift/yamlmini.py gelesen, einem Reader für die Teilmenge, die diese Packs verwenden – keine Abhängigkeit, und er wirft bei Ankern und Tags einen Fehler, statt so zu tun, als verstehe er sie.
Zwei Dinge werden beim Import bewusst verworfen:
validation:-Blöcke, die pro Regel eine URL benennen. sift kontaktiert nur Hosts, die in validate.py fest einprogrammiert sind. Ein Regelpack, das einen Endpunkt benennen könnte, würde entscheiden, wohin deine Befunde gesendet werden – und eine Regelsammlung ist Daten, keine Entscheidung.[[:alnum:]] eine POSIX-Klasse ist; Python liest es als Menge literaler Zeichen, kompiliert es bereitwillig und matcht das Falsche. Die Übersetzung wird gegen die Beispiele jeder Regel geprüft, sodass ein Muster, das die Kompilierung überlebt hat, aber seine Bedeutung geändert hat, verworfen wird, statt stillschweigend nie zu feuern. Zwölf von Kingfishers Regeln fallen durch diese Prüfung und werden nicht importiert.Ob sifts eigene Unterdrückung ein bestimmtes Beispiel verwerfen würde, disqualifiziert die Regel nicht – diese Packs enthalten absichtlich gefälschte Beispiele (keyXXXXXXXX, ...EXAMPLE), daher hat der Platzhalterfilter beim Beispiel recht und sagt nichts über das Muster aus. Bevor diese Unterscheidung gezogen wurde, hatte diese Strenge 121 funktionierende Regeln verworfen.
Generische Geheimnis-Regeln werden wegen des Rauschens aufgegeben, daher sind die Noise-Filter genauso sorgfältig abgestimmt wie die Muster. Gemessen an einem echten Baum mit 6.000 Dateien reduzierten die unten stehenden Unterdrückungsregeln die Befunde von 1.088 auf 257, ohne Verlust an Recall im Testkorpus:
password: process.env.DB_PASS ist eine Variable, kein Wert. Diese eine Unterdrückung entfernt das meiste generische Regel-Rauschen in Quellbäumen.def login(user: str, password: str) ist eine Signatur..wrangler, .next, site-packages, node_modules, …) sowie minifizierte Bundles und Source Maps werden übersprungen. Maschinell erzeugter Text produziert nur maschinell erzeugte Fehlpositive.Es gibt bewusst keine https://user:pass@host-Inhaltsregel mit lockerem Ende. Die naheliegende Version feuerte 476-mal auf einem Dev-Baum, weil minifiziertes JSON keine Leerzeichen hat und das Muster von einer URL über Anführungszeichen und Kommas lief, bis es Hunderte Zeichen später ein unzusammenhängendes @ fand.
python tests/run_all.py
Zwölf Test-Suiten: Erkennung gegen eine synthetische Freigabe (aufgeteilt in „was die CI-Scanner bereits erkennen“, „die Lücke, die dieses Tool adressiert“, und „Köder, die still bleiben müssen“), die Befehlszeile, das Ranking der Regelvorschläge, die Umfrage und die gedrosselte Datenerfassung (einschließlich der Messung des Ratengrenzwerts gegen die Wanduhr), der PDF-Schreiber (zurückgeparst, wie es ein Leser tun würde, um zu beweisen, dass die Schwärzung den Seiteninhalt erreicht hat), die Gitleaks/Trufflehog-Importeure, die HTTP-API einschließlich aller Sicherheitswächter, die statische Analyse der UI und der Block-Leser für überdimensionierte Dateien (mit der Bestätigung, dass ein Geheimnis im letzten Block immer noch seine wahre Zeilennummer in der gesamten Datei meldet).
Um eine Freigabe zum Ausprobieren zu erhalten:```bash
sift demo C:\temp\demoshare
Jede Anmeldeinformation in diesem Korpus ist erfunden.
Zwei Ebenen, weil sie sehr unterschiedliche Risiken bergen.
Prüfsummen sind kostenlos und immer aktiv. ghp_, npm_, Atlassian ATATT,
Bitbucket ATCTT und GitLabs routbare glpat--Tokens tragen alle eine CRC32
über ihren eigenen Inhalt. Die Neuberechnung beantwortet offline, was früher das
Internet brauchte: Ist das ein echtes Token oder das Beispiel, das jemand in eine
README eingefügt hat? Funde werden in der Warteschlange mit checksum ok oder
malformed gekennzeichnet. Eine Prüfsumme beweist Form, nicht Leben – ein
wohlgeformtes Token kann vor einem Jahr widerrufen worden sein.
Die Live-Validierung ist deaktiviert, bis du sie ausführst. sift validate fragt den Anbieter,
ob eine Anmeldeinformation noch funktioniert. Es ist ein separater Befehl, kein Flag für
scan, und es bringt dich dazu, validate an einer Eingabeaufforderung einzutippen, die zuerst jeden
Endpunkt nennt, den sie kontaktieren wird. Die Sicherheitsregeln:
sift/validate.py hartcodiert. Keine Regel – eingebaute,
vom Benutzer geschriebene oder aus einem fremden Paket importierte – kann eine URL liefern.
Ohne das würde das Importieren eines Regelpakets ausreichen, um jede Anmeldeinformation
auf der Freigabe an eine Adresse des Paketautors zu senden.--redact-Store zu laufen: Wenn Werte maskiert werden,
weil die Datenbank die Vorfallgrenze verlässt, ist die Übertragung des Klartexts genau das,
wogegen geschützt werden soll.validation-log.json neben der Funddatenbank geschrieben
Validierungsversuche landen in den Audit-Logs des Eigentümers der Anmeldeinformation, in diesem Moment deiner Adresse zugeordnet. Das ist manchmal genau das, was du willst, und manchmal alarmiert es einen Gegner, der zusieht. Entscheide dich, bevor du es ausführst; genau deshalb fragt es.
Derzeit GitHub, npm, Slack und Stripe. trufflehog verifiziert noch weitaus mehr – führe es aus und verwende import-findings, um beides zu erhalten.
import-findings; verifizierte Treffer werden nach oben sortiert..kdbx- oder .pfx-Container wird
namentlich gemeldet; sift versucht nicht, ihn zu öffnen.name=value zusammengesetzt; andernfalls sitzen das geheime Wort und sein Wert in getrennten
Spalten und keine Regel sieht das Paar..7z, .rar und verschachtelte Archive werden markiert, aber nicht entpackt. Nur ZIP-
basierte Formate und .eml-Nachrichten werden im Inneren gelesen.--max-size werden in Blöcken gelesen, nicht gecacht. Sie werden gescannt
(eine Verbindungszeichenfolge in einem 4-GB-.bak wird an ihrer echten Zeilennummer gefunden), aber
der Text-Cache fasst nur, was hineinpasst, sodass der gecachte Rescan von einer Sekunde sie nicht
abdeckt – eine neue Regel erreicht eine große Datei beim nächsten vollständigen Scan.Apache-2.0. Siehe LICENSE.
Das Erkennungstest-Korpus (sift/selftest.py, tests/) enthält absichtlich formatkorrekte, aber erfundene Anmeldeinformationen; Secret-Scanning-Warnungen für diese Pfade werden über .github/secret_scanning.yml unterdrückt.
| Flag | Wirkung |
|---|
--tier 1|2|3 | Empfindlichkeitsregler. 1 = hohe Signalqualität, 2 = Standard, 3 = nichts übersehen |
--redact | Werte im Store und in Exporten maskieren. Verwenden, falls die Datenbank den Vorfallbereich verlässt |
--no-ui | Store befüllen und beenden, für skriptgesteuerte Läufe |
--no-browser | UI-Server starten, aber keinen Browser öffnen (nützlich über RDP) |
--include/--exclude GLOB | Den Durchlauf eingrenzen |
--no-archives | docx/xlsx/zip-Container nicht öffnen |
--no-strings | Keinen Strings-Durchlauf über Binärdateien ausführen |
--no-large | Dateien über --max-size überspringen, statt sie blockweise zu lesen |
--jobs N | Arbeiterprozesse (Standard: auto) |
--max-size MB | Dateien darüber überspringen (Standard 25) |
--port N | UI-Port (Standard 8973) |
| Taste | Aktion |
|---|
j / k | nächster / vorheriger Befund |
↑ / ↓ | Kontext nach oben / unten erweitern |
c / f | bestätigen / als falsch positiv markieren |
x | Auswahl für Sammel-Triage umschalten |
o / n | in VS Code an der Zeile öffnen / Datei in Notepad öffnen |
r | Regel aus dem hervorgehobenen Text erstellen |
y | Wert kopieren |
/ | suchen |
.doc/.xls/.pdf (vor 2007 und PDF) durchlaufen einen Strings-Durchlauf statt eines
echten Parsers, daher ist die Erkennungsrate bei diesen niedriger als bei den OOXML-Formaten.