Random IRC quote :      <@ggonzalez> la de trikitriki tri <@ggonzalez> monam?

IIS6/ASP & file upload for fun and profit

Hoy vamos a hablar sobre un comportamiento de IIS6 no conocido que considero interesante y puede ser útil a la hora de realizar auditorías de seguridad. Se trata de un artículo sobre cómo funciona IIS6 a la hora de trabajar junto con aplicaciones de terceros que realicen operaciones sobre el sistema de ficheros (creación de directorios, upload de ficheros) tales como gestores de ficheros en web.

Descripción

Tratando de saltar la seguridad en el componente de upload de ficheros de una aplicación ASP corriendo bajo IIS 6, me dí cuenta que IIS sólo usa la parte de la URL antes de una ‘/’ o ‘\’ para determinar si un fichero será ejecutado como un Active Server Page por la librería ASP.dll. En concreto, IIS no parsea correctamente los nombres de los directorios cuando estos tienen extensiones ejecutables como 1) .asp, 2) .asa y 3) .cer. La extensión .aspx parece ser que no está afectada devolviendo un error 404, aun cuando el fichero existe en dicho path.

Cuando se parsea una URL tal como ‘maliciousfolder.asp/code.pdf’, se ejecuta una rutina que comprueba si ese fichero debe ser ejecutado por  la ASP.dll. El carácter ‘/’ (o ‘\’) rompe la cadena e IIS determina que ese fichero debe ser ejecutado como un script ASP, pero a la hora de ejecutarlo, una rutina distinta lee el fichero correcto: ‘maliciousfolder.asp/code.pdf’ y ejecuta el código contenido en él, por lo que un atacante remoto podría ejecutar código ASP en el servidor web desde un fichero pdf o cualquier otro tipo de archivo considerado «seguro» para las aplicaciones de upload de ficheros.

Además, es posible combinar este ataque con el bug CVE-2009-4444, permitiendo a atacantes remotos crear un directorio con una extensión ejecutable seguido de un carácter ‘;’ y a continuación una extensión considerada segura o cualquier otro sufijo, como se demuestra del uso de ASP.dll para manejar cadenas del tipo «.asp;.jpg».

Proof of concept

IIS ejecutará el código ASP contenido en el fichero ‘document.pdf’ al acceder a las siguientes URL. Aquí se describen algunos ejemplos:

http://host/path/folder.asp/document.pdf
http://host/path/user.cer/documents/document.pdf
http://host/path/folder.asa/other/path/document.pdf

http://host/path/folder.asp\document.pdf
http://host/path/folder.cer\document.pdf
http://host/path/folder.asa\document.pdf

En combinación con el CVE-2009-4444 ref #1, la siguiente URL es válida también :

http://host/path/folder.asp;.jpg/document.pdf

En otros casos me he encontrado filtros backlist para el filtrado de extensiones, pero lo que normalmente se trata de transmitir a los desarrolladores es que esos filtros no funcionan, siempre hay una manera de saltarlos, la solución es usar filtros whitelist y el principio de seguridad en profundidad.

Por ejemplo, un caso real fue una aplicación que filtraba las extensiones «peligrosas» tales como «.asa», «.asp», «.php», «.jsp», «.cer» etc etc, pero utilizaba *sólo* los 3 caracteres siguientes después del punto para comprobar si la extensión esta permitida o no. Pues bien, esto se podría bypassear usando NTFS Alternate Data Streams (ADS) gracias al carácter ‘:’  después del nombre de fichero y el stream «$DATA», lo que haría que se creara el fichero ‘file.asp’ con el código que elijamos y lo haría accesible vía el servidor web, por lo que, podríamos ejecutarlo.

Proof of concept: file.asp::$DATA

Incluso usando filtros whitelist existen maneras de saltar ciertas protecciones, como la presentada más arriba, o usando otro tipo de técnicas.

