SQL注入之宽字节注入学习笔记 📅 2026/8/15 11:30:27 一、什么是宽字节注入宽字节注入是SQL注入中比较特殊的一种类型其核心逻辑与之前学的所有注入都不同。前面几种注入联合查询、报错注入、布尔盲注、时间盲注、堆叠查询本质上都是利用开发者的代码逻辑缺陷而宽字节注入利用的是数据库和程序对字符编码的处理差异。简单来说当数据库使用GBK、GB2312、SJIS等多字节字符集时程序在处理用户输入时可能会错误地将两个字节识别为一个汉字字符导致原本应该被转义的特殊字符如单引号没有被正确转义从而造成注入。宽字节注入的适用场景宽字节注入在以下场景中有效目标网站使用GBK、GB2312、SJIS等宽字节字符集编码网站开启了转义功能如 addslashes()、magic_quotes_gpc对单引号等特殊字符进行了转义转义函数对宽字节字符处理不完善导致转义被绕过数据库连接字符集与页面字符集不一致宽字节注入的核心要素宽字节注入需要满足以下几个条件目标网站使用宽字节字符集编码输入的单引号等特殊字符被反斜杠转义如 ’ 变成 转义后的反斜杠可以被宽字节字符“吃掉”从而失效二、宽字节注入的基本原理1 , 单字节字符集与多字节字符集在理解宽字节注入之前需要先了解字符集的概念。单字节字符集如ASCII、Latin1 每个字符使用1个字节表示。例如英文字母 A 的ASCII码是65用一个字节即可表示。多字节字符集如GBK、GB2312、SJIS、UTF-8 每个字符可能使用1个、2个或更多字节表示。例如在GBK编码中英文字母仍用1个字节而中文字符使用2个字节。2 . 转义函数的工作原理在PHP中addslashes() 函数会在特殊字符前添加反斜杠进行转义’ 变成 ’ 变成 \ 变成 \空字符变成 \0这样做的目的是让特殊字符失去原有的SQL语法意义变成普通的字符串内容。例如用户输入 ’ OR 11 – 经过 addslashes() 处理后变成 ’ OR 11 – 单引号被转义无法闭合原有的SQL语句注入失效。3 . 宽字节“吃掉”反斜杠的原理在GBK编码中中文字符由两个字节组成第一个字节的范围是 0x81-0xFE第二个字节的范围是 0x40-0xFE。反斜杠 \ 的十六进制编码是 0x5C。当攻击者输入一个十六进制为 0xDF 的字符GBK中的“運”字的第一个字节加上单引号时用户输入%df%27addslashes() 处理后%df%5c%27单引号被转义为 %5c%27在数据库中使用GBK编码解析时%df%5c 被识别为一个GBK中文字符“連”字而 %27 单独出现反斜杠 %5c 被前面的 %df “吃掉”了单引号 %27 没有被转义成功逃逸出来造成了注入漏洞。更准确地说%df 不是一个完整的中文字符而是与 %5c 共同构成一个合法的GBK双字节字符因此 %5c 失去了转义的作用。三、宽字节注入的利用步骤第一步判断是否存在宽字节注入首先测试目标是否使用宽字节编码以及是否存在宽字节注入漏洞。正常输入nameadmin测试输入带单引号nameadmin如果页面报错说明单引号被带入SQL语句执行了可能存在注入。测试输入宽字节单引号nameadmin%df如果页面行为与普通单引号测试不同如报错信息不同或原本被过滤的现在有效了说明宽字节注入可能存在。第二步获取数据库信息确认存在宽字节注入后使用类似联合查询注入的方式获取数据。但由于宽字节注入的Payload需要额外的编码处理构造方式稍有不同。获取当前数据库名nameadmin%df union select 1, database() --获取所有数据库名nameadmin%df union select 1, group_concat(schema_name) from information_schema.schemata --第三步获取表名和列名获取当前数据库的表名nameadmin%df union select 1, group_concat(table_name) from information_schema.tables where table_schemadatabase() --获取指定表的列名nameadmin%df union select 1, group_concat(column_name) from information_schema.columns where table_nameusers --第四步获取具体数据获取users表中的用户名和密码nameadmin%df union select 1, group_concat(username, :, password) from users --四、不同编码环境下的宽字节注入1 . GBK编码环境GBK是最常见的宽字节注入场景因为GBK的编码范围广容易与反斜杠形成合法的双字节字符。常用Payload前缀· %df最常用与 %5c 组合成GBK中文字符· %e5%也可以与 %5c 组合· %81GBK编码范围内的字节2 . GB2312编码环境GB2312是GBK的子集编码范围比GBK小但仍然存在宽字节注入的可能。常用Payload前缀%d5在GB2312范围内与 %5c 组合成合法字符%b0同样在GB2312范围内3 . SJIS编码环境日文SJISShift-JIS是日文编码同样存在宽字节注入问题。常用Payload前缀· %81、%82、%83 等SJIS编码范围内的字节4 . UTF-8编码环境UTF-8虽然是多字节编码但它的编码规则与GBK不同。UTF-8中的多字节字符有固定的格式第一个字节的格式决定了后续字节的数量反斜杠 0x5C 无法与前面的字节组合成一个合法的UTF-8字符。因此在UTF-8编码环境下传统的宽字节注入方式基本不适用。但是在某些特殊情况下如果程序使用了不正确的编码转换如先以GBK解码再以UTF-8编码仍然可能出现宽字节注入问题。五、宽字节注入的防御措施防御宽字节注入的核心思路是统一字符集编码和正确使用参数化查询。最根本的防御措施统一字符集编码确保页面编码、数据库连接编码、数据库存储编码一致在数据库连接后执行 SET NAMES ‘utf8’ 或 SET character_set_client ‘utf8’使用参数化查询PreparedStatement替代动态SQL拼接从根本上杜绝注入具体防御方案设置数据库连接字符集为UTF-8避免使用GBK等宽字节编码在PHP中使用 mysql_set_charset(‘utf8’) 或 mysqli_set_charset(‘utf8’) 而非 SET NAMES因为 SET NAMES 在某些版本中仍然存在宽字节绕过问题在Java中使用 PreparedStatement 进行参数化查询并确保数据库连接URL中指定了正确的字符集如 useUnicodetruecharacterEncodingUTF-8在输入过滤层面使用专门的转义函数或过滤库而非简单的 addslashes()靶场实例SQLi-Labs靶场Less-32、Less-33SQLi-Labs的Less-32和Less-33关也涉及到了宽字节注入。环境搭建从GitHub下载SQLi-Labs源码使用PHPStudy或XAMPP搭建确保数据库连接字符集设置为GBK。漏洞利用过程当输入 id1’ 时单引号被转义为’注入无效。加上 %df 后输入 id1%df’由于%df与%5c组合成汉字单引号成功逃逸。探测字段数1%df order by 3%23获取数据库名-1%df union select 1,database(),3%23获取表名需要使用十六进制编码绕过单引号转义-1%df union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()%23