cd ~/blog

~/vulns/blind-sqli-time-based.md

Time-Based Blind SQL Injection

webautor: Jordy Pérez Osorio aviso legal
SQL-InjectionTime-Based-Blind-SQL-Injection

~3 min de lectura


1. Descripción técnica

Time-Based Blind SQL Injection es una variante de SQL Injection en la cual la aplicación no devuelve el resultado de la consulta ni un error útil, pero una entrada controlada todavía modifica la sentencia SQL.
El atacante explota la vulnerabilidad provocando retrasos medibles en la respuesta del servidor mediante funciones como SLEEP() en MySQL o pg_sleep() en PostgreSQL.

De esta forma, si una condición es verdadera, la consulta se ralentiza artificialmente; si es falsa, responde al instante.
Esto permite reconstruir, carácter por carácter, información de la base de datos.

Ejemplo de payload time-based:

' AND IF(SUBSTRING(DATABASE(),1,1)='t', SLEEP(2), 0) -- -
  • Si el primer carácter del nombre de la base es t, el servidor tardará 2 segundos más en responder.

  • Si no lo es, la respuesta será inmediata.

Repitiendo el proceso, el atacante puede extraer todo el nombre de la base, tablas, columnas y finalmente registros sensibles.

2. Impacto

Con una Blind SQLi Time-Based, el atacante puede llegar a:

  • Descubrir la base de datos activa con consultas del tipo DATABASE().

  • Enumerar tablas y columnas de information_schema.

  • Volcar datos sensibles (usuarios, contraseñas, correos, tokens).

  • Comprometer toda la aplicación, especialmente si las credenciales permiten privilegios de administrador.

Aunque es más lenta que otras variantes de SQL Injection, la automatización permite reconstruir información de forma sistemática. La gravedad real depende de los permisos de la cuenta de base de datos y de los datos accesibles desde la consulta vulnerable.

3. Condiciones necesarias

  1. Una entrada no confiable se concatena o incorpora de forma insegura a una consulta SQL.
  2. El motor admite una operación que produce un retraso observable, como SLEEP(), pg_sleep() o WAITFOR DELAY.
  3. La aplicación espera la finalización de la consulta antes de responder.
  4. La latencia permite distinguir una condición verdadera de una falsa mediante varias mediciones.

4. Explotación documentada en los writeups

4.1. 080-talk

El writeup utiliza un script que prueba cada carácter y decide si coincide a partir del tiempo de respuesta.

Estrategia del script

  1. Definición de caracteres válidos:
    string.ascii_letters + string.digits + "_@.-:$"

posibles caracteres del nombre de tablas/columnas/datos.

  1. Payload genérico con SLEEP():
    1' AND (SELECT IF(SUBSTRING((consulta),{pos},1)='{char}', SLEEP(0.5), 0)) -- -
  • Cambia {pos} por la posición del carácter.

  • Cambia {char} por cada posible carácter hasta encontrar el correcto.

  1. Extracción paso a paso:

    • Primero el nombre de la base de datos (DATABASE()).
    • Luego tablas de information_schema.tables.
    • Luego columnas de cada tabla.
    • Finalmente, concatenación de campos sensibles como username:password.
  2. Medición del tiempo de respuesta:
    Si la respuesta tarda más del umbral (ej. 0.4s), el carácter probado es correcto.

Ejemplo de salida del script

[*] Extrayendo nombre de base de datos...
[+] db_name: secure_app
[*] Extrayendo nombres de tablas...
  [+] Tabla 1 -> users
  [+] Tabla 2 -> messages
[*] Extrayendo columnas de `users`...
  [+] Columna 1 -> username
  [+] Columna 2 -> password
[*] Extrayendo registros de `users`...
  [+] Registro 1 -> admin:5f4dcc3b5aa765d61d8327deb882cf99

Esto muestra cómo, aunque no hay errores SQL ni respuestas visibles, es posible reconstruir todo el esquema y los datos sensibles.

5. Validación y detección

  • Manual:
    Probar payloads como:
    1' AND IF(1=1, SLEEP(2), 0) -- - 1' AND IF(1=2, SLEEP(2), 0) -- -

Si la primera consulta presenta un retraso repetible respecto de la segunda, existe evidencia de un canal temporal. Una medición aislada no basta, porque la carga del servidor y la red también producen variaciones.

  • Automatizada:
    Herramientas como:
    • sqlmap (--technique=T)
    • BurpSuite (con Intruder + payloads de tiempo)
    • Scripts personalizados en Python.

6. Mitigación

  1. Consultas parametrizadas (prepared statements).
    Evitan la concatenación de cadenas con entrada del usuario.

  2. Validación estricta de entrada.
    Ejemplo: si id debe ser numérico, asegurarse que solo acepte enteros.

  3. Principio de privilegios mínimos.
    La aplicación no debería conectarse como root a la base.

  4. Uso de WAF para filtrar patrones como SLEEP(), pg_sleep(), WAITFOR DELAY.

  5. Errores genéricos.
    No mostrar trazas SQL ni información sensible.

7. Clasificación

  • Tipo: Blind Injection (Time-Based)

  • OWASP Top 10: A03:2021 Injection

  • CWE:

    • CWE-89: Improper Neutralization of Special Elements used in an SQL Command

8. Referencias y conexiones

// relacionados