
Abdeckungsbasierter Fuzzer für Python-Anwendungen
pip3 install frelatage
Der Python Fuzzer, den die Welt verdient
Installation | Funktionsweise | Funktionen | Verwendung von Frelatage | Konfiguration
Frelatage ist eine abdeckungsbasierte Python-Fuzzing-Bibliothek, mit der Python-Code gefuzzt werden kann. Die Entwicklung von Frelatage wurde durch verschiedene andere Fuzzer inspiriert, darunter AFL/AFL++, Atheris und PythonFuzz. Der Hauptzweck des Projekts ist es, die besten Eigenschaften dieser Fuzzer zu nutzen und sie in einem neuen Werkzeug zu vereinen, um Python-Anwendungen effizient zu fuzzen.
HAFTUNGSAUSSCHLUSS : Dieses Projekt befindet sich im Alpha-Stadium und kann noch viele unerwartete Verhaltensweisen verursachen. Frelatage sollte derzeit nicht in einer Produktionsumgebung eingesetzt werden.
pip3 install frelatage
Für Entwickler empfohlen. Klont automatisch den Hauptbranch aus dem Frelatage-Repository und installiert aus dem Quellcode.
# Das Frelatage-Repository automatisch klonen und Frelatage aus dem Quellcode installieren
bash <(wget -q https://raw.githubusercontent.com/Rog3rSm1th/Frelatage/main/scripts/autoinstall.sh -O -)
Die Idee hinter dem Design von Frelatage ist die Verwendung eines genetischen Algorithmus, um Mutationen zu erzeugen, die so viel Code wie möglich abdecken. Die Funktionsweise eines Fuzzing-Zyklus kann grob mit diesem Diagramm dargestellt werden:
graph TB
m1(Mutation 1) --> |input| function(Gefuzzte Funktion)
m2(Mutation 2) --> |input| function(Gefuzzte Funktion)
mplus(Mutation ...) --> |input| function(Gefuzzte Funktion)
mn(Mutation n) --> |input| function(Gefuzzte Funktion)
function --> generate_reports(Berichte erstellen)
generate_reports --> rank_reports(Berichte bewerten)
rank_reports --> select(Die n besten Berichte auswählen)
select --> |mutate| nm1(Mutation 1) & nm2(Mutation 2) & nmplus(Mutation ...) & nmn(Mutation n)
subgraph Zyklusmutationen
direction LR
m1
m2
mplus
mn
end
subgraph Mutationen des nächsten Zyklus
direction LR
nm1
nm2
nmplus
nmn
end
style function fill:#5388e8,stroke:white,stroke-width:4px
Frelatage ermöglicht es, eine Funktion zu fuzzen, indem eine Datei als Eingabe übergeben wird.
import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.parse(data)
input = frelatage.Input(value="initial_value")
f = frelatage.Fuzzer(MyFunctionFuzz, [[input]])
f.fuzz()
Frelatage bietet die Möglichkeit, Eingabeparameter vom Typ Datei zu fuzzen. Um den Wert dieser Dateien zu initialisieren, müssen Sie Dateien im Eingabeordner (standardmäßig ./in) erstellen.
Wenn wir den Wert einer Datei initialisieren möchten, die zum Fuzzen verwendet wird, können wir das so tun:
echo "initial value" > ./in/input.txt
Und dann den Fuzzer ausführen:
import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.load_file(data)
input = frelatage.Input(file=True, value="input.txt")
f = frelatage.Fuzzer(MyFunctionFuzz, [[input]])
f.fuzz()
import frelatage
import my_vulnerable_library
input = frelatage.Input(file=True, value="input.txt")
@frelatage.instrument([[input]])
def MyFunctionFuzz_1(data):
my_vulnerable_library.load_file(data)
@frelatage.instrument([[input]])
def MyFunctionFuzz_1(data):
my_vulnerable_library.load_file_but_different(data)
# Und so weiter
# Es werden die instrumentierten Methoden nacheinander gefuzzt
frelatage.Fuzzer.fuzz_all()
Wenn Sie mehrere Dateien auf einmal in einen Korpus laden müssen (nützlich, wenn Sie einen großen Korpus verwenden), können Sie die integrierte Funktion von Frelatage load_corpus verwenden. Diese Funktion gibt eine Liste von Eingaben zurück.
load_corpus(directory: str, file_extensions: list) -> list[Input]
./, ./images["jpeg", "gif"], ["pdf"]import frelatage
import my_vulnerable_library
def MyFunctionFuzz(data):
my_vulnerable_library.load_file(data)
my_vulnerable_library.load_file(data2)
# Lade jede Datei im Verzeichnis ./in
corpus_1 = frelatage.load_corpus(directory="./")
# Lade jede .gif/.jpeg-Datei im Unterverzeichnis ./in/images
corpus_2 = frelatage.load_corpus(directory="./images", file_extension=["gif", "jpeg"])
f = frelatage.Fuzzer(MyFunctionFuzz, [corpus_1, corpus_2])
f.fuzz()
Sie können eines oder mehrere Wörterbücher, die sich hier befinden, in das für Wörterbücher vorgesehene Verzeichnis (./dict standardmäßig) kopieren.
Differenzielles Fuzzing ist eine beliebte Softwaretesttechnik, die versucht, Fehler zu erkennen, indem sie dieselbe Eingabe an mehrere Bibliotheken/Programme übergibt und Unterschiede in ihrem Verhalten beobachtet. Ein Beispiel für die Verwendung von differenziellem Fuzzing mit Frelatage mit den Bibliotheken json und ujson finden Sie hier.
Weitere Beispiele für Fuzzer und Korpus finden Sie im Beispielverzeichnis.
Jeder Absturzbericht wird im Ausgabeordner (standardmäßig ./out) in einem Ordner mit dem Namen id:<crash ID>,err:<error type>,err_pos:<error>,err_file:<error file> gespeichert.
Das Berichtsverzeichnis hat folgende Form:
├── out
│ ├── id:<crash ID>,err:<error type>,err_file:<error file>,err_pos:<err_pos>
│ ├── message
│ ├── input
│ ├── 0
│ ├── <inputfile1>
│ ├── ...
│ ├── ...
Jeder Absturzbericht enthält eine message-Datei, die die Fehlermeldung enthält.
Jeder Bericht zur Abdeckungserhöhung wird im Abdeckungsordner (standardmäßig ./cov) in einem Ordner mit dem Namen coverage_<ID> gespeichert, und das Berichtsverzeichnis hat die gleiche Form wie die Absturzberichtsverzeichnisse.
Die an eine Funktion übergebenen Eingaben werden mit dem Modul pickle serialisiert, bevor sie in der Datei <report_folder>/input gespeichert werden. Daher ist es notwendig, sie zu deserialisieren, um den Inhalt der Datei lesen zu können. Diese Aktion kann mit dem Befehl frelatage-report ausgeführt werden.
$ frelatage-report input
Es gibt zwei Möglichkeiten, Frelatage zu konfigurieren:
Ein Konfigurationsbeispiel :
export FRELATAGE_DICTIONARY_ENABLE=1 &&
export FRELATAGE_SAVE_NEW_COVERAGE=1 &&
export FRELATAGE_TIMEOUT_DELAY=2 &&
export FRELATAGE_INPUT_FILE_TMP_DIR="/tmp/frelatage" &&
export FRELATAGE_INPUT_MAX_LEN=4096 &&
export FRELATAGE_MAX_THREADS=8 &&
export FRELATAGE_MAX_STAGES=1000000 &&
export FRELATAGE_MAX_CYCLES_WITHOUT_NEW_PATHS=5000 &&
export FRELATAGE_INPUT_DIR="./in" &&
export FRELATAGE_DICTIONARY_DIR="./dict" &&
python3 fuzzer.py
import frelatage
def myfunction(input1_string, input2_int):
pass
input1 = frelatage.Input(value="initial_value")
input2 = frelatage.Input(value=2)
f = frelatage.Fuzzer(
# Die Methode, die Sie fuzzen möchten
method=myfunction,
# Korpus
corpus=[[input1], [input2]],
# Anzahl der Threads
threads_count=8,
# Ausnahmen, die berücksichtigt werden
exceptions_whitelist=(OSError),
# Ausnahmen, die nicht berücksichtigt werden
exceptions_blacklist=(),
# Verzeichnis, in dem die Fehlerberichte gespeichert werden
output_directory="./out",
# Verzeichnis, in dem die Abdeckungserhöhungsberichte gespeichert werden
coverage_directory="./cov",
# Aktivieren oder Deaktivieren des lautlosen Modus
silent=False,
# Aktivieren oder Deaktivieren des unendlichen Fuzzings
infinite_fuzz=False
)
f.fuzz()
Bitte beachten Sie, dass Fuzzing – ähnlich wie viele andere rechenintensive Aufgaben – Ihre Hardware und das Betriebssystem belasten kann. Insbesondere:
Ihre CPU wird heiß laufen und benötigt eine ausreichende Kühlung. In den meisten Fällen werden die CPU-Geschwindigkeiten automatisch gedrosselt, wenn die Kühlung unzureichend ist oder nicht mehr richtig funktioniert. Dennoch ist es, insbesondere beim Fuzzing auf weniger geeigneter Hardware (Laptops, Smartphones usw.), nicht völlig ausgeschlossen, dass etwas explodiert.
Zielprogramme können unberechenbar Gigabyte an Arbeitsspeicher beanspruchen oder die Festplatte mit Junk-Dateien füllen. Frelatage versucht, grundlegende Speichergrenzen durchzusetzen, kann jedoch nicht jeden möglichen Fehler verhindern. Das Fazit ist, dass Sie nicht auf Systemen fuzzen sollten, bei denen das Risiko von Datenverlust nicht akzeptabel ist.
Fuzzing umfasst Milliarden von Lese- und Schreibvorgängen auf dem Dateisystem. Auf modernen Systemen wird dies in der Regel stark zwischengespeichert, was zu relativ bescheidenen "physischen" E/A-Vorgängen führt – aber es gibt viele Faktoren, die diese Gleichung verändern können. Es liegt in Ihrer Verantwortung, auf mögliche Probleme zu achten; bei sehr hoher E/A-Belastung kann die Lebensdauer vieler HDDs und SSDs verkürzt werden.
Eine gute Möglichkeit, die Festplatten-E/A unter Linux zu überwachen, ist der Befehl 'iostat':
$ iostat -d 3 -x -k [...optionale Festplatten-ID...]
Ich bin Rog3rSm1th, 21 Jahre alt und ein französischer Computer- und Cybersicherheits-Enthusiast. Ich entwickle gerne Werkzeuge (OSINT, Fuzzing...) und spiele CTFs/Wargames. Um mehr über mich und meine Projekte zu erfahren, klicken Sie einfach hier.
➜ Wenn Sie mich für eines Ihrer Projekte (Programmierung, Cybersicherheit...) einstellen möchten, kontaktieren Sie mich einfach unter [email protected] und wir werden gemeinsam Ihre Bedürfnisse einschätzen.
Bei Anmerkungen, Vorschlägen, Fehlerberichten oder wenn Sie einen Fehler mit Frelatage gefunden haben, können Sie mich unter [email protected] oder auf Twitter @Rog3rSm1th kontaktieren.
| Umgebungsvariable | Beschreibung | Mögliche Werte | Standardwert |
|---|
| FRELATAGE_DICTIONARY_ENABLE | Aktiviert die Verwendung von Mutationen basierend auf Wörterbuchelementen | 1 zum Aktivieren, 0 andernfalls | 1 |
| FRELATAGE_SAVE_NEW_COVERAGE | Neue Abdeckungseingaben speichern, um sie später wiederzuverwenden | 1 zum Aktivieren, 0 andernfalls | 1 |
| FRELATAGE_TIMEOUT_DELAY | Verzögerung in Sekunden, nach der eine Funktion einen TimeoutError zurückgibt | 1 - unendlich | 2 |
| FRELATAGE_INPUT_FILE_TMP_DIR | Temporärer Ordner, in dem Eingabedateien gespeichert werden | absoluter Pfad zu einem Ordner, z.B. /tmp/custom_dir | /tmp/frelatage |
| FRELATAGE_INPUT_MAX_LEN | Maximale Größe einer Eingabevariable in Bytes | 4 - unendlich | 4094 |
| FRELATAGE_MAX_THREADS | Maximale Anzahl gleichzeitiger Threads | 8 - unendlich | 8 |
| FRELATAGE_MAX_STAGES | Maximale Anzahl von Stufen für eine gefuzzte Funktion | 1 - unendlich | 1000000 |
| FRELATAGE_MAX_CYCLES_WITHOUT_NEW_PATHS | Anzahl der Zyklen ohne gefundene neue Pfade, nach denen zur nächsten Stufe übergegangen wird | 10 - unendlich | 5000 |
| FRELATAGE_INPUT_DIR | Verzeichnis, das die anfänglichen Eingabedateien enthält. Muss ein relativer Pfad (zum Pfad der Fuzzing-Datei) sein | relativer Pfad zu einem Ordner, z.B. ./in | ./in |
| FRELATAGE_DICTIONARY_DIR | Standardverzeichnis für Wörterbücher. Muss ein relativer Pfad (zum Pfad der Fuzzing-Datei) sein | relativer Pfad zu einem Ordner, z.B. ./dict | ./dict |
| FRELATAGE_DEBUG_MODE | Aktiviert den Debug-Modus (zeigt den Fehler an, wenn Frelatage abstürzt) | 1 zum Aktivieren, 0 andernfalls | 1 |