0x01: 转义函数
- addslashes()
- mysql_real_escape_string()
addslashe在单引号,双引号,反斜杠\,NULL前加反斜杠转义
而mysql_real_escape_string可转义 \x00, \n, \r, ‘, “ ,\x1a
它们都没有转义%,所以我们可以根据宽字节的特性来进行注入
我们先来看一下几种常见的编码方式
0x02: 常见编码
gbk
gbk/3是扩充汉字, 高位是 0x81 - 0xA0,低位是 0x40 - 0xFE,反斜杠\的十六进制是0x5c,属于低位,\的十六进制是5c, 在低位中,所以会造成宽字节注入。
gb2312
gb2312编码的高位范围是0xA1 - 0xF7,低位范围是0xA1 - 0xFE,而\是0x5c,是不在低位范围中的。所以,0x5c根本不是gb2312中的编码,所以不会造成宽字节注入
utf-8
utf-8的编码规则
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于大于一个字节的来说,除了第一个字节,剩下的字节的前两位都是01, 所以0x0000005c不可能在utf-8中,所以不存在宽字节注入。
0x03:转换字符集造成的宽字节注入
我们来看一些mysql中的字符集变量
It converts statements sent by the client from character_set_client to character_set_connection
当mysql接受到客户端的数据后,会先将其转换为character_set_client,然后又将换成character_set_connection的编码,然后进入具体表和字段后,再转换成字段对应的编码。
所以如果传给mysql的数据编码方式与character_set_client不一致时,就有可能出现宽字节注入
传给mysql的数据编码方式 -> character_set_client
utf-8 -> gbk:
gbk编码汉字是两个字节,而utf-8是三个字节,所以如果我们提交 %aa’,
%aa’ -> %aa%5c%27,
确切的来说,只要%5c前面有奇数个字节,%5c就会被前面的吃掉,造成宽字节注入。gbk -> utf-8:
由于utf8多字节的性质,我们传utf8字节时只能传单个字节
例如提交%df’
%df’ -> %df%5c%27
0x03: 防御
- 我们可以将character_set_client设为binary,这样数据会以二进制处理,增加了安全性。或者也可以将各层的字符集都设为utf-8,这样也更方便。
但是我们要格外小心这个函数
string iconv ( string $in_charset , string $out_charset , string $str )
将str由第一个编码变为第二个编码
iconv('utf-8','gbk',$id);
如果它出现在转义之后的,那就已经吃掉单引号了那么还是会出现宽字节注入。
当然这种基于字符集的注入也可以用于其他的攻击,这种攻击归根结底就是没有同意各层的字符编码,所以给了宽字节注入可乘之机,同意设置成utf-8是最好的选择。
参考
浅谈白盒审计中的字符编码与sql注入: http://www.freebuf.com/articles/web/31537.html