El cruce o salto de directorio (identificado mediante CWE-22) es una vulnerabilidad de aplicaciones web que permite a los atacantes acceder a archivos restringidos dentro de un sistema subyacente. Según cómo y dónde se produzca el salto, el atacante puede leer o escribir archivos arbitrarios de un servidor web, llegando a acceder a archivos o datos de naturaleza sensible, modificar datos de aplicaciones o tomar el control completo del servidor web.
Las vulnerabilidades de salto se dividen normalmente entre las que permiten leer archivos y las que permiten escribir archivos. En los próximos apartados mostraremos cómo puede afectar cada una.
Piensa en una aplicación en la que un usuario almacena fotos para luego recuperarlas mediante una petición GET, utilizando un parámetro de nombre de archivo que indique qué archivo se debe recuperar. Si la aplicación no puede impedir el salto de directorio y crea la ruta del archivo a partir del parámetro de nombre de archivo proporcionado, podrían recuperarse archivos arbitrarios del servidor web subyacente. La figura n.º 1 muestra esta secuencia en la práctica:
Si bien la aplicación es vulnerable ante el salto descrito, sigue habiendo limitaciones que hay que tener en cuenta, como los permisos de la aplicación. Por ejemplo, si se aplica el principio del mínimo privilegio, que restringe el acceso de la aplicación al servidor web, sus permisos pueden limitar los archivos a los que tiene acceso el atacante aprovechándose de la vulnerabilidad. Este es uno de los motivos por los que las cargas útiles de salto suelen utilizar /etc/passwd como objetivo, y es que el archivo debe ser legible para todos los usuarios. Hay otras formas de aislar y limitar el acceso a la aplicación que repasaremos más a fondo en el apartado de prevención.
Vuelve a pensar en esa misma aplicación de almacenamiento de fotos, pero ahora resulta que permite al usuario dar nombre a cada una de las imágenes que almacena. Al guardar el archivo en el disco, la aplicación utiliza el nombre proporcionado para generar la ruta de archivo de la foto. A menos que haya suficientes protecciones, un atacante puede añadir al nombre secuencias de salto (p. ej., «../») que le permitan controlar en qué directorio se almacena el archivo.
Por muy inofensiva que parezca esta acción tratándose del almacenamiento de una foto, hay modos de sacar más provecho de la vulnerabilidad. Si no se valida el tipo de archivo (es decir, JPEG, PNG, etc.), un atacante podría cargar cualquier tipo de archivo y dar pie a distintas situaciones de vulnerabilidad, como por ejemplo:
añadir la llave pública del atacante a un archivo authorized_keys del usuario (p. ej., «/root/.ssh/authorized_keys») para hacerse con un acceso persistente;
sobrescribir archivos de la aplicación para modificar el comportamiento de la misma;
cargar una shell web dentro de la raíz web;
provocar una denegación de servicio sobrescribiendo archivos del sistema necesarios;
cargar archivos ejecutables, como programas maliciosos, ransomware, etc.
Dependiendo del nivel de acceso con el que cuente la aplicación, un salto de directorio con escritura en un archivo arbitrario puede tener un efecto devastador.
Aclarados los conceptos básicos del salto de directorio, veamos cómo se ha aprovechado esta vulnerabilidad en el mundo real en los últimos tiempos.
En la versión 16.0.0 de Gitlab, existe una vulnerabilidad de salto de directorio que permite leer archivos arbitrarios. Si se carga un archivo adjunto dentro de un Issue en una instalación predeterminada de Gitlab, Gitlab almacenará el archivo en una ruta de 10 directorios con un patrón como el siguiente:
/var/opt/gitlab/gitlab-rails/uploads/@hashed/<directory>/<directory>/<directory>/<directory>/<filename>
Después de la carga, Gitlab también proporciona un punto de conexión para recuperar el archivo en cuestión:
/<repo-name>/uploads/<file-id>/<filename>
En una petición enviada al punto de conexión, Gitlab no sanea ni valida el parámetro de nombre de archivo, por lo que es posible lanzar un ataque de salto de directorio. Para aprovechar el salto, el repositorio debe estar anidado a una distancia mínima de 5 grupos. El número de grupos indica la cantidad de directorios que se pueden saltar aprovechando la vulnerabilidad.
En una instalación estándar, esto significa que se debe anidar el repositorio en 11 grupos para poder llegar a la raíz del sistema de archivos. En este caso, una carga útil maliciosa para recuperar el archivo /etc/passwd sería algo así:
GET /Group-1/Group-2/Group-3/Group-4/Group-5/Group-6/Group-7/Group-8/Group-9/Group-10/Group-11/<repo-name>/uploads/<file-id>/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
Los atacantes no autenticados solo pueden aprovechar la vulnerabilidad si hay un repositorio público con los grupos anidados requeridos. Como es difícil que esto ocurra, es más probable que la vulnerabilidad se aproveche por parte de un usuario autenticado con privilegios para crear los grupos y repositorios anidados que hagan falta para ello. Repasando los pasos del aprovechamiento, primero hay que crear los grupos y el repositorio necesarios, luego cargar el archivo y, finalmente, saltar de directorio para leer archivos arbitrarios, como se muestra en esta prueba de concepto.
En compilaciones de Desktop Central de ManageEngine anteriores a 10.1.2127.1, un salto de directorio en la funcionalidad de carga de archivos permitía escribir archivos arbitrarios manipulando el parámetro «computerName» (o algunos otros) para que se incluyeran las secuencias del salto.
Cuando se descubrió, esta vulnerabilidad era objeto de ataques que, combinados con una omisión de autenticación (CVE-2021-44515), permitían ejecutar código de forma remota. Para ser breves, nos centraremos en la parte del ataque correspondiente al salto de directorio, ya que da pie a la escritura del archivo y logra burlar una validación de escasa rigurosidad.
En una función llamada «doPost», Desktop Central maneja varios parámetros dentro de la carga de un archivo, «computerName» y «filename» incluidos. Desde esta función, salen a relucir dos vulnerabilidades que permiten efectuar un salto de directorio con escritura de archivo:
Únicamente se comprueba la presencia de secuencias de saltos en el parámetro «filename», mientras que otros parámetros, como «domainName», «computerName» o «customerId», se usan para generar la ruta absoluta del archivo, pero no se comprueba si llevan consigo secuencias de saltos. Como «computerName» es el último parámetro utilizado en la cadena concatenada, sería el lugar ideal donde introducir una secuencia de salto, puesto que no presentaría ningún contenido inmediatamente posterior.
Se permite cargar archivos con extensiones zip, 7z, and gz, lo cual puede parecer seguro a simple vista. No obstante, al ser Desktop Central una aplicación de Java, y los archivos JAR generarse en formato zip, esto permite ejecutar código de forma remota. Si carga un archivo zip al directorio C:\Program Files\DesktopCentral_Server\lib
y fuerza un reinicio, un atacante avezado puede sobrescribir archivos de clases en la aplicación para que incluyan su propio código y, así, conseguir ejecutar código.
Esta vulnerabilidad pone de relieve las graves consecuencias que puede acarrear una vulnerabilidad de salto de directorio y, a la vez, muestra cómo una prevención incompleta puede abrir la puerta a esta vulnerabilidad.
El salto de directorio es una de las técnicas de ataque más habituales, como destacamos en el Informe de amenazas y efecto red del segundo trimestre de 2023.
Esto puede deberse, entre otros motivos, a las graves consecuencias que puede tener un ataque efectivo o al tamaño de las listas de cargas útiles que pueden utilizar los atacantes y detectores. Por ejemplo, un fragmento de una de las listas de salto de directorio de PayloadsAllTheThings intenta leer el mismo archivo con distintos niveles de salto, como se muestra a continuación:
../../../../../../../../../etc/passwd
../../../../../../../../etc/passwd
../../../../../../../etc/passwd
../../../../../../etc/passwd
../../../../../etc/passwd
../../../../etc/passwd
../../../etc/passwd
En la mayoría de los casos, es difícil que un atacante sepa dónde se encuentra la aplicación dentro del sistema de archivos cuando busca la vulnerabilidad del salto de directorio. No obstante, las aplicaciones no van más allá de la raíz del sistema (es decir, «/»), por lo que los atacantes utilizan secuencias más largas de «../» para asegurarse de que alcanzarán la raíz. Las secuencias más cortas, por su parte, están ahí por si las más largas quedan bloqueadas o interrumpen la funcionalidad de la aplicación.
Otros tipos de ataques, como el scripting entre sitios (XSS), pueden usar cargas útiles políglotas, que combinan múltiples técnicas en una sola carga útil. Así, los atacantes y detectores pueden enviar muchas más cargas útiles para detectar la vulnerabilidad que si simplemente buscasen XSS. Nuestro archivo de ejemplo de PayloadsAllTheThings contiene 140 cargas útiles, comparadas con el archivo XSS_Polyglots, que contiene 16. La carga útil más grande de la vulnerabilidad de salto de directorio en PayloadsAllTheThings cuenta con más de 21 000 entradas, mientras que la más grande de XSS consta de 600, SQLi tiene más de 400 (aunque es de suponer que esta sería más grande en la práctica si la base de datos fuera desconocida, ya que habría que probar muchos tipos) y hay más de 400 por la inyección de comandos en el sistema operativo.
La popularidad de la técnica de ataque de salto se puede explicar, pues, por el tamaño de las listas de cargas útiles, pero también puede ser que se use más a menudo por las graves consecuencias que puede acarrear, como hemos visto con CVE-2022-48362, que permitía la ejecución de código remoto y ya era conocida entre los atacantes cuando se descubrió.
Con tal de prevenir las vulnerabilidades de salto de directorio, se pueden seguir estrategias como realizar cambios en el diseño para evitar generar rutas de archivos con entrada del usuario, la validación estricta de la entrada, el uso de la canonización de rutas y la limitación de los accesos de la aplicación. Repasémoslos a continuación uno por uno.
En vez de usar la entrada del usuario para crear rutas de archivos, podrías usar un nombre o identificador del archivo correspondiente para hacer referencia al archivo. A continuación, asigna identificadores del archivo a la ruta de su ubicación de almacenamiento. Cuando un usuario solicite el archivo o cargue uno, solo podrá controlar el identificador, de modo que será incapaz de acceder a los contenidos utilizados para crear la ruta en cuestión. Así se elimina del todo la posibilidad de un salto de directorio, dado que la entrada del usuario no se usa para generar la ruta del archivo que se recupera.
La validación estricta no es lo mismo que el saneamiento. En vez de sanear la entrada intentando eliminar las secuencias de salto (como «../»), que apenas sirve de algo, valida que la entrada del usuario solo contenga el contenido esperado y rechaza todo lo que no supere la validación estricta. Ejemplos de validación que pueden ayudar a impedir el salto de directorio:
validar que la entrada solo contenga valores alfanuméricos;
validar que haya un solo carácter «.» en el nombre de archivo proporcionado;
validar que no haya caracteres no deseados en la entrada proporcionada, como «/» o «\»;
validar el tipo de archivo de un archivo cargado (pero no por la extensión, que se puede burlar fácilmente);
Lo que hace la canonización, en resumidas cuentas, es acortar la ruta del archivo a su ruta real, eliminando vínculos simbólicos, secuencias de «../» y demás contenido simbólico. Si obtienes una ruta canónica, puedes verificar que empiece con el directorio base previsto (p. ej., uploads/photos/). A continuación exponemos ejemplos de funciones para obtener una ruta canónica:
Java: getCanonicalPath
PHP: realpath
C: realpath
ASP.NET: GetFullPath
En general, una aplicación solo debe tener acceso a archivos y directorios a los que necesita acceder para funcionar correctamente. Así, cuando se produce un salto de directorio, esto puede limitar las consecuencias de la vulnerabilidad si se descubre. Por ejemplo, una aplicación web no tendría que ejecutarse nunca bajo el usuario raíz y, en la medida de lo posible, debería poder acceder solamente a los archivos que necesita para funcionar.
El cruce o salto de directorio es una vulnerabilidad de aplicaciones web que permite a los atacantes acceder a archivos restringidos dentro de un sistema subyacente. Dependiendo de la vulnerabilidad del salto de directorio, el atacante podría llegar a leer archivos o datos de naturaleza sensible, modificar datos de aplicaciones o tomar el control completo del servidor web. Las vulnerabilidades de salto pueden acarrear graves consecuencias y, como hemos visto en los ejemplos reales y los datos del WAF de última generación, son un importante vector de ataque. A pesar de todo, las aplicaciones pueden impedir las vulnerabilidades de cruce de directorio siguiendo las soluciones que hemos mencionado. Si tienes dificultades a la hora de impedir dichas vulnerabilidades o cuentas con un producto que ya las ha sufrido, infórmate acerca del WAF de última generación de Fastly para protegerte ante estos y otros ataques.