WebSocket Fuzzing - Entwicklung eines eigenen Fuzzers

WebSocket Fuzzing

Entwicklung eines eigenen Fuzzers

Andrea Hauser
von Andrea Hauser
am 20. April 2023
Lesezeit: 8 Minuten

Keypoints

So lässt sich WebSocket Fuzzing umsetzen

  • Toolunterstützung im Bereich WebSockets ist nicht gut beziehungsweise nicht vollständig
  • Wenn viele WebSocket Nachrichten von der Applikation versandt werden ist manuelles Testen unmöglich
  • Es wurde ein eigenes Skript erstellt, dass den Versand und das Fuzzen von WebSocket Nachrichten automatisiert
  • Die Auswertung der gefuzzten Nachrichten muss vom Tester allerdings immer noch manuell getroffen werden

Vor kurzem trafen wir in einem Projekt auf eine Webseite, die praktisch ausschliesslich über WebSockets kommuniziert. Grundsätzlich hatten wir auch schon früher Webseiten mit WebSockets angetroffen, allerdings wurden da die WebSockets jeweils nur für einen kleinen und sehr spezifischen Teil der Webseite eingesetzt. Wenn nur ein kleiner Teil der Webseite mit WebSockets interagiert, können die WebSockets gut manuell getestet werden. In diesem Projekt zeigte sich allerdings, dass dieser Ansatz für grössere Projekte mit mehr WebSocket-Interaktionen nicht sinnvoll ist.

Die Toolunterstützung ist im Bereich der WebSockets nicht gut fortgeschritten, zum Beispiel können in Burp zwar WebSockets aufgezeichnet und manuell im Repeater manipuliert und wiederholt werden, es besteht allerdings keine Möglichkeit WebSocket Nachrichten zu scannen oder zu fuzzen. Eine kurze Internetsuche zeigt, dass OWASP ZAP eine integrierte WebSocket-Fuzzing-Funktionalität haben soll, allerdings konnte die getestete Webseite nicht mehr genutzt werden, sobald sie durch ZAP als Proxy geleitet wurde, da die WebSocket Verbindungen immer direkt geschlossen wurden. Somit wurde auch ZAP als Möglichkeit für das automatisierte Auswerten von WebSockets ausgeschlossen. Eine etwas vertieftere Internetsuche bringt zwar einige WebSocket Fuzzer zum Vorschein, doch die sind stark veraltet und basieren noch auf Python2 und konnten in aktuellen Testumgebungen nicht mehr ohne Aufwand gestartet werden. Dementsprechend haben wir uns entschieden ein eigenes WebSocket Fuzzing Skript zu erstellen.

Eine zeitliche Investition in die Entwicklung eines eigenen Skripts macht zudem auch Sinn, wenn kürzlich getroffene Aussagen von PortSwigger in die Entscheidung miteinbezogen werden. Denn gemäss PortSwigger ist das WebSocket Fuzzing aktuell nicht umgesetzt und erst etwas, dass sie hoffen in Zukunft zu erforschen. Dementsprechend muss für die Zwischenzeit, solange keine Unterstützung von Burp besteht eine eigene Lösung gefunden werden. PortSwigger beruft sich darauf, dass das WebSocket Scanning schwierig ist, da es nicht einfach ist eine Ursache und Wirkung festzustellen. Diese Problematik wurde bei der Entwicklung des Skripts ebenfalls beachtet und es wurde sich dazu entschieden, aktuell keine Logik für die Erkennung von Schwachstellen in das Skript einzubauen. Stattdessen werden mit dem Skripts lediglich Payloads ausgelöst und, falls erhalten, werden die Antworten des Servers aufgezeichnet. Es wird dann dem Tester überlassen die ausgelösten Antworten und weiteren Verhalten des Servers manuell zu verarbeiten und interpretieren. Ziel des Skripts ist es dem Tester das manuelle Auslösen von vielen WebSocket Nachrichten zu ersparen.

Funktionalität des Skripts

Die grundsätzlichen Anforderungen an dieses Skript wurden bewusst tief gehalten, so musste das Skript lediglich erfolgreich eine WebSocket Verbindung aufbauen können und danach eine Payload aus einer Datei abschicken. Dies wurde mit der folgenden, für den Artikel gekürzten, Funktion fertiggestellt:

def fuzzer(cookie, hostname, url, fuzz_values_file, websocket_messages_file, proxy_host, proxy_port, verbose):

    # Read fuzzing payloads from text file
    with open(fuzz_values_file, "r") as f:
        fuzz_values = [payload_parsing(line.rstrip('\n')) for line in f.readlines()]

    # Read WebSocket message from text file
    with open(websocket_messages_file, "r") as messages_file:

        for websocket_message in messages_file:
            websocket_message = websocket_message.strip()
            for fuzz_value in fuzz_values:
                # Create the WebSocket
                if proxy_host is None:
                    ws = websocket.WebSocket()
                    ws.connect("wss://"+hostname+url, cookie=cookie, origin="https://"+hostname)
                else:
                    ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
                    ws.connect("wss://"+hostname+url, cookie=cookie, origin="https://"+hostname,
                               http_proxy_host=proxy_host, http_proxy_port=proxy_port, proxy_type="http")

                # Replace FUZZ_VALUE with attack payload from the file
                message = websocket_message.replace("FUZZ_VALUE", fuzz_value)
                print("\n<----> WebSocket message that will be sent/fuzzed: " + message + "\n")

                # Send the fuzzed message over the WebSocket connection and wait for answer
                ws.send(message)
                ws.recv()
                ws.close()

