
Netzwerkprotokoll-Fuzzer, der PCAP-Verkehr durch eine Mutations-Engine (Radamsa) wiedergibt, um Schwachstellen in Zielhosts schnell zu entdecken, und zwar über anpassbare Nachrichtenprozessoren und Monitore.
Blogbeitrag hier:
Links zu diesem YouTube-Video-Demo:
Für weitere Funktionen, die auf Fuzzing-Kampagnen/Feedback/Harnesses ausgerichtet sind:
Das Mutiny Fuzzing Framework ist ein Netzwerk-Fuzzer, der durch Wiederholung von PCAPs mit einem Mutations-Fuzzer arbeitet. Ziel ist es, Netzwerk-Fuzzing so schnell wie möglich zu beginnen, auf Kosten der Gründlichkeit.
Der allgemeine Arbeitsablauf für Mutiny besteht darin, eine Probe legitimen Datenverkehrs, wie z. B. eine Browser-Anfrage, zu nehmen und in ein Vorbereitungsskript einzuspeisen, um eine .fuzzer-Datei zu generieren. Dann kann Mutiny mit dieser .fuzzer-Datei ausgeführt werden, um Datenverkehr gegen einen Zielhost zu erzeugen und dabei Pakete zu mutieren, die der Benutzer wünscht.
Es gibt Erweiterungen, die die Funktionsweise von Mutiny verändern, darunter das Ändern von Nachrichten basierend auf Ein-/Ausgabe, das Ändern der Reaktionsweise von Mutiny auf Netzwerkfehler und das Überwachen des Ziels in einem separaten Thread.
Mutiny verwendet Radamsa, um Mutationen durchzuführen.
Der Decept Proxy ist ein Mehrzweck- Netzwerk-Proxy, der Datenverkehr von einer Klartext- oder TLS-TCP/UDP/Domain-Socket-Verbindung zu einer Klartext- oder TLS-TCP/UDP/Domain-Socket-Verbindung weiterleiten kann, neben anderen Funktionen. Er ist ein guter Begleiter für Mutiny, da er sowohl .fuzzer-Dateien direkt erzeugen kann, was besonders hilfreich beim Fuzzing von TLS-Verbindungen ist, als auch Mutiny die Kommunikation mit TLS-Hosts ermöglicht.
sample_apps geben eine grundlegende Vorstellung davon, was mit dem Fuzzer gemacht werden kann, mit einigen verschiedenen Anwendungen/Clients zum Testen.
Geschrieben von James Spadaro ([email protected]) und Lilith Wyatt ([email protected])
Stellen Sie sicher, dass Python und Scapy installiert sind.
Entpacken Sie Radamsa und führen Sie make aus. (Sie müssen kein make install ausführen, es sei denn, Sie möchten es
in /usr/bin – das lokale Radamsa wird verwendet.) Aktualisieren Sie mutiny.py mit dem Pfad zu
Radamsa, falls Sie ihn geändert haben.
Speichern Sie die PCAP in einem Ordner. Führen Sie mutiny_prep.py auf <XYZ>.pcap aus (geben Sie optional auch
das Verzeichnis eines benutzerdefinierten Prozessors an, falls vorhanden, mehr dazu unten). Beantworten Sie die
Fragen, Sie erhalten eine <XYZ>.fuzzer-Datei im selben Ordner wie die PCAP.
Führen Sie mutiny.py <XYZ>.fuzzer <targetIP> aus. Dies startet das Fuzzing. Protokolle werden
im selben Ordner im Verzeichnis
<XYZ>_logs/<time_of_session>/<seed_number> gespeichert.
Die .fuzzer-Dateien sind lesbar und kommentiert. Sie erlauben das Ändern verschiedener Optionen pro .fuzzer-Datei, einschließlich der Angabe, welche Nachricht oder welche Nachrichtenteile gefuzzt werden.
In einer .fuzzer-Datei befinden sich die Nachrichteninhalte. Dies sind einfach Zeilen, die mit 'inbound' oder 'outbound' beginnen, was die Richtung der Nachricht angibt. Sie sind im Python-String-Format, wobei '\xYY' für nicht druckbare Zeichen verwendet wird. Diese werden automatisch von 'mutiny_prep.py' und Decept generiert, müssen aber manchmal manuell angepasst werden.
Wenn eine Nachricht das Schlüsselwort 'fuzz' nach 'outbound' enthält, bedeutet dies, dass sie durch Radamsa gefuzzt werden soll. Eine bestimmte Nachricht kann Zeilenfortsetzungen haben, indem einfach mehr Nachrichtendaten in Anführungszeichen in eine neue Zeile gesetzt werden. In diesem Fall wird diese zweite Zeile mit der ersten zusammengeführt.
Alternativ kann das Schlüsselwort 'sub' verwendet werden, um eine Unterkomponente anzugeben. Dies ermöglicht die Angabe einer separaten Komponente der Nachricht, um nur bestimmte Teile zu fuzzen und der Einfachheit innerhalb eines Message Processors.
Hier ist ein Beispiel für einen beliebigen Satz von Nachrichtendaten:
outbound 'sag'
' hallo'
sub fuzz ' und fuzz'
' dies'
sub ' aber nicht dies\xde\xad\xbe\xef'
inbound 'dies ist die erwartete Antwort'
' des Servers'
Dies bewirkt, dass Mutiny sag hallo und fuzz dies aber nicht dies(0xdeadbeef) überträgt. 0xdeadbeef wird als 4 Hex-Bytes übertragen. und fuzz dies wird für das Fuzzing an Radamsa übergeben, aber sag hallo und aber nicht dies(0xdeadbeef) bleiben unverändert.
Mutiny wartet nach dem Übertragen der einzelnen obigen Nachricht auf eine Antwort vom Server,
aufgrund der 'inbound'-Zeile. Die erwartete Antwort des Servers ist
dies ist die erwartete Antwort des Servers. Mutiny wird nicht viel mit diesen Daten anstellen,
außer zu prüfen, ob das, was der Server tatsächlich gesendet hat, mit diesem String übereinstimmt.
Wenn ein Absturz auftritt, protokolliert Mutiny sowohl die erwartete Ausgabe vom Server als auch das,
was der Server tatsächlich geantwortet hat.
mutiny_classes/ enthält Basisklassen für den Message Processor, Monitor und Exception Processor. Jede dieser Dateien kann in denselben Ordner wie die .fuzzer-Datei (standardmäßig) oder in einen separaten Unterordner kopiert werden, der als 'processor_dir' innerhalb der .fuzzer-Datei angegeben wird.
Diese drei Klassen ermöglichen das Speichern von Serverantworten und das Ändern ausgehender Nachrichten, das Überwachen des Ziels in einem separaten Thread sowie das Ändern der Art und Weise, wie Mutiny Ausnahmen behandelt.
Der Message Processor definiert verschiedene Callbacks, die während eines Fuzzing- Durchlaufs aufgerufen werden. Innerhalb dieser Callbacks kann jeder Python-Code ausgeführt werden. Anekdotisch werden diese hauptsächlich auf drei Arten verwendet.
Am häufigsten, wenn der Server Tokens sendet, die zu zukünftigen ausgehenden
Nachrichten hinzugefügt werden müssen. Wenn Mutiny beispielsweise mit der ersten Nachricht eingeloggt wird,
und der Server mit einer Sitzungs-ID antwortet, kann der Callback postReceiveProcess() verwendet werden,
um diese Sitzungs-ID zu speichern. Dann kann in preSendProcess() die ausgehenden Daten
mit dieser Sitzungs-ID repariert werden. Ein Beispiel hierfür ist in
sample_apps/session_server.
Eine weitere häufige Verwendung eines Message Processors besteht darin, eine gefuzzte Nachricht zu begrenzen oder zu ändern. Wenn der Server beispielsweise immer Nachrichten verwirft, die größer als 1000 Bytes sind, könnte es sich nicht lohnen, große Nachrichten zu senden. preSendProcess() kann verwendet werden, um Nachrichten nach dem Fuzzing, aber vor dem Senden zu verkürzen oder eine Ausnahme auszulösen.
Das Auslösen einer Ausnahme führt zur letzten Art, wie Message Processors üblicherweise verwendet werden.
Innerhalb eines Callbacks können benutzerdefinierte Ausnahmen, die in
mutiny_classes/mutiny_exceptions.py definiert sind, ausgelöst werden. Es gibt mehrere
Ausnahmen, alle kommentiert, die verschiedene Verhaltensweisen von Mutiny bewirken. Diese beinhalten
im Allgemeinen entweder Protokollierung, Wiederholung oder Abbruch des aktuellen Durchlaufs.
Der Monitor hat eine monitorTarget()-Funktion, die in einem separaten Thread vom
Haupt-Mutiny-Fuzzer ausgeführt wird. Der Zweck ist es, die Implementierung eines langlaufenden
Prozesses zu ermöglichen, der einen Host auf irgendeine Weise überwachen kann. Dies kann alles sein, was
in Python möglich ist, wie die Kommunikation mit einem Überwachungs-Daemon auf dem
Ziel, das Lesen einer langen Datei oder sogar das wiederholte Anpingen des Hosts, je nach
den Anforderungen der Fuzzing-Sitzung.
Wenn der Monitor einen Absturz erkennt, kann er jederzeit signalMain() aufrufen. Dies wird
den Haupt-Mutiny-Thread signalisieren, dass ein Absturz aufgetreten ist, und dieser wird den
Absturz protokollieren. Diese Funktion sollte normalerweise in einer Endlosschleife arbeiten, da eine Rückkehr
den Thread beenden wird und er nicht neu gestartet wird.
Der Exception Processor bestimmt, was Mutiny mit einer bestimmten Ausnahme
während einer Fuzzing-Sitzung tun soll. Im allgemeinsten Sinne wird die
processException()-Funktion Python- und Betriebssystem-Ausnahmen so gut wie möglich in
Mutiny-Fehlerbehandlungsaktionen übersetzen.
Wenn Mutiny beispielsweise 'Verbindung abgelehnt' erhält, ist die Standardantwort, anzunehmen,
dass der Zielserver unwiederbringlich abgestürzt ist, so dass Mutiny den vorherigen Durchlauf protokolliert
und anhält. Dies trifft in den meisten Fällen zu, aber dieses Verhalten kann auf das Verhalten einer
der Ausnahmen in mutiny_classes/mutiny_exceptions.py geändert werden, falls nötig,
was eine Anpassung der Absturzerkennung und Fehlerkorrektur ermöglicht.