Como ya comentaba hace unos días, la conocida web de CINESA tenia ciertas vulnerabilidades que podian poner en peligro a los usuarios que accedian a ella. Finalmente, después de casi un mes he conseguido conversar con los responsables de la web para que pudieran solucionar las incidencias.
La web esta desarrollada en ASP.NET (utilizando C# bajo el Framework 2.0) con acceso a un servidor de datos SQL Server 2005 todo ello corriendo en Windows NT 5.2 ¿como se podia averiguar todo esto? Vamos a verlo:
Saber que la web está desarrollada en ASP.NET no es dificil ya que sus páginas tienen extensión .aspx, por ejemplo http://www.cinesa.es/cines/cines2.aspx?id=631 pero si queremos tener confirmación sobre esto basta con producir un error en la página, por ejemplo, cambiando el código del parámetro id por algún valor no válido o, simplemente, abriendo esa página sin indicar ningún valor para el parámetro, es decir http://www.cinesa.es/cines/cines2.aspx?id=
Este mensaje de error nunca debería mostrarse en un entorno de producción pero al parecer la aplicación tenia habilitado el modo debug lo que hace que se mostrasen mensajes de error bastante detallados. Concretamente en este, nos da información sobre el lenguaje utilizado (la extensión .cs corresponde a C Sharp) y se indica claramente que se utiliza ASP.NET y Framework 2.0. Además también muestra la ruta completa del archivo (d:\WebCinesa\Production\cines\cines2.aspx.cs) lo que, posteriormente, veremos que podia ser utilizado para visualizar su contenido.
Para saber que la base de datos utilizada es SQL Server 2005 podiamos acceder a la página de promociones que era vulnerable a inyección sql y preguntarselo directamente utilizando la función @@version. Pero antes vamos a ver como se podía forzar dicha inyección sql en la página http://www.cinesa.es/promociones/landing.aspx?promo=66. Esta página muestra una imagen donde se encuentra la promoción junto con un link asociado a la misma, es de suponer que tanto la ruta de la imagen y el link se obtienen desde base de datos en función del código de la promoción (66) por lo que podemos intentar un UNION para devolver la ruta y el link que deseemos.
Si accediamos a la URL http://www.cinesa.es/promociones/landing.aspx?promo=66 union select 1 se mostraba un mensaje de error que decia "Todas las consultas combinadas que usan un operador UNION, INTERSECT o EXCEPT deben tener el mismo número de expresiones en sus listas de destino." lo que nos confirma que la inyección sql era efectiva y que estabamos en el "buen" camino así que solo quedaba ir añadiendo campos hasta que la consulta resultante fuera válida.
Al llegar a la URL http://www.cinesa.es/promociones/landing.aspx?promo=66 union select 1,2,3,4,5,6,7,8,9,10,11 el mensaje de error cambiaba y mostraba lo siguiente: "Conflicto de tipos de operandos: text es incompatible con int", esto se debia a que los campos que intentabamos añadir a la consulta eran del tipo int pero la consulta original esperaba un campo de tipo text. Como no sabemos que campo es el que nos esta mostrando el error lo mejor seria convertirlos todos en text, para lo cual simplemente se les añaden unas comillas simples quedando la siguiente URL http://www.cinesa.es/promociones/landing.aspx?promo=66 union select '1','2','3','4','5','6','7','8','9','10','11' pero nuevamente se obtenia un mensaje de error, en esta ocasión decia: "El tipo de datos text no se puede seleccionar como DISTINCT porque no es comparable.". Parece ser que la consulta original utilizaba DISTINCT para seleccionar dos registros y no es posible hacer un DISTINCT en campos de tipo text pero esto se soluciona facilmente utilizando UNION ALL en lugar de UNION, es decir, http://www.cinesa.es/promociones/landing.aspx?promo=66 union all select '1','2','3','4','5','6','7','8','9','10','11'.
Como veis poco a poco se van solventando los distintos errores que van apareciendo pero aún nos quedan unos pocos más hasta conseguir nuestro objetivo. Ahora tenemos en pantalla el mensaje: "Error de conversión al convertir una cadena de caracteres a datetime." lo que quiere decir que alguno de los campos debe ser de tipo datetime y nuevamente no sabemos cual es asi que en lugar de escribir los valores 1,2,3... introduciremos valores que sean representables como datetime, por ejemplo 20100801,20100802,..., quedando la URL de la siguiente forma: http://www.cinesa.es/promociones/landing.aspx?promo=66 union all select '20100801', '20100802', '20100803', '20100804', '20100805', '20100806', '20100807', '20100808', '20100809', '20100810', '20100811' y, ¡sorpresa!, la página de la promoción se mostraba sin ningún error.
Ahora ya tenemos nuestra consulta en ejecución sin errores pero si quisieramos saber que campos son los campos datetime se podian volver a poner los valores 1,2,3... en lugar de las fechas introducidas. Este cambio habria que hacerlo campo a campo para ver cual de ellos nos devuelve la página sin errores y cual nos muestra un error. Al final vemos que solo hay dos campos de tipo datetime, concretamente el tercero y el cuarto lo que me hace pensar en el típico par de fechas "desde/hasta", algo así como la validez de la promoción así que pondremos un rango de fechas válido, por ejemplo 20100803 y 20990804 quedando la URL: http://www.cinesa.es/promociones/landing.aspx?promo=66 union all select '1','2','20100803','20110804','5','6','7','8','9','10','11' y para que en lugar de mostrarse la promoción 66 se mostrasen los datos de nuestra consulta inyectada solo hay que indicar un código de promoción inexistente, por ejemplo, -66, es decir, http://www.cinesa.es/promociones/landing.aspx?promo=-66 union all select '1','2','20100803','20110804','5','6','7','8','9','10','11' lo que mostraba la siguiente página:
En esta página podemos ver que se intentaba mostrar una imagen y que dicha imagen tenia un enlace asociado. Accediendo al código fuente de la página se ve que la imagen que se intentaba mostrar es "/promociones/manager/1/911" y el enlace apuntaba a "7" lo que da que pensar que los campos utilizados para montar la url de la imagen son el campo 1, 9 y 11 mientras que el enlace es el campo 7.
Si haciamos la prueba y sustituiamos nuestro campo '7' por 'http://www.google.es', es decir: http://www.cinesa.es/promociones/landing.aspx?promo=-66 union all select '1','2','20100803','20110804','5','6','http://www.google.es','8','9','10','11'.
Podiamos ver que, efectivamente, la url del enlace mostraba el link a Google con lo que quedaba confirmado que la inyección sql se realizaba correctamente y es en este momento cuando se podia acceder a la base de datos tal y como se decia ateriormente, por ejemplo, para obtener la versión de la misma. En lugar de poner el link a Google simplemente se podría poner la sentencia sql que devuelve la versión de la base de datos @@version, quedando la url de la página así: http://www.cinesa.es/promociones/landing.aspx?promo=-66 union all select '1','2','20100803','20110804','5','6',@@version,'8','9','10','11'
Se puede apreciar que el enlace al que apunta la imagen contenia el texto "Microsoft SQL Server 2005" pero para verlo más comodamente podemos acceder al código fuente de la página.
Una vez hecho esto ya tenemos toda la información que os daba al comienzo de este post pero evidentemente se podía tener acceso a mucha más información, como por ejemplo, a la lista de tablas existentes en el servidor (y a sus datos).
Full Path Disclosure
Al principio comentaba que en uno de los mensajes de error se mostraba la ruta completa de una de las páginas (Full Path Disclosure), concretamente el error se producia en la página cines2.aspx y se mostraba la ruta d:\WebCinesa\Production\cines\cines2.aspx.cs. Esto supone dos problemas, el primero es que no se deberia mostrar la ruta y el segundo es que se hace referencia al archivo cines2.aspx.cs en lugar de a cines2.aspx lo cual me hace pensar que el archivo cines2.aspx.cs también se encuentra accesible. Los archivos con extensión .cs son archivos con el código fuente y realmente no son necesarios una vez compilada la aplicación pero parece que también los han subido a producción.
Si intentamos acceder al archivo cines2.aspx.cs desde el explorador (http://www.cinesa.es/cines/cines2.aspx.cs) obtenemos un mensaje de error debido a que el FrameWork bloquea el acceso a los archivos de código fuente (por seguridad)
Pero gracias a la inyección SQL se podia leer el archivo cines2.aspx.cs línea a línea. Por ejemplo, podíamos utilizar la instrucción BULK INSERT de SQL indicando la ruta completa del archivo para cargarlo en una tabla temporal de SQL y luego mostrar el contenido de dicha tabla utilizando la SELECT que vimos anteriormente mostrandose de la siguiente forma:
O bien visualizarlo directamente utilizando xp_cmdshell para copiarlo con una extensión que el FrameWork no bloquee.
Además, con xp_cmdshell teníamos una shell completa en el servidor por lo que era posible incluso examinar los directorios y archivos que no son accesibles desde el servidor web.
En fin que visto lo visto no era dificil acceder al servidor de CINESA y a sus datos con lo que no solo se ponia en peligro la web sino también a los usuarios registrados ya que es posible acceder a información confidencial.
Fecha de comunicación del problema: 06/08/2010
Fecha de resolución: 30/08/2010
No hay comentarios:
Publicar un comentario