
Statisches Analyse-Framework, das fuzzbare Funktionsziele in Quellcode und Binärdateien identifiziert, Harness-Vorlagen generiert und sich mit AFL++ und libFuzzer für die automatisierte Schwachstellenerkennung integriert.
Framework zur Automatisierung der Erkennung von Fuzzable-Zielen mittels statischer Analyse

Sicherheitsforscher, die Sicherheitsbewertungen von Software durchführen, nutzen oft die Möglichkeiten des abdeckungsgesteuerten Fuzzings mit leistungsstarken Tools wie AFL++ und libFuzzer. Dies ist wichtig, da es die Fehlersuche automatisiert und ausbeutbare Bedingungen in Zielen schnell aufdeckt. Bei großen und komplexen Codebasen oder Closed-Source-Binärdateien müssen Forscher jedoch mühsam Zeit in manuelle Audits und Reverse Engineering investieren, um Funktionen zu identifizieren, bei denen eine fuzzing-basierte Erkundung nützlich sein kann.
Fuzzable ist ein Framework, das sowohl mit C/C++-Quellcode als auch mit Binärdateien integriert wird, um Sicherheitsforscher bei der Identifizierung von Funktionszielen zu unterstützen, die für das Fuzzing geeignet sind. Dies geschieht durch die Anwendung mehrerer auf statischer Analyse basierender Heuristiken, um riskantes Verhalten in der Software und die Funktionen, die diese ausführen, zu lokalisieren. Forscher können das Framework dann nutzen, um grundlegende Harness-Vorlagen zu generieren, die entweder zur Jagd nach Schwachstellen oder zur Integration in eine kontinuierliche Fuzzing-Pipeline wie Googles -Projekt verwendet werden können.
Neben der Verwendung als eigenständiges Tool ist Fuzzable auch als Plugin für den Binary Ninja-Disassembler integriert, wobei die Unterstützung für andere Disassemblierungs-Backends entwickelt wird.
Schauen Sie sich den ursprünglichen Blogbeitrag an, der das Tool detailliert beschreibt, hier, der die technischen Spezifikationen der statischen Analyseheuristiken und die Entstehungsgeschichte dieses Tools hervorhebt. Dieses Tool wird auch auf der Black Hat Arsenal USA 2022 vorgestellt.
Einige Binärziele erfordern möglicherweise eine Bereinigung (z.B. Signatur-Matching oder Identifizierung von Funktionen aus Inlining). Daher verwendet fuzzable primär Binary Ninja als Disassemblierungs-Backend, da es diese Probleme effektiv lösen kann. Daher kann es sowohl als eigenständiges Tool als auch als Plugin eingesetzt werden.
Da Binary Ninja nicht für alle zugänglich ist und es eine Nachfrage nach Nutzung für Sicherheitsbewertungen und möglicherweise Skalierung in der Cloud geben könnte, wird auch ein angr Fallback-Backend unterstützt. Ich beabsichtige, in Zukunft auch weitere Disassembler einzubinden (Priorität: Ghidra).
Wenn Sie Binary Ninja Commercial besitzen, installieren Sie die API für eigenständige Headless-Nutzung:
$ python3 /Applications/Binary\ Ninja.app/Contents/Resources/scripts/install_api.py
Installation mit pip:
$ pip install fuzzable
Wir verwenden poetry für die Abhängigkeitsverwaltung und den Build. Für einen manuellen Build klonen Sie das Repository mit den Drittanbieter-Modulen:
$ git clone --recursive https://github.com/ex0dus-0x/fuzzable
So installieren Sie manuell:
$ cd fuzzable/
# ohne poetry
$ pip install .
# mit poetry
$ poetry install
# mit poetry für eine Entwicklungsumgebung (virtualenv)
$ poetry shell
Sie können nun Binär- und/oder Quellcode mit dem Tool analysieren:
# Analyse einer einzelnen Shared-Object-Bibliothek (Binär)
$ fuzzable analyze examples/binaries/libbasic.so
# Analyse einer einzelnen C-Quelldatei
$ fuzzable analyze examples/source/libbasic.c
# Analyse eines Arbeitsbereichs mit mehreren C/C++-Dateien und Headern
$ fuzzable analyze examples/source/source_bundle/
fuzzable kann einfach über den Binary Ninja Plugin-Marktplatz installiert werden, indem Sie zu Binary Ninja > Manage Plugins gehen und danach suchen. Hier ist ein Beispiel des fuzzable-Plugins in Aktion, das Ziele zum Fuzzing und zur weiteren Schwachstellenbewertung genau identifiziert:

