PHP Filter Wrapper (Source Disclosure)
Arsenal completo de comandos en la cheatsheetphp://filter es uno de los wrappers de flujo de PHP: una "tubería" que aplica filtros de transformación a un recurso antes de entregarlo. Su abuso clásico convierte una primitiva de inclusión o lectura de ficheros (LFI, XXE) en robo del código fuente de la aplicación.
El problema que resuelve para el atacante. Si pides directamente un fichero .php a través de un LFI o un XXE, el servidor lo ejecuta y solo ves su salida (a menudo vacía), no su código. Los secretos viven en el código: credenciales de base de datos, claves de API, lógica de autenticación. Para verlos hace falta obtener el texto fuente, no el resultado de ejecutarlo.
La técnica. Se envuelve el recurso con el filtro convert.base64-encode, que codifica el contenido del fichero en Base64 antes de incluirlo. Como el resultado es texto Base64 (no código PHP válido), el motor no lo ejecuta: lo devuelve tal cual, y al descodificarlo aparece el fuente íntegro:
php://filter/read=convert.base64-encode/resource=/var/www/html/db.phpecho -ne '<base64 recibido>' | base64 -d # -> código fuente de db.phpPor qué Base64. Sin el filtro, incluir db.php lo ejecutaría; con convert.base64-encode, PHP procesa el fichero por el flujo del filtro y emite Base64, que sobrevive intacto a la inclusión. Otros filtros encadenables permiten cosas más avanzadas (la técnica de filter chains llega incluso a generar contenido arbitrario para RCE), pero el caso habitual es la exfiltración de fuentes.
De LFI a RCE con filter chains. Cuando no hay wrappers data:///input, una cadena de filtros iconv construye byte a byte código PHP arbitrario usando solo php://filter, convirtiendo un LFI de lectura en RCE:
python3 php_filter_chain_generator.py --chain '<?php system($_GET["cmd"]); ?>'
# pega la cadena php://filter/... resultante en el parametro vulnerable y anade &cmd=id
curl 'http://<ip>/index.php?page=php://filter/convert.iconv.../resource=php://temp&cmd=id'Dónde aplica. Cualquier punto que incluya o lea una ruta controlable: parámetros tipo ?page=, ?file=, y también dentro de un XXE como recurso de la entidad externa, exactamente como en BountyHunter para sacar db.php.
Cómo detectarlo. La firma en el log de acceso es el propio wrapper en un parámetro: php://filter/, convert.base64-encode, resource= o, en la variante de RCE, la larga cadena de filtros iconv/convert.iconv.* (los filter chains generan URLs enormes y muy reconocibles). Un WAF que inspeccione parámetros por php:// y base64-encode las bloquea. Un pico de respuestas grandes en Base64 desde endpoints tipo ?page=/?file= sugiere exfiltración de fuentes. Dentro de un XXE, la misma cadena aparece como recurso de la entidad externa en el cuerpo XML.
Defensa. No pasar entrada del usuario a funciones de inclusión/lectura de ficheros; si es inevitable, usar listas blancas de rutas y deshabilitar los wrappers peligrosos (allow_url_include=Off, restringir php://). Y, de fondo, no incrustar secretos en el código accesible por la web.
Máquinas donde se aplica
- BountyHunterHackTheBox
- Hacker Kid 1.0.1VulnHub
- Symfonos 5VulnHub