lunes, 22 de noviembre de 2010

SQLMap, SQL Server & Hyphens

Hace algún tiempo me encontré con una situación interesante mientras auditaba una aplicación web conectada a un servidor de base de datos Microsoft SQL Server que provocaba que ninguna de las herramientas que utilizo habitualmente para la explotación de Blind SQL Injection funcionara correctamente.

La aplicación web presentaba una vulnerabilidad de Inyección SQL en uno de sus parámetros. Evidentemente no puedo mostrar la aplicación real que contenía el fallo, pero pongamos que la aplicación tenía un código como el siguiente:


Evidentemente, la aplicación es vulnerable a Inyección SQL, y ni siquiera Inyección SQL Ciega, pero vamos a usarlo como ejemplo.

Si lanzamos la herramienta SQLMap para la detección y explotación del parámetro "id", obtenemos lo siguiente:

# ./sqlmap.py -u "http://172.16.24.151/?id=1" -p id


Perfecto! SQLMap detecta correctamente que el parámetro "id" es vulnerable, y nos muestra el fingerprint del servidor de base de datos. Ahora, como un posible segundo paso, veríamos las bases de datos contenidas en el servidor:

# ./sqlmap.py -u "http://172.16.24.151/?id=1" -p id --dbs


Cuando llegué a este punto en la auditoría, intenté ir accediendo a la información contenida en las bases de datos, pero cuando le tocó a "test-db" me encontré con algo así:

# ./sqlmap.py -u "http://172.16.24.151/?id=1" -p id -D "test-db" --tables


Parece que por algún motivo no puedo recuperar las tablas de la base de datos. No hubo manera de hacerlo funciona cambiando las opciones, ni tampoco era por un tema de permisos, puesto que era la base de datos utilizada por la aplicación web. Probé otras herramientas y nada, todas me devolvían el mismo resultado.

Al final, lancé SQLMap con la opción "-v 2", para así poder ver con algo más de detalle que estaba pasando, y obtuve lo siguiente:

# ./sqlmap.py -u "http://172.16.24.151/?id=1" -p id -D "test-db" --tables -v 2


La SQL, a mis ojos, parecía correcta, pero por si acaso me la llevé a una maqueta de Microsoft SQL Server y la lancé, con lo que obtuve un "bonito" error de sintaxis:


"Sintaxis incorrecta cerca de -", y el único "-" que hay en la SQL es el del nombre de la base de datos, así que... no puede ser que el guión (hyphen) sea un carácter no permitido para nombres de tablas en Microsoft SQL Server, porque de hecho la tabla existe, pero parece tratarse de algún tipo de carácter especial en SQL que deberá ser escapado de alguna manera.

Revisando la documentación del SQL Server y referencias varias en Internet, me encontré con que es posible definir el nombre de una tabla entre corchetes, y que eso podría evitar que ese guión fuera interpretado como lenguaje SQL. Veamos que pasa si cambiamos la SQL anterior incluyendo esos corchetes:


Bueno, parece que SÍ que era ese el problema, así que solo necesitamos decirle a SQLMap que el nombre de nuestra base de datos es "[test-db]" en lugar de "test-db" para poder seguir extrayendo la información.

Tras extraer el nombre de las tablas (opción --tables), vemos una llamada "usuarios", así que aprovechamos lo que acabamos de aprender para obtener todo el contenido de la tabla:

# ./sqlmap.py -u "http://172.16.24.151/?id=1" -p id -D "[test-db]" -T usuarios --dump


Hay otra manera de corregir este problema para que no nos vuelva a suceder ni ahora ni nunca, independientemente del nombre que tengan las bases de datos. SQLMap contiene las sentencias SQL dentro de un fichero llamado queries.xml (en el directorio "xml" del sqlmap), con lo que podemos realizar pequeñas (o grandes si nos atrevemos) modificaciones sobre ellas, entre las cuales podemos incluir corchetes en las referencias a nombre de tablas, que serán del tipo %s..loquesea, y que tras la modificación pasarán a ser [%s]..loquesea, o de tipo [DB]..loquesea que pasará a ser [[DB]]..loquesea, solo para la zona de sentencias para SQL Server, por supuesto:


Una vez hecho esto podemos lanzar la herramienta de una forma totalmente normal, y no volveremos a encontrarnos este problema.

Cualquiera de las dos formas nos vale para solucionar nuestro problemilla, aunque a mi me gusta más la segunda. No será la primera vez que toca modificar algo en el código de sqlmap para adaptarlo alguna situación concreta, como por ejemplo WAFs que filtran algunas palabras y que fastidian un poco.