Normalmente los desarrolladores, obtendrán los tres últimos carácteres y compararán con la lista de extensiones seguras (tales como jpg, gif, png, etc). En este caso, usando ADS y el carácter ‘:’ (CVE-2009-4445 ref. #2) podríamos construir una cadena para el nombre del fichero del tipo «filename.asp:.jpg» lo cual haría que la extensión sea válida, ya que jpg estaría en esa lista de extensiones permitidas y podríamos crear ficheros vacíos con extensión asp. Combinando esta vulnerabilidad con otras podríamos llegar a comprometer el servidor.

PoC: file.asp:.jpg -> El fichero file.asp es creado en el DocumentRoot sin contenido.

Junto a estas, existen otras técnicas para tratar de burlar el sistema de protección, pero cada caso hay que estudiarlo por separado. Los componentes de upload de ficheros en aplicaciones web son uno de los elementos más delicados y hay que prestarle mucha atención en todas las etapas del SDLC.

Si no conoces como funcionan los ADS, echale un ojo a  al ref. #3

Impacto

El impacto de esta vulnerabilidad es alto debido a que los atacantes pueden saltar las protecciones ante la gestión de las extensiones de ficheros en 3rd-party webapps subiendo ficheros con cualquier extensión (por ej pdf, txt) a una carpeta acabada en una extensión ejecutable (tal como .asp, .cer, .asa, …).

La librería ASP.dll tiene un comportamiento no esperado manejando este tipo de URLs y podría permitir a atcantes remotos ejecutar código si el directorio tiene permiso de ejecución.

Sistemas afectados

Probado en Microsoft Windows 2003 SP2 up to date con Internet Information Services (IIS) version 6
Nota: un atacante necesita interacturar con una aplicación la cual debe tener permisos de escritura para subir ficheros y ejecución en el servidor web.
Systemas no afectados: Parece que IIS 5.1 sobre Windows XP SP3 devuelve un código 404 cuando se intenta reproducir el PoC, IIS 7.x not tested

La respuesta

La respuesta del MSRC fue una frase que a muchos os sonará: HOYGAN! This is not a bug, it’s a feature!

bug-feature

De todas maneras, me parece importante publicar la descripción técnica ya que puede ser útil en algunos pen-tests/auditorías de seguridad, y de modo similar o más importante para ayudar a los sysadmin a prevenir este tipo de ataques (la solución ante este problema se describe en la última sección de este artículo). Gracias de todos modos al MSRC y a todos los que participaron de una u otra manera en la investigación.

De todos modos, también puede ser argumentado (y fue la conclusión final) que esta vulnerabilidad no es del propio IIS, sino de la 3rd-party webapp, debido a que es su responsabilidad filtrar todo tipo de carácteres malintencionados tanto en los nombres de los ficheros como en los nombres de las carpetas. Y el hecho es que muchas aplicaciones web aplican protecciones de seguridad ante los nombres de los ficheros pero no a los nombres de las carpetas en aquellas apps que trabajan con directorios. Es en este caso es, precisamente,  donde encaja este estudio.

El porqué

Ahora voy a explicar los detalles técnicos:

Cuando una nueva petición llega a IIS, éste calcula con que módulo se procesará, parseando la URL de izquierda a derecha y buscando extensiones válidas en cada segmento.

Cuando una extensión es encontrada, en primer lugar se compara con una lista de extensiones ejecutables (.exe, .com, .dll e .isa). Si ésta es .exe o .com IIS pasa el control a CGI o a ISAPI, en caso de ser .dll o .isa. De la misma manera, también compara dicha extensión contra la lista configurada de extensiones de script (por defecto esta lista contendrá: .asp, .cer, .asa, etc). Si alguna de estas extensiones coincide se pasará el control al motor de script asociado con la extensión en cuestión.

La cadena que se encuentre después de una extensión válida y antes del carácter ‘?’ será considerado la variable PATH_INFO según la especificación CGI, (la cadena después del carácter ‘?’ es la query string)

Pero, qué es PATH_INFO?

Como se puede leer en #4:

The extra path information, as given by the client. In other words, scripts can be accessed by their virtual pathname, followed by extra information at the end of this path. The extra information is sent as PATH_INFO. This information should be decoded by the server if it comes from a URL before it is passed to the CGI script.

Por lo tanto es la información extra al final del nombre de ruta virtual (donde el nombre de ruta virtual es la URL). Pero el problema es que ASP maneja de forma no standard tanto la variable PATH_INFO como la variable PATH_TRANSLATED a la hora de buscar el fichero de script a ejecutar. ASP asume que la variable PATH_TRANSLATED contendrá el path físico completo al fichero de script.

Para el correcto funcionamiento de ASP, PATH_INFO debe ser la URL, ya que el mapeo de la URL a un path físico conducirá a la página ASP. Pero, de acuerdo con la especificación de CGI 1.3 #ref 4, PATH_INFO no está definido como una URL.

IIS tiene un switch de configuración que controla cuando los motores de script ven la URL o la información definida por CGI en la variable del servidor PATH_INFO. Este switch de configuración se llama AllowPathInfoForScriptMappings y podeis encontrar más información en ref #5


Debemos considerar los dos valores de configuración posible para la variable AllowPathInfoForScriptMappings, en ambos casos podemos reproducir el PoC:

AllowPathInfoForScriptMappings=FALSE (Por defecto)

En esta situación la URL será asignada a la variable PATH_INFO, por lo que la variable PATH_TRANSLATED contendrá el path físico completo a la URL.

Pongamos de ejemplo de URL “http://host/path/folder.asp/file.txt”, veamos como quedaría:

  1. URL: http://host/path/folder.asp/file.txt
  2. PATH_INFO: /path/folder.asp/file.txt
  3. PATH_TRANSLATE: c:\inetpub\wwwroot\path\folder.asp\file.txt

Ya que la extensión encontrada ‘.asp’ está asignada para ser procesada por un script, la petición será gestionada por asp.dll, la cual intentará abrir la ruta final (#3). Si este fichero existe, ASP lo procesará como un script ASP y enviará la salida al cliente. Para que el PoC funcione, el fichero “file.txt” debe existir en el directorio “folder.asp”. Este es el caso comentado más arriba.


AllowPathInfoForScriptMappings=TRUE

En este caso, veamos como queda:

  1. URL: http://host/path/folder.asp/file.txt
  2. PATH_INFO: /file.txt
  3. PATH_TRANSLATE: c:\inetpub\wwwroot\file.txt

Usando el mismo ejemplo,  y teniendo en cuenta que la extensión encontrada es también .asp, la petición será gestionada por asp.dll.

ASP abrirá el fichero “c:\inetpub\wwwroot\file.txt” (#3) y lo procesará como un script ASP. En este caso el sysadmin ha debido cambiar el valor de AllowPathInfoForScriptMappings manualmente, por lo que considero el ataque mucho más complicado.

Hay que tener en cuenta que configurar AllowPathInfoForScriptMappings al valor TRUE, romperá el funcionamiento normal de ASP. Considerando una petición “normal” de ASP como “http://host/path/file.asp”, significaría que la variable PATH_INFO sería una cadena vacía (puesto que no hay nada después de la URL) y PATH_TRANSLATED valdría “c:\inetpub\wwwroot\” sin ningún fichero. Lo que significa que las peticiones normales de ASP no funcionarían y es muy poco probable que un administrador de sistemas quiera servir ASP con esta configuración.

La solución

La solución va enfocada a dos roles diferentes:

Sysadmins: Eliminar el permiso de ejecución en los directorios donde se permita subir ficheros. Seguir la guía de mejores prácticas de seguridad para IIS 6 (Ref #6)

Developers: No confiar en la entrada proporcionada por el usuario y *nunca* usarla como nombre de fichero. Generar un nombre de fichero aleatorio y almacenar el nombre real en un lugar distinto (por ej, una base de datos). A ser posible setear la extensión por la propia aplicación, con claúsulas switch-case por ejemplo. Sólo aceptar cadenas alphanuméricas para la extensión y nombre de fichero.

Referencias

  1. CVE-2009-4444 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4444
  2. CVE-2009-4445 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-4445
  3. Alternate Data Streams (ADS) http://es.wikipedia.org/wiki/Alternate_Data_Streams
  4. CGI 1.3 specification http://web.bilkent.edu.tr/WWW/hoohoo/cgi/env.html
  5. AllowPathInfoForScriptMappings http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/b9368427-8c20-42fb-af4e-85c4b7ff3b49.mspx?mfr=true
  6. IIS 6.0 Security Best Practices (IIS 6.0) http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/596cdf5a-c852-4b79-b55a-708e5283ced5.mspx?mfr=true
  7. File system http://www.owasp.org/index.php/File_System
  8. Unrestricted File Upload http://www.owasp.org/index.php/Unrestricted_File_Upload
  9. IIS semicolon report http://soroush.secproject.com/downloadable/iis-semicolon-report.pdf

CVE-2009-4444

5 Comentarios para “IIS6/ASP & file upload for fun and profit”

  1. Comment por Juan Galiana | 09/28/10 at 6:06 pm

    El estudio se realizó con componentes propietarios, pero básicamente el componente en cuestión debe permitir crear carpetas y subir ficheros, para reproducirlo la forma más sencilla es:

    1) Crear un directorio con nombre «dir.asp» en el DocumentRoot
    2) Subir un fichero a ese directorio con cualquier extensión con código ASP (por ej file.pdf)
    3) Acceder desde el navegador a la URL http://host/dir.asp/file.pdf y el código de script será ejecutado.

    *Nota*: El directorio debe tener permisos de ejecución para scripts ASP (lo que se está bypasseando aqui es el sistema de upload de ficheros, que normalmente aplica las protecciones *sólo* a los nombres de los ficheros y no de los directorios, ya que estamos subiendo un fichero con extension válida ´pdf´, sin embargo se está ejecutando debido al nombre del directorio acabado en «.asp».)

  2. Comment por Tyler | 10/03/10 at 11:56 am

    Muy instructivo.

    Gracias por tu tiempo y conocimientos empleados en el post.

  3. Comment por Ruben | 10/08/10 at 3:32 pm

    Skooooooooooooooooooooooooooooooooooool.
    Hola.
    Esta guachi.

  4. Comment por sha0 | 10/13/10 at 1:22 pm

    Que tal Juan?, que gran artículo!! veo que sigues en tu línea.
    juass eso si que es una fea-ture 🙂

    La combinación de vulnerabilidades es algo que muchos auditores no hacen y es crucial hoy dia para ganar acceso, combo roolz.

    nos vemos en la lacon.

  5. Comment por Mario Díaz | 10/19/10 at 11:41 am

    Muy grande Juan!! 😀 esto me facilitará mucho la faena en los TI 😉

Se han cerrado los comentarios