
The x86 processor fuzzer
: der x86-Prozessor-Fuzzer
Der Sandsifter prüft x86-Prozessoren auf versteckte Instruktionen und Hardware-Fehler, indem er systematisch Maschinencode generiert, um den Befehlssatz eines Prozessors zu durchsuchen und die Ausführung auf Anomalien zu überwachen. Sandsifter hat geheime Prozessorinstruktionen von allen großen Herstellern aufgedeckt; allgegenwärtige Softwarefehler in Disassemblern, Assemblierern und Emulatoren; Schwachstellen in Unternehmens-Hypervisoren; sowie sowohl harmlose als auch sicherheitskritische Hardwarefehler in x86-Chips.
Angesichts der Vielzahl existierender x86-Prozessoren ist es das Ziel des Tools, Benutzern zu ermöglichen, ihre eigenen Systeme auf versteckte Instruktionen und Fehler zu überprüfen.
Um eine grundlegende Prüfung Ihres Prozessors durchzuführen:
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t

Der Computer wird systematisch nach anomalen Instruktionen durchsucht. In der oberen Hälfte sehen Sie die Instruktionen, die der Sandsifter gerade auf dem Prozessor testet. In der unteren Hälfte meldet der Sandsifter gefundene Anomalien.
Die Suche dauert zwischen einigen Stunden und einigen Tagen, abhängig von der Geschwindigkeit und Komplexität Ihres Prozessors. Wenn sie abgeschlossen ist, fassen Sie die Ergebnisse zusammen:
./summarize.py data/log

