宽字节注入

概念

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

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

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

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

常见的宽字节: GB2312、GBK、GB18030、BIG5、Shift_JIS
GB2312 不存在宽字节注入,可以收集存在宽字节注入的编码。

前提条件

简单理解:数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入

深入讲解:要有宽字节注入漏洞,首先要满足数据库后端使用双/多字节解析SQL语句,其次还要保证在该种字符集范围中包含低字节位是 0x5C(01011100) 的字符,初步的测试结果 Big5 和 GBK 字符集都是有的, UTF-8 和 GB2312 没有这种字符(也就不存在宽字节注入)。

SQL 执行原理

网上遇到一个能较好体现 SQL 语句的解析&执行过程的图片,在这里:

假如这个网站有宽字节注入那么我们提交:

http://127.0.0.1/GBK?id=%df%27

这时,假如我们现在使用的是addslashes来过滤,那么就会发生如下的转换过程
例子:

%df%27===(addslashes)===>%df%5c%27===(数据库GBK)===>運'

SQL 在执行过程中,会分为如下几个部分:

1.客户端以某种字符生成SQL语句发送至服务器,这里“某种字符”其实是任意规定的,当 PHP 作为客户端连接 MySQL 的时候,这个字符集就是 PHP 的默认编码。

2.服务器接收到请求后会把客户端编码的字符串转换成连接层编码字符串(具体流程是先使用系统变量character_set_client 对 SQL语句进行解码后会使用系统变量 character_set_connection 对解码后的十六进制进行编码)。

3.进行内部操作前,将请求按照如下规则转化成内部操作字符集,如下:

  • 3.1 使用字段 CHARACTER SET 设定值;
  • 3.2 若上述值不存在,使用对应数据表的DEFAULT CHARACTER SET设定值;
  • 3.3 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;
  • 3.4 若上述值不存在,则使用character_set_server设定值。

4.执行完 SQL 语句之后,将执行结果按照 character_set_results 编码进行输出。

使用 SET NAMES 命令SET NAMES ‘gbk’或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。

SET NAMES ‘x’语句与这三个语句等价:

  • mysql>SET character_set_client =x;
  • mysql>SET character_set_results =x;
  • mysql>SET character_set_connection =x;

也就是说你设置了 SET NAMES ‘x’ 时就等于同时执行了上面的3条语句

总结

在使用UTF-8 对 SQL 语句进行解析时,若想发生注入,并不是在解析 MySQL 语句的阶段,而是在客户端提交到服务器之前就已经发生了 SQL 注入,所以这种注入并不是 UTF-8 编码的锅, 统一使用 UTF-8 编码并且不要使用危险的函数 iconv 是一个比较安全的编码方案。

如果由于历史遗留原因一定要使用 GBK 的编码(解析)方式可以采用 mysql_set_charset 配合 mysql_real_escape_string 转义的方式进行防护。

在代码审计的较多需要留意一下 类似 GBK 和 BIG5 这种的双字节编码,同时存在低字节位位可以是 %5C 的字符,如果使用这种存在这种字符的编码对 SQL 语句进行解析,宽字节注入就离你不远啦。

参考:
https://paper.tuisec.win/detail/80365c7a33e34bc
https://paper.tuisec.win/detail/cb5a91c63a97b8d

为您推荐

发表评论

电子邮件地址不会被公开。 必填项已用*标注