Local File Inclusion (LFI)
Ahora que entendemos qué son las vulnerabilidades de inclusión de archivos y cómo ocurren, podemos comenzar a aprender cómo podemos explotar estas vulnerabilidades en diferentes escenarios para poder leer el contenido de los archivos locales en el servidor back-end.
LFI básico
Recorrido de ruta
En el payload anterior funcionaría si se usara toda la entrada dentro de la include()
función sin añadir nada, como en el siguiente ejemplo:
En este caso, si intentamos leer /etc/passwd
, la include()
función recuperará ese archivo directamente. Sin embargo, en muchas ocasiones, los desarrolladores web pueden añadir o anteponer una cadena al variable
parámetro. Por ejemplo, el language
parámetro puede usarse para el nombre del archivo y añadirse después de un directorio, como se indica a continuación:
En este caso, si intentamos leer /etc/passwd
, entonces la ruta pasada a include()
sería ( ./variable//etc/passwd
), y como este archivo no existe, no podremos leer nada:
Como era de esperar, el error detallado devuelto nos muestra la cadena pasada a la include()
función, indicando que no existe /etc/passwd
en el directorio de variable.
Podemos evitar fácilmente esta restricción recorriendo directorios usando relative paths
. Para ello, podemos añadir ../
antes del nombre del archivo, que hace referencia al directorio principal. Por ejemplo, si la ruta completa del directorio de idiomas es /var/www/html/variable/
, entonces usar ../index.php
haría referencia al index.php
archivo en el directorio principal (es decir, /var/www/html/index.php
).
Entonces, podemos usar este truco para retroceder varios directorios hasta llegar a la ruta raíz (es decir, /
), y luego especificar nuestra ruta de archivo absoluta (por ejemplo, ../../../../etc/passwd
), y el archivo debería existir:
Como podemos ver, esta vez pudimos leer el archivo sin importar el directorio en el que nos encontráramos. Este truco funcionaría incluso si se usara el parámetro completo en la include()
función, así que podemos usar esta técnica por defecto y debería funcionar en ambos casos. Además, si estuviéramos en la ruta raíz ( /
) y usáramos ../
`, permaneceríamos en ella. Por lo tanto, si no estuviéramos seguros del directorio en el que se encuentra la aplicación web, podemos agregar ` ../
varias veces` sin que se rompa la ruta (¡aunque lo hagamos cientos de veces!).
Prefijo de nombre de archivo
En nuestro ejemplo anterior, usamos el variable
parámetro después del directorio para poder recorrer la ruta y leer el passwd
archivo. En ocasiones, nuestra entrada puede añadirse después de una cadena diferente. Por ejemplo, puede usarse con un prefijo para obtener el nombre completo del archivo, como en el siguiente ejemplo:
En este caso, si intentamos recorrer el directorio con ../../../etc/passwd
, la cadena final sería lang_../../../etc/passwd
, lo cual no es válido:
Como era de esperar, el error nos dice que este archivo no existe. Por lo tanto, en lugar de usar directamente el recorrido de ruta, podemos anteponer un a /
a nuestra carga útil, y esto debería considerar el prefijo como un directorio y luego deberíamos omitir el nombre del archivo y poder recorrer directorios:
Extensiones adjuntas
Otro ejemplo muy común es cuando se añade una extensión al variable
parámetro, como sigue:
Esto es bastante común, ya que en este caso no tendríamos que escribir la extensión cada vez que necesitemos cambiar el idioma. Esto también podría ser más seguro, ya que podría restringirnos a incluir solo archivos PHP. En este caso, si intentamos leer /etc/passwd
, el archivo incluido sería /etc/passwd.php
, que no existe:
Hay varias técnicas que podemos utilizar para evitar esto y las analizaremos en las próximas secciones.
Ataques de segundo orden
Como podemos ver, los ataques LFI pueden presentarse de diferentes formas. Otro ataque LFI común, y un poco más avanzado, es un Second Order Attack
. Esto ocurre porque muchas funcionalidades de aplicaciones web pueden estar extrayendo archivos del servidor back-end de forma insegura según parámetros controlados por el usuario.
Por ejemplo, una aplicación web podría permitirnos descargar nuestro avatar mediante una URL como ( /profile/$username/avatar.png
). Si creamos un nombre de usuario LFI malicioso (por ejemplo, ../../../etc/passwd
), podríamos cambiar el archivo que se extrae a otro archivo local en el servidor y obtenerlo en lugar de nuestro avatar.
En este caso, estaríamos envenenando una entrada de la base de datos con una carga LFI maliciosa en nuestro nombre de usuario. Luego, otra funcionalidad de la aplicación web utilizaría esta entrada envenenada para ejecutar nuestro ataque (es decir, descargar nuestro avatar basándose en el valor del nombre de usuario). Por eso, este ataque se denomina Second-Order
ataque.
Los desarrolladores suelen pasar por alto estas vulnerabilidades, ya que pueden proteger contra la entrada directa del usuario (por ejemplo, desde un ?page
parámetro), pero pueden confiar en valores extraídos de su base de datos, como nuestro nombre de usuario en este caso. Si lográramos manipular nuestro nombre de usuario durante el registro, el ataque sería posible.
La explotación de vulnerabilidades LFI mediante ataques de segundo orden es similar a lo que hemos analizado en esta sección. La única diferencia radica en que necesitamos identificar una función que extraiga un archivo basándose en un valor que controlamos indirectamente y luego intentar controlar ese valor para explotar la vulnerabilidad.
Last updated