Typischerweise werden mehrere Millionen undokumentierte Instruktionen auf Ihrem Prozessor gefunden, die jedoch im Allgemeinen in eine kleine Anzahl verschiedener Gruppen fallen. Nach dem Binning der Anomalien versucht das Zusammenfassungstool, jede Instruktion einer Problemkategorie zuzuordnen:
Drücken Sie 'Q', um zu beenden und eine textbasierte Zusammenfassung des Systemscans zu erhalten:
Die Ergebnisse eines Scans können für die Tools manchmal schwer automatisch zu klassifizieren sein und können eine manuelle Analyse erfordern. Wenn Sie Hilfe bei der Analyse Ihrer Ergebnisse benötigen, senden Sie die Datei ./data/log bitte an [email protected]. In dieser Logdatei sind keine persönlichen Informationen enthalten, außer der Hersteller, das Modell und die Revision des Prozessors (aus /proc/cpuinfo).
Das Scannen mit dem Sandsifter hat undokumentierte Prozessorfunktionen in Dutzenden von Opcode-Kategorien, Schwachstellen in Unternehmens-Hypervisoren, Fehler in nahezu jedem großen Disassemblierungs- und Emulationswerkzeug sowie kritische Hardwarefehler aufgedeckt, die Sicherheitslücken im Prozessor selbst öffnen.
Details zu den Ergebnissen finden Sie im Whitepaper des Projekts.
(TODO: detailed results enumeration here)
Sandsifter erfordert zuerst die Installation des Capstone-Disassemblers: http://www.capstone-engine.org/. Capstone kann in der Regel wie folgt installiert werden:
sudo apt-get install libcapstone3 libcapstone-dev
sudo pip install capstone
Sandsifter kann mit folgendem Befehl erstellt werden:
make
und wird dann ausgeführt mit
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t
Flags werden mit --flag an den Sifter und mit -- -f an den Injektor übergeben.
Beispiel:
sudo ./sifter.py --unk --dis --len --sync --tick -- -P1 -t
Sifter-Flags:
--len
Suche nach Längenunterschieden bei allen Instruktionen (Instruktionen, die
anders ausgeführt wurden als vom Disassembler erwartet, oder nicht
existierten, als der Disassembler sie erwartete
--dis
Suche nach Längenunterschieden bei gültigen Instruktionen (Instruktionen, die
anders ausgeführt wurden als vom Disassembler erwartet)
--unk
Suche nach unbekannten Instruktionen (Instruktionen, die der Disassembler
nicht kennt, aber erfolgreich ausgeführt werden)
--ill
das Gegenteil von --unk, Suche nach ungültigen Disassemblierungen (Instruktionen, die
nicht erfolgreich ausgeführt werden, die der Disassembler aber anerkennt)
--tick
schreibe regelmäßig die aktuelle Instruktion auf die Festplatte
--save
speichere den Suchfortschritt beim Beenden
--resume
setze die Suche vom letzten gespeicherten Zustand fort
--sync
schreibe Suchergebnisse sofort auf die Festplatte, sobald sie gefunden werden
--low-mem
Ergebnisse nicht im Speicher ablegen
Injector-Flags:
-b
Modus: Brute Force
-r
Modus: randomisiertes Fuzzing
-t
Modus: getunneltes Fuzzing
-d
Modus: extern gesteuertes Fuzzing
-R
Rohausgabemodus
-T
Textausgabemodus
-x
schreibe periodischen Fortschritt auf stderr
-0
Nullzeiger-Dereferenzierung erlauben (erfordert sudo)
-D
doppelte Präfixe erlauben
-N
keine NX-Bit-Unterstützung
-s seed
bei zufälliger Suche: Startwert
-B brute_depth
bei Brute-Force-Suche: maximale Suchtiefe
-P max_prefix
maximale Anzahl zu durchsuchender Präfixe
-i instruction
Instruktion, bei der die Suche beginnen soll (inklusive)
-e instruction
Instruktion, bei der die Suche enden soll (exklusive)
-c core
Kern, auf dem die Suche durchgeführt werden soll
-X blacklist
die angegebene Instruktion auf die Blacklist setzen
-j jobs
Anzahl gleichzeitig auszuführender Jobs
-l range_bytes
Anzahl der Basisinstruktions-Bytes in jedem Unterbereich
m: Modus – Suchmodus ändern (Brute Force, Zufall oder Tunnel) für den Sifter
q: Beenden – den Sifter beenden
p: Pause – Suche anhalten oder fortsetzen
Das Scannen unterstützt vier verschiedene Suchalgorithmen, die über die Befehlszeile festgelegt oder über Tastenkürzel durchgeschaltet werden können.
sudo
Für optimale Ergebnisse sollte das Tool als Root-Benutzer ausgeführt werden. Dies ist notwendig, damit der Prozess eine Seite an Adresse 0 in den Speicher einblenden kann, was Root-Berechtigungen erfordert. Diese Seite verhindert, dass viele Instruktionen bei Speicherzugriffen einen Segfault auslösen, was eine genauere Fehleranalyse ermöglicht.
Präfixe
Die Haupteinschränkung für die Tiefe einer Instruktionssuche ist die Anzahl der zu durchsuchenden Präfix-Bytes, wobei jedes zusätzliche Präfix-Byte den Suchraum um etwa den Faktor 10 vergrößert. Begrenzen Sie die Präfix-Bytes mit dem Flag -P.
Farben
Die Benutzeroberfläche des Sifters ist für ein 256-Farben-Terminal ausgelegt. Die Details variieren stark je nach Terminal, aber grob kann dies erreicht werden mit:
export TERM='xterm-256color'
GUI
Die Oberfläche setzt voraus, dass das Terminal mindestens eine bestimmte Größe hat. Wenn die Oberfläche nicht korrekt dargestellt wird, versuchen Sie, die Terminalgröße zu vergrößern; dies kann oft durch Verkleinern der Terminal-Schriftgröße erreicht werden.
In einigen Fällen kann es wünschenswert oder notwendig sein, das Tool ohne die grafische Oberfläche auszuführen. Dies kann durch direktes Ausführen des Injektors erfolgen:
sudo ./injector -P1 -t -0
Um die Ergebnisse eines direkten Injektor-Aufrufs zu filtern, kann grep verwendet werden. Zum Beispiel:
sudo ./injector -P1 -r -0 | grep '\.r' | grep -v sigill
durchsucht nach Instruktionen, bei denen Prozessor und Disassembler sich über die Instruktionslänge uneinig waren (grep '.r'), die Instruktion jedoch erfolgreich ausgeführt wurde (grep -v sigill).
Gezieltes Fuzzing
In vielen Fällen ist es nützlich, den Fuzzer auf ein bestimmtes Ziel auszurichten. Wenn Sie beispielsweise vermuten, dass ein Emulator Fehler im Zusammenhang mit wiederholten 'lock'-Präfixen (0xf0) aufweist, können Sie den Fuzzer mit den Flags -i und -e anweisen, diesen Bereich des Instruktionsraums zu durchsuchen:
sudo ./sifter.py --unk --dis --len --sync --tick -- -t -i f0f0 -e f0f1 -D -P15
Sandsifter ist ein Forschungsprojekt von Christopher Domas (@xoreaxeaxeax).
Legacy-Systeme
Für das Scannen wesentlich älterer Systeme (i586-Klasse Prozessoren, Systeme mit wenig Arbeitsspeicher) übergeben Sie das Flag --low-mem an den Sifter und das Flag -N an den Injektor:
sudo ./sifter.py --unk --dis --len --sync --tick --low-mem -- -P1 -t -N
Wenn Sie beobachten, dass Ihre Scans zu schnell abgeschlossen werden (z. B. ein Scan in Sekunden), liegt dies normalerweise daran, dass diese Flags für den von Ihnen gescannten Prozessor erforderlich sind.
32 vs. 64 Bit
Standardmäßig wird Sandsifter für die Bitness des Host-Betriebssystems erstellt. Einige Instruktionen verhalten sich jedoch in einem 32-Bit-Prozess anders als in einem 64-Bit-Prozess. Um diese Szenarien zu untersuchen, kann es manchmal sinnvoll sein, einen 32-Bit-Sandsifter auf einem 64-Bit-System auszuführen.
Um einen 32-Bit-Sandsifter auf einem 64-Bit-System zu erstellen, muss Capstone als 32-Bit-Version installiert werden; die Anweisungen hierfür finden Sie unter http://www.capstone-engine.org/.
Dann muss Sandsifter für eine 32-Bit-Architektur erstellt werden:
make CFLAGS=-m32
Damit kann der 32-Bit-Instruktionsraum auf einem 64-Bit-System erkundet werden.