宽字节注入问题

0x00 宽字节

在代码注入攻击中,宽字节问题已经是老生常谈。注意,这里的代码注入是指宽泛的代码注入:所有突破数据与代码边界,使数据注入代码段,变成可执行代码的攻击手法都可以叫代码注入,包括SQL注入和XSS。啥是宽字节呢?其实就是用多个字节表示一个字符。

0x01 另一个角度看MySQL的宽字节注入问题

先说说MySQL中的宽字节注入,MySQL在接受到php传来的SQL语句时,会使用MySQL设置中的character_set_client设置值进行编码。而如果character_set_client是一个宽字符集,那么可能会将SQL语句中的多个字节编码成一个字符,这样就改变了SQL语句的原意。我们对这个编码前的SQL语句稍加控制,使编码编掉一些字符,比如\,这样就能绕过php层的安全策略。说起来可能略抽象,下面打一个简单的比方。

实验环境:magic_quotes_gpc=Off,php代码如下

1
2
3
4
<?php
$a=$_GET['a'];
$a=addslashes($a);
print "select * from admin where name='".$a."'";

代码非常简单,将传入的a使用addslashes函数转义,转义掉单引号等字符。我们请求http://115.28.188.93/1.php?a=admin%df‘ and 1=1 – s抓包,看到的响应如下图

红色框中被选中的内容就是响应的内容,这个是二进制的,可以看做是SQL语句在传给MySQL的时候的状态。这个时候,浏览器的返回时这样的(浏览器编码设置为UTF-8)

在这里,浏览器设置的编码相当于MySQL的character_set_client,浏览器会对http响应的部分做编码,MySQL也是一样,这种情况下,我们发现我们请求中的单引号已经被转义了,无法形成SQL注入。我们把浏览器编码设置为gbk,再看看

这个时候,我们发现\不见了,我们插入的单引号成功闭合了前面的单引号,and 1=1已经插入到了SQL语句代码部分,能影响SQL语句的逻辑。也就是说,这个时候,我们相当于把MySQL的character_set_client设置成了gbk,成功引发了宽字节的注入问题,这就是整个数据流的流向,最复杂的一部分已经弄清楚了,下面就是一些细节问题了。

在admin%df’被addslashes后,结果是admin%df\’,也就是admin%df%5c%27,而将其转换为gbk编码后,%df%5c代表一个中文字符,然后就被编码成運,喜闻乐见的,我们的单引号就被插入了。

(题外话:不同浏览器在得到一个没有指定编码的html响应时可能会采用不同的编码,我的Chrome和Firefox就是这样。所以,请手动设置编码方式)

哪些范围会被gbk编码成汉字呢?根据gbk编码,第一个字节ascii码大于128,基本上就可以了。如果character_set_client是gb2312,能不能成功呢?理论上来说,只要\,也就是%5c在某些字符集的低位中,都是可以的,不巧,gb2312的低位范围是0xA1~0xFE,所以不可以。

0x03 初衷

我为啥写这篇文章?phithon在Freebuf上的浅析白盒审计中的字符编码及SQL注入写得非常好,但是我认为在SQL语句的流向方面写得不够详细,我做了一点补充,其余内容请参看phithon大神的文章。如果有什么不明白,那多半是SQL语句的流向以及编码状态不明白,可以参考我上面浏览器编码的比喻。

0x04 意识

玩儿英雄联盟的人都知道,意识最为重要。做安全也是如此,意识本质上是安全观。宽字节的问题,有可能改头换面出现在另一个地方,就看下次遇到的时候,谁能思考得深,看到更内在的东西了。