0x01 原理

  • 单字节字符集: 所有的字符都使用一个字节来表示,比如 ASCII 编码。

  • 多字节字符集: 在多字节字符集中,一部分字节用多个字节来表示,另一部分(可能没有)用单个字节来表示。

  • 两位的多字节字符有一个前导字节和尾字节。 在某个多字节字符集内,前导字节位于某个特定范围内,尾字节也一样。

  • UTF-8 编码: 是一种编码的编码方式(多字节编码),它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

  • 常见的宽字节: GB2312、GBK、GB18030、BIG5、Shift_JIS GB2312 而转义符 \ 及 %5c 和 其他字节 比如 %df 就可以构成一个汉字

0x02 条件

当前端为utf-8 ,数据库设置GBK(或者其他多字节字符集)

由于 传入参数需要转码操作 就会使 %df%5c 看成一个汉字

0x03 演示

http://localhost/sqlilabs/Less-32/?id=-1%df%27 union select 1,group_concat(username) ,group_concat(password)   from security.users--+

0x04 防止

  • 就是先调用mysql_set_charset设置当前字符集为gbk,再调用函数mysql_real_escape_string来过滤用户输入。

  • 还可以把character_set_client设置为binary二进制 ,当我们的mysql接受到客户端的数据后,会认为他的编码是character_set_client,然后会将之将换成character_set_connection的编码,然后进入具体表和字段后,再转换成字段对应的编码。然后,当查询结果产生后,会从表和字段的编码,转换成character_set_results编码,返回给客户端。

对于宽字节编码,有一种最好的修补就是:

  • 使用mysql_set_charset(GBK)指定字符集

  • 使用mysql_real_escape_string进行转义

原理是,mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集,不会出现前面e5和5c拼接为一个宽字节的问题,但是这个“当前字符集”如何确定呢?

0x05 补充

1、当 ' " 被转义是 后面用到时,可将字符串转成16进制 从而绕过 不使用 引号

0x06 参考

SQL注入:宽字节注入(GBK双字节绕过)

Q.E.D.