在使用PHP连接MySQL的时候,当设置"set character_set_client=gbk"的时候 会导致一个编码转换的注入问题,也就是宽字符注入。我们先搭建一个环境:
建立的有test数据库,user表,id列,username列和password列,里面存的有相应的数据。 首先我们先加一个单引号试试
可以看到没有报错,说明不能执行sql注入。为什么会这样呢?查看代码可以看到 $id=addslashes($_GET['id']);此函数的作用就是让'变成\',让单引号不再是单引号,因此就没法执行sql注入了。宽字节注入是利用MySQL的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。如果我们输入%df%27看会怎样:
我们可以看到,已经报错了。我们看到报错,说明sql语句出错,看到出错说明可以注入了。
这是因为id的参数传入代码层,就会在’前加一个\,由于采用的URL编码,所以产生的效果是:%df%5c%27,关键就在这里,在GBK编码中,两个字符表示一个数字,所以%df把%5c吃掉形成了一个汉字,后面就剩一个单引号,所以此时的单引号并没有被转义可以发挥效果。
很明显sql注入成功了。
注意:宽字符注入利用的是多字节编码,而多字节编码并不止GBK一种,比如还有GB2312,而用GB2312就不会有 宽字符注入,这是因为gb2312编码的取值范围。它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE,而\是0x5c,是不在低位范围中的。所以,0x5c根本不是gb2312中的编码,所以自然也是不会被吃掉的。而GBK首字节对应0x81-0xFE,尾字节对应0x40-0xFE(除0x7F),刚好涵盖了对应的编码0x5C,所以有宽字符注入。因此可以推广到所有多字节编码,只要低位覆盖0x5c就可以进行宽字符注入。
网友评论