最近在学习模糊测试相关内容,在知乎上看到泉哥写的”从研究者的视角看Fuzzing技术30年”,感觉内容质量很高,原文链接:https://zhuanlan.zhihu.com/p/103914349
看完之后受益匪浅,写个博客总结一下,并想从中探索自己的研究方向。
源起
Barton Miller提出fuzz生成器用随机生成的数据测试Unix程序的健壮性。此阶段模糊测试仅用于验证代码质量和程序的稳定性,而不是专用于漏洞挖掘。
从学术界到工业界的证明
2001年PROTOS测试项目将Fuzzing技术用于网络协议的安全测试中,2002年基于块模板定义的网络协议测试工具SPIKE出现。
这部分内容令我没想到,最早fuzzing与工业结合应用是用于网络协议的测试,个人认为网络协议的测试相比二进制程序,要相对困难一些。
文件Fuzzing技术的兴起
2004年,Peach模糊测试框架发布,标志着文件Fuzzing时代的到来,最初是python,后面使用C#重写,Peach支持对网络协议、文件格式、Active控件等多种内容的测试。
直至今日,Peach依然还有人在用,更有人将Peach与AFL打通,在Github上发布aflsmart的开源项目。
文件Fuzzing应该是当前Fuzzing应用中最为普遍的形式,即使是网络协议等其它目标的Fuzzing,也是可以转换为文件Fuzzing的。比如OpenSSL网络协议Fuzzing,通过源码打Log的方式先收集网络数据为本地文件,再调用其API写个hareness用AFL或libfuzzer进行本地测试,就顺利地将网络协议Fuzzing转换为文件Fuzzing。
文件Fuzzing是什么意思呢?作者没有做详细解释,是将测试对象作为文件处理,还是说通过构造文件实现对程序的测试呢?
语法模板Fuzzing:打开攻击浏览器的大门
2008年,Mozilla安全团队发布了jsfunfuzz和DOMfuzz,基于JS语法模板来生成测试用例,以挖掘浏览器漏洞,后来两款工具合称funfuzz(https://github.com/MozillaSecurity/funfuzz),以开源的形式对外公开。
语法模板fuzzing,个人认为其关键点在于为什么这种方式可以打开攻击浏览器的大门,个人猜测是因为语法模板fuzzing在生成结构化数据,对格式有要求的数据时更具效率,文件fuzzing和随机模糊生成的数据无法通过校验,生成的数据绝大多数都是无价值的。所以将语法融入模糊测试是非常必要的。
符号执行:学术与工业之争
之前不知道符号执行是什么,在简单学习“The Fuzzing book”后基本了解了其原理。正如原文作者所说的,符号执行的消耗对于工业界来说显然过大,对于大型应用使用显然不现实,会出现路径爆炸等问题。真正引发新技术浪潮的是接下来要介绍的代码覆盖率技术。
代码覆盖引导技术:Fuzzing技术的分水岭
2013年底,afl-fuzz(http://lcamtuf.coredump.cx/afl/ )发布了,首次采用源码编译插桩和QEMU模式来实现代码覆盖引导Fuzzing的方式,这绝对是Fuzzing技术发展历程中最重要的一次里程碑,也是技术分水岭,它开启了Fuzzing技术的新篇章。
代码覆盖率为什么重要,我在这里分享一些自己的理解。上文提到的语法Fuzzing、文件Fuzzing好像都没有使用到程序内部信息,而代码覆盖率作为内部信息反馈给模糊器,模糊器使用其进行优化策略是一个相当好的方式,通过程序信息来测试程序想想就很靠谱。
随后,基于afl二次开发的fuzzer如雨后春笋般涌现出来,比如winafl、libfuzzer、AFLFast、Vuzzer等等,而且针对各种语言的版本出相继出现,比如go、python、js、ruby等等。一些已知名的Fuzzer也迅速跟进,比如syzkaller内核Fuzzer,它原本是基于API调用模板的,后来也引入了代码覆盖引导能力。同时,业界都在试图将其移植到各种平台上(比如windows、android、IOT平台等等),并实现支持闭源程序的代码覆盖引导能力,这一直是近几年来Fuzzing技术研究的热点方向,比如动静态插桩、虚拟机模拟执行、硬件特性等等。无论是工业界大会(BlackHat、OffensiveCon、CCC等等),还是学术界四大顶会,关于Fuzzing的议题也越来越多,相信这种趋势会持续下去。
上段话总结了AFL对于Fuzzing研究方面的影响,从中可以看出很多优化的点,但这些方向感觉做起来太难了,实现支持闭源程序的代码覆盖引导能力,这些问题解决起来感觉难度太高了。看懂AFL的源码,简单改下算法都够我花很多很多时间了。但其内容人仍然值得学习和思考,以理解模糊测试研究的发展。
系统函数调用模板Fuzzing一度成为攻击内核的常用手段
2015年Google开源了syzkaller,一款用于Fuzzing Linux内核的工具,漏洞产出特别高。现在依然很多人用它来挖各系统平台的内核漏洞,包括Android、macOS、Windows等主流系统平台。syzkaller通过定义系统函数调用模板来实现,在模板中定义系统调用函数参数类型,并解决函数调用的顺序依赖和值依赖问题。Project Zero官方博客就曾写过一篇利用syzkaller fuzz socket挖掘Linux内核漏洞的文章,标题为“Exploiting the Linux kernel via packet sockets(syzkaller usage)” (https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html ),详细讲述了如何编写模板,以及syzkaller的使用方式。
通过定义系统函数调用模板来Fuzzing内核,我目前不太明白这是什么。看起来使用模板对内核进行测试,但为什么不是针对其他目标呢?为什么使用这种方式非常适用于内核呢?
助力开源生态安全建设
可以看到google对于模糊测试的研究做出了很大的贡献,目前针对这些开源工具我还没有实践使用过,后续可以搜寻相关资料,做一些实践。
语法树变异成为语法解析引擎漏洞挖掘的新方向
2012年,USENIX安全顶会上发布一篇论文“Fuzzing with code fragments”,研究者开发了一款叫LangFuzz的工具,他们从firefox、webkit、chromium等开源的浏览器项目以及网络上去收集js测试样本,然后用ANTLR其进行AST语法树分析,再将样本拆分成非终止语法的代码片断,放入代码池中,最后再基于代码池的代码片断对输入样本作交叉变异,主要取同类型的代码片断作替换或插入,再运行生成的变异样本进行测试。
这一部分内容在“The Fuzzing book”中有专门讲解,通过语法树解析语法,以这种方式来对数据进行变异,目的可以说是为了提升测试用例的生成质量。
人工智能在Fuzzing中的应用仍亟待探索