In der aller ersten Version des Skripts musste jedes Mal, bevor eine WebSocket Nachricht gefuzzt werden konnte eine manuelle Anpassung des Skripts vorgenommen werden, da sich die zu fuzzende Nachricht im Skript befand. Dies wurde durch das Auslagern der WebSocket Nachrichten in eine zweite Datei behoben. Dadurch entstehen zwar etwas unschöne verschachtelte for-Schleifen, für das Testen ist es allerdings viel einfacher zu benutzen.

Zudem ist in dieser Version des Skripts das Payload Parsing auf JSON ausgelegt, da in unserem Fall JSON Nachrichten via WebSockets versandt wurden. Dies müsste je nach angetroffenen WebSocket Nachrichten ebenfalls noch optimiert werden vor dem Fuzzing.

def payload_parsing(payload):
    payload = payload.replace('"', '\\"')
    return payload

Das ganze Skript wurde auf unserem GitHub zur Verfügung gestellt. Dort sind auch effektive Benutzungsbeispiele aufgeführt.

Wichtig zu beachten bei der Verwendung dieses Skripts ist, dass das Skript selbst keine Auswertungen zum Fuzzing macht. Das heisst aktuell wird stark empfohlen das Skript durch einen Proxy wie Burp laufen zu lassen, damit danach die ausgelösten Antworten weiter manuell ausgewertet werden können.

WebSocket Testing Tipps

Tipps für Tester wie das Skript für die besten Ergebnisse genutzt werden kann: Zuerst sollte analysiert werden, wie die Webseite die WebSocket Messages aufbaut und versendet. Das Versenden einer Nachricht sollte zuerst ohne Fuzzing mit dem Skript nachgespielt werden können, ansonsten macht das Fuzzing wenig Sinn. Während unserem Testing wurde festgestellt, dass für das Erhalten einer Antwort des Servers oft mehr als eine Nachricht über den WebSocket geschickt werden muss. Dementsprechend wurde im Skript die Möglichkeit zur Verfügung gestellt solche “pre messages” vorzugeben, bevor die effektive Fuzzing Nachricht verarbeitet wird. Das Fuzzing der WebSocket Nachrichten selbst ist nur so gut wie die zusammengestellten Fuzzing-Payloads, dementsprechend sollten solche Listen mit Sorgfalt erstellt werden.

Nachdem die Nachrichten erfolgreich gefuzzt wurden, kann folgendes gemacht werden, um die manuelle Analyse zu vereinfachen: Im verwendeten Proxy in der WebSocket History nur noch die vom Server erhaltenen Nachrichten anzeigen und diese nach Grösse sortieren. So kann schnell erkannt werden, ob es Nachrichten mit einer abweichenden Grösse gibt, diese können dann als erstes ausgewertet werden. Es kann zudem manuell gefiltert werden auf erwartete Fehlermeldungen.

Neben dem, was das Skript an Testing Möglichkeiten zur Verfügung stellt, ist ebenfalls zu beachten, dass es noch weitere WebSocket spezifische Schwachstellen gibt, die durch dieses Skript nicht abgedeckt werden. Wie diese Bereiche von WebSockets getestet werden können, wurde bereits in einem unserer früheren Labs-Artikel ausführlich beschrieben.

Ideen für Weiterentwicklungen

Die folgenden Verbesserungspunkte wurden bereits festgehalten für dieses Skript und werden zu einem späteren Zeitpunkt noch entwickelt:

Fazit

Das hier zur Verfügung gestellte Skript kann einem Tester einen Teil der manuellen Bearbeitung von WebSocket Nachrichten abnehmen. Tester, die dieses Skript verwenden, müssen sich allerdings bewusst sein, dass weiterhin manueller Aufwand für die Auswertung der generierten Nachrichten dieses Skripts besteht. Das Skript vereinfacht allerdings das Fuzzing deutlich, da viel mehr Nachrichten abgesetzt werden können, als das mit nur manuellem wiederholen von Nachrichten möglich wäre. Obwohl das Skript während dem Testing bereits einige Verbesserungen und Erweiterungen erhalten hat gibt es weiterhin Bereiche in die Zeit investiert werden können.

Über die Autorin

Andrea Hauser

Andrea Hauser hat ihren Bachelor of Science FHO in Informatik an der Hochschule für Technik Rapperswil abgeschlossen. Sie setzt sich im offensiven Bereich in erster Linie mit Web Application Security Testing und der Umsetzung von Social Engineering Kampagnen auseinander. Zudem ist sie in der Forschung zum Thema Deepfakes tätig. (ORCID 0000-0002-5161-8658)

Links

Sie wollen die Sicherheit Ihrer Firewall prüfen?

Unsere Spezialisten kontaktieren Sie gern!

×
Angriffsmöglichkeiten gegen Generative AI

Angriffsmöglichkeiten gegen Generative AI

Andrea Hauser

XML-Injection

XML-Injection

Andrea Hauser

Burp Makros

Burp Makros

Andrea Hauser

Prototype Pollution

Prototype Pollution

Andrea Hauser

Sie wollen mehr?

Weitere Artikel im Archiv

Sie brauchen Unterstützung bei einem solchen Projekt?

Unsere Spezialisten kontaktieren Sie gern!

Sie wollen mehr?

Weitere Artikel im Archiv