Pero eso ya para otro post.

9 comentarios :

fossie dijo...

Lo de los corchetes para nombrar los nombres de las bases de datos, tablas, columnas, etc, es algo bastante común cuando se trabaja con SQL.

También hay que tener en cuenta que, en ocasiones hay que especificar la intercalación COLLATE ya que no siempre nos deja utilizar varchar tal cual si estamos utilizando un campo que tiene una intercalación, por ejemplo, UTF o Modern Spanish.

SQLMap facilita mucho el "trabajo" pero, por desgracia, también nos hacen olvidar el funcionamiento interno de las cosas, es por eso que sigo prefiriendo hacerlo "a mano". Es mucho más lento pero más educativo.

Al dijo...

Muy importante lo de tener una maqueta de las BBDD para poder afinar las pruebas. Muchas veces es la diferencia entre sólo detectar un problema y poderlo explotar en condiciones.

Muy buen artículo, como ya nos tenéis acostumbrados.

Jose Selvi dijo...

Gracias a los dos por vuestros comentarios :)

@fossie: No soy un gran experto en bases de datos, más bien cuando algo no me funciona (por ejemplo, un filtro me borra algunos caracteres o palabras) tiro de manual y utilizo una maqueta de la misma base de datos para intentar obtener el mismo dato sin utilizar las "palabras prohibidas" (como si jugara el Taboo ;P)

Sin duda, la gente se olvida de que hay por debajo de la herramienta, y cuando esta falla (algo bastante habitual) ya no saben que hacer. Hacerlo a mano... como tú dices es más educativo, pero cuesta mucho más tiempo, y en un Pentest profesional... el tiempo es oro, porque suele ser muy limitado, así que sería imposible sacar una tabla de usuarios y contraseñas a mano con una Inyección SQL Ciega.

@Al: Yo uso mis maquetas de base de datos para probar las sentencias a ver si funcionan antes de probarla en explotación, más que nada porque si lo hago directamente y no funciona no sabré si es la base de datos, algún símbolo/palabra... ni idea, vamos. Si sé que la sintaxis que he usado es correcta y aún así no funciona, entonces es que me están filtrando algo de lo que estoy usando.

Para temas de explotación de vulnerabilidades más "peligrosas" como corrupciones de memoria... imprescindible hacerlo antes en maqueta, si es posible.

fossie dijo...

@Jose Selvi
Yo tampoco soy un experto en bases de datos jeje, que más quisiera yo!! :D

Es cierto que para un Pentest profesional el tiempo es oro y no suele dar tiempo a hacerlo a mano. No discuto que estas herramientas son muy útiles, solo comentaba que, en mi caso (que no soy profesional de seguridad ni nada) me gusta trastear a mano porque me parece más educativo. Es una forma más de aprender y al final las herramientas te pueden fallar por casos que realmente tienen solución (como tu has visto) pero que si no sabes trastear un poco no podrías resolverlo.

Felizmente existen los manuales y, sobre todo, la curiosidad. Eso es lo divertido. Al final siempre nos pica el gusanillo de trastear un poquito :D

Y... gracias por tu blog!

Jose Selvi dijo...

@fossie: Totalmente de acuerdo! :)

Gracias a ti por tus comentarios.
Saludos!

Edgar Carrillo Egea dijo...

Buenisimo tu artículo, como todos. Sencillos y muy bien explicados.
Me he pasado un poco tarde (ando en muchos lios, ya te contaré), pero bueno mas vale tarde que nunca.
Un saludo!!!

Anónimo dijo...

Lo que no entiendo es por qué SQLmap a la hora de mostrarte las bbdd no mostró los corchetes :S, no debería haberlos mostrado?

Jose Selvi dijo...

@Anónimo: Porque en realidad, el nombre de la base de datos no lleva corchetes.

Lo que ocurre es algo parecido a cuando queremos escribir una cadena de texto como parámetros por linea de comandos, que si utilizamos el caracteres espacio, como tiene un significado especial (separar parámetros) tenemos que, o bien escaparlo de alguna forma, o bien poner la cadena entre comillas, para señalar que todo lo que hay dentro es literal, y no hay que interpretar nada.

En este caso, para SQL, los corchetes actúan como esas comillas de las que te hablo, las usamos para señalar que el nombre de la base de datos es literal, y que no hay que hacer ninguna interpretación del carácter - ni ningún otro.

No sé si resuelvo tu duda, pero si no es así házmelo saber y te lo intentaré explicar de otra forma.

Gracias por el comentario!
Saludos!

Anónimo dijo...

Muchas gracias Jose, Perfectamente entendido ahora. :D

Un saludo