XUT_ / COURSES / PENETRATION TESTER

Abusing Websockets for Request Smuggling

Contrabandeando Peticiones HTTP a través de Túneles Rotos de WebSockets

Para contrabandear peticiones a través de un proxy vulnerable, podemos crear una petición malformada para que el proxy piense que un upgrade WebSocket es realizado, pero el backend no eleva la conexión. Esto forzará al proxy a establecer un túnel entre el cliente y el servidor que no será comprobado ya que asume que ahora es una conexión WebSocket, pero el backend seguirá esperando tráfico HTTP.

Una forma de forzar esto es mandar una petición con un header Sec-Websocket-Version inválido. Este header es usado para especificar la versión del protocolo WebSocket a usar y normalmente tomará el valor 13 en la gran mayoría de implementaciones actuales de WebSocket. Si el servidor soporta la versión pedida, debería mandar una respuesta 101 Switching Protocols y elevar la conexión.

Pero no estamos interesados en mejorar la conexión. Si mandamos un valor no soportado para el header Sec-Websocket-Version, el servidor mandará una respuesta 426 Upgrade Required para indicar que la upgrade no fue exitosa.

Abusing Websockets for Request Smuggling

Algunos proxies pueden asumir que la upgrade siempre es completada independientemente de la respuesta del servidor. Esto puede ser abusado para contrabandear peticiones HTTP una vez más realizando los siguientes pasos:

  1. El cliente manda una petición de upgrade WebSocket con una versión inválida.
  2. El proxy redirecciona la petición al backend.
  3. El backend responde con 426 Upgrade Required. La conexión no se eleva, por lo que el backend continúa usando HTTP en lugar de cambiar a WebSockets.
  4. El proxy no comprueba la respuesta del servidor y asume que la elevación fue exitosa. Cualquier comunicación posterior será tuneleada ya que el proxy cree que son parte de una conexión elevada WebSocket.

Abusing Websockets for Request Smuggling

IMPORTANT

Esta técnica no nos permite contaminar las conexiones de backend de otros usuarios. Estaremos limitados a tunelear peticiones a través del proxy por lo que podemos evadir cualquier restricción impuesta por el frontend con este truco.


Bypassear Restricciones del Proxy

Comprobemos la aplicación en el directorio /flag de la máquina. Esta aplicación corre detrás del proxy Varnish con una configuración vulnerable. Nuestro objetivo en esta aplicación es recuperar el valor guardado en dicho directorio.

Al primer intento vamos al directorio directamente y se nos muestra el siguiente mensaje:

Abusing Websockets for Request Smuggling

El mensaje de error fue mandado por Varnish (el proxy) en lugar de por el backend, lo que podría ser interesante. Si intentamos acceder a otro recurso no existente como http://IP:8001/noexistent134, el mensaje de error presentado será diferente. En este punto deberíamos sospechar que el frontend está restringiendo el acceso a /flag en el backend.

Por suerte, también hay un endpoint WebSocket que podemos abusar en /websocket. Mandaremos el siguiente payload para tratar de contrabandear una petición dentro de una conexión WebSocket rota:

shell-session
GET /socket HTTP/1.1
Host: 10.114.191.82:8001
Sec-WebSocket-Version: 777
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==

GET /flag HTTP/1.1
Host: 10.114.191.82:8001

Para mandar la petición, usaremos el Repeater de Burp Suite. Para asegurarnos que Burp no modifica nuestra petición y rompe el ataque, necesitaremos asegurarnos de que Update Content-Length está desactivado:

Abusing Websockets for Request Smuggling

Una vez hecho esto, podemos mandar el payload y deberíamos obtener la flag (date cuenta de las dos lineas al final del payload):

Abusing Websockets for Request Smuggling

Como esperábamos, obtenemos un error 426 de la primera petición al WebSocket. En este punto el proxy piensa que la conexión usa ya WebSockets y tuneliza todo directamente al backend, incluyendo peticiones contrabandeadas.


¿Qué Pasa si la App no Habla WebSocket?

Debes saber que algunos proxies ni siquiera requieren la existencia de un endpoint websocket para que esta técnica funcione. Todo lo que necesitamos es engañar al proxy para que piense que estamos estableciendo una conexión WebSocket incluso si no es cierto. Mira lo que pasa si intentas mandar el siguiente payload (asegúrate de añadir dos líneas al final).

shell-session
GET / HTTP/1.1
Host: 10.114.191.82:8001
Sec-WebSocket-Version: 13
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==

GET /flag HTTP/1.1
Host: 10.114.191.82:8001

Este payload debería funcionar, incluso aunque está dirigido a /, que no es un endpoint WebSocket-habilitado. El proxy simplemente no comprueba la respuesta del upgrade por lo que puedes usar cualquier payload que se parezca a un WebSocket upgrade.