Natas Nivel 22 a 23
Nivel oficial: http://natas22.natas.labs.overthewire.org
El nivel ilustra un error de logica muy frecuente en PHP: usar header('Location: ...') para redirigir al usuario sin detener la ejecucion del script. El cuerpo HTML con informacion sensible se genera igualmente, pero el navegador lo descarta al seguir el redirect. Un cliente que ignora los redirects (como curl) ve ese cuerpo sin problema.
Este laboratorio es legal y autorizado. Solo practica estas tecnicas en entornos de wargame como OverTheWire o sistemas sobre los que tengas permiso explicito.
Objetivo
Obtener la contrasena de natas23 accediendo al cuerpo de la respuesta HTTP que el servidor genera antes de redirigir, sin seguir la cabecera Location.
Que aprendes
| Concepto / Comando | Para que sirve |
|---|---|
header('Location: url') en PHP | Envia una cabecera HTTP 302 que indica al cliente donde ir |
exit() / die() tras header() | Detiene la ejecucion PHP; sin el, el script sigue generando cuerpo |
curl -v URL | Muestra cabeceras de respuesta y cuerpo sin seguir el redirect |
curl -L URL | Sigue redirects (comportamiento del navegador; aqui NO lo queremos) |
Parametro revelio en la query string | Control de flujo del nivel: activa la rama que muestra la contrasena |
Concepto clave: header() sin exit() en PHP
La categoria de vulnerabilidad es Improper Output Neutralization / Logic Flaw (OWASP A04 - Insecure Design). Se clasifica habitualmente como Redirect sin halt o Response Splitting logic flaw.
El patron es el siguiente: el codigo PHP comprueba una condicion (ausencia del parametro revelio) y, si no se cumple, llama a header('Location: /') para redirigir al usuario. Sin embargo, PHP no para la ejecucion automaticamente despues de enviar una cabecera. El interprete continua ejecutando el resto del script, que imprime el contenido HTML con la contrasena.
// Logica vulnerable (simplificada del nivel)
if (!isset($_GET['revelio'])) {
header('Location: /');
// SIN exit() aqui -> el codigo siguiente se ejecuta igual
}
// Este bloque se ejecuta siempre, con o sin redirect
echo "La contrasena es: " . file_get_contents('/etc/natas_webpass/natas23');El navegador recibe la respuesta, lee la cabecera Location y navega a la nueva URL antes de mostrar el cuerpo. Para el usuario parece que la pagina solo redirige. Pero el cuerpo ya viajo en la misma respuesta HTTP; simplemente el navegador lo ignoro.
Paso a paso
1. Acceder al nivel con las credenciales de natas22
# Usuario: natas22
# Contrasena: <pass_natas22>
# URL: http://natas22.natas.labs.overthewire.org2. Intentar el acceso normal desde el navegador
Abre la URL sin parametros. El servidor responde con un 302 Found y te manda de vuelta a /. No ves nada util porque el navegador sigue el redirect.
3. Inspeccionar la respuesta con curl sin seguir redirects
Por defecto curl NO sigue redirects, lo que nos permite leer el cuerpo que el servidor genero antes de redirigir.
curl -u natas22:<pass_natas22> \
"http://natas22.natas.labs.overthewire.org/"Veras las cabeceras de respuesta y el cuerpo HTML. Si el nivel requiere el parametro revelio para entrar en la rama que imprime la contrasena, pasalo directamente:
curl -u natas22:<pass_natas22> \
"http://natas22.natas.labs.overthewire.org/?revelio=1"4. Leer la contrasena en el cuerpo de la respuesta
La salida de curl incluira algo similar a:
<html>
...
<div id="content">
The password for natas23 is: <pass_natas23>
</div>
...
</html>Esa es la contrasena del siguiente nivel. El servidor la incluyo en el cuerpo a pesar del header('Location') porque no hay exit() despues.
5. Verificar que el navegador sigue el redirect (para entender el contraste)
# Con -L curl sigue el redirect; el cuerpo con la pass desaparece
curl -L -u natas22:<pass_natas22> \
"http://natas22.natas.labs.overthewire.org/?revelio=1"Con -L llegas a la pagina destino del redirect y ya no ves la contrasena. Esto replica lo que ve el navegador normal.
Por que funciona
HTTP y PHP son capas independientes. header() en PHP escribe una linea en la seccion de cabeceras de la respuesta HTTP, pero no tiene ningun efecto sobre el flujo de ejecucion del interprete PHP. La separacion entre cabeceras y cuerpo en HTTP/1.1 significa que ambas partes viajan juntas en la misma conexion TCP.
El navegador aplica la logica de seguir el redirect como convencion de cliente, no porque el servidor le impida ver el cuerpo. Un cliente minimalista como curl (o Burp Suite con el seguimiento desactivado, o cualquier script HTTP que no implemente redirects automaticos) recibe y muestra ese cuerpo sin restriccion.
El fix correcto en PHP es siempre:
header('Location: /');
exit(); // o die(); — detiene la ejecucion inmediatamenteErrores comunes
-
Usar
curl -L: con la opcion-Lcurl sigue los redirects igual que un navegador y aterrizas en la pagina destino sin ver el cuerpo original. Omite-L. -
Olvidar la autenticacion HTTP Basic: todo el dominio exige
Authorization: Basic. Usa-u natas22:<pass_natas22>o incluye las credenciales en la URL (http://natas22:<pass>@natas22...). Sin ellas obtendras un401 Unauthorized. -
No pasar el parametro
revelio: si el script tiene la comprobacion del parametro para decidir que rama ejecutar, sin?revelio=1en la URL puede que el cuerpo generado no contenga la contrasena aunque el redirect no se siga. -
Confundir
302con301: ambos redirigen, pero el comportamiento es el mismo desde el punto de vista del cuerpo filtrado. La vulnerabilidad existe en cualquier codigo de redirect (301, 302, 303, 307) cuando no va seguido deexit().
Pasar al siguiente nivel
La contrasena obtenida en el cuerpo de la respuesta es la credencial para:
- URL:
http://natas23.natas.labs.overthewire.org - Usuario:
natas23 - Contrasena:
<pass_natas23>
El nivel 23 introduce comparaciones de tipo debil en PHP (== vs ===) y la coercion de tipos al comparar strings con enteros, otra clase de logic flaw muy caracteristica del lenguaje.