fuzzable bietet verschiedene Optionen zur besseren Anpassung Ihrer Analyse. In zukünftigen Plänen werden weitere Optionen sowie etwaige Feature-Anfragen unterstützt.
Um die Fuzzbarkeit zu bestimmen, verwendet fuzzable mehrere Heuristiken, um die vielversprechendsten Ziele für die dynamische Analyse zu ermitteln. Diese Heuristiken werden mit der Bibliothek scikit-criteria unterschiedlich gewichtet, die eine Multi-Kriterien-Entscheidungsanalyse verwendet, um die besten Kandidaten zu ermitteln. Diese Metriken und ihre Gewichte sind hier zu sehen:
| Heuristik | Beschreibung | Gewicht |
|---|---|---|
| Fuzz-freundlicher Name | Symbolname deutet auf Verhalten hin, das Datei-/Puffereingaben aufnimmt | 0.3 |
| Riskante Senken | Argumente, die in riskante Aufrufe (z. B. memcpy) fließen | 0.3 |
| Natürliche Schleifen | Anzahl der mit der Dominanzgrenze erkannten Schleifen | 0.05 |
| Zyklomatische Komplexität | Komplexität des Funktionsziels basierend auf Kanten + Knoten | 0.05 |
| Abdeckungstiefe | Anzahl der Callees, die das Ziel durchläuft | 0.3 |
Wie bereits erwähnt, schauen Sie sich den technischen Blogbeitrag für einen tieferen Einblick, warum und wie diese Metriken verwendet werden.
Viele Metriken wurden stark von Vincenzo Iozzo's ursprünglicher Arbeit zum 0-Knowledge-Fuzzing inspiriert.
Jedes Ziel, das Sie analysieren möchten, ist vielfältig, und fuzzable wird nicht jedes Randfallverhalten im Programmziel berücksichtigen können. Daher kann es während der Analyse wichtig sein, diese Gewichte entsprechend anzupassen, um zu sehen, ob andere Ergebnisse für Ihren Anwendungsfall sinnvoller sind. Um diese Gewichte in der CLI anzupassen, geben Sie einfach das Argument --score-weights an:
$ fuzzable analyze <TARGET> --score-weights=0.2,0.2,0.2,0.2,0.2
Standardmäßig filtert fuzzable Funktionsziele basierend auf den folgenden Kriterien aus:
static sind und nicht über Header exponiert werden.Um Aufrufe zu sehen, die von fuzzable herausgefiltert wurden, setzen Sie das Flag --list_ignored:
$ fuzzable analyze --list-ignored <TARGET>
In Binary Ninja können Sie diese Einstellung unter Settings > Fuzzable > List Ignored Calls aktivieren.
Falls fuzzable fälschlicherweise wichtige Aufrufe herausfiltert, die analysiert werden sollten, wird empfohlen, --include-* Argumente zu verwenden, um sie während des Laufs einzubeziehen:
# alle nicht-Top-Level-Aufrufe einbeziehen, die herausgefiltert wurden
$ fuzzable analyze --include-nontop <TARGET>
# bestimmte Symbole einbeziehen, die herausgefiltert wurden
$ fuzzable analyze --include-sym <SYM> <TARGET>
In Binary Ninja wird dies unter Settings > Fuzzable > Include non-top level calls und Symbols to Exclude unterstützt.
Nachdem Sie nun Ihre idealen Kandidaten zum Fuzzing gefunden haben, hilft Ihnen fuzzable auch bei der Generierung von Fuzzing-Harness, die (fast) bereit sind, instrumentiert und kompiliert zu werden, um entweder mit einem dateibasierten Fuzzer (z.B. AFL++, Honggfuzz) oder einem In-Memory-Fuzzer (libFuzzer) verwendet zu werden. Gehen Sie dazu in der CLI wie folgt vor:
# Harness aus einem Kandidaten generieren
$ fuzzable create-harness target --symbol-name=some_unsafe_call
# minimale und notwendige Änderungen am Harness vornehmen
$ vim target_some_unsafe_call_harness.cpp
# Beispielkompilierung für AFL-QEMU, wie in den Kommentaren des generierten Harness angegeben
$ clang target_some_unsafe_call_harness.cpp -no-pie -o target_some_unsafe_call_harness -ldl
# Grundlegende Seeds erstellen, idealerweise sollten diese für die Eingabe wohlgeformter sein
$ mkdir in/
$ echo "seed" >> in/seed
# Black-Box-Fuzzing starten
$ afl-fuzz -Q -m none -i in/ -o out/ -- ./target_some_unsafe_call_harness
Wenn es sich bei diesem Ziel um eine Codebasis handelt, wird die generische Quellvorlage verwendet.
Wenn es sich bei dem Ziel um eine Binärdatei handelt, wird die generische Black-Box-Vorlage verwendet, die idealerweise mit einem Fuzzing-Emulationsmodus wie AFL-QEMU verwendet werden kann. Eine Kopie der Binärdatei wird auch als Shared Object erstellt, wenn das Symbol nicht direkt exportiert wird, um es mit LIEF per dlopen geladen zu werden.
Derzeit ist diese Funktion recht rudimentär, da sie lediglich einen eigenständigen C++-Harness mit den entsprechenden Parametern erstellt und keinen Code für Laufzeitverhalten (z.B. Instanziieren und Freigeben von Strukturen) automatisch generiert. Die für fuzzable erstellten Vorlagen sollten Ihnen jedoch dennoch einen schnellen Start ermöglichen. Hier sind einige ehrgeizige Funktionen, die ich in Zukunft implementieren möchte:
fuzzable unterstützt die Generierung von Berichten in verschiedenen Formaten. Derzeit werden JSON, CSV und Markdown unterstützt. Dies kann nützlich sein, wenn Sie dies als Teil einer Automatisierung nutzen, bei der Sie die Ausgabe in einem serialisierbaren Format erfassen möchten.
In der CLI übergeben Sie einfach das Argument --export mit einem Dateinamen mit der entsprechenden Erweiterung:
$ fuzzable analyze --export=report.json <TARGET>
In Binary Ninja gehen Sie zu Plugins > Fuzzable > Export Fuzzability Report > ... und wählen das Format, in das Sie exportieren möchten, und den Pfad, in den Sie schreiben möchten.
Dieses Tool wird kontinuierlich weiterentwickelt, und jede Hilfe von externen Maintainern wird geschätzt!
Fuzzable ist unter der MIT-Lizenz lizenziert.