论文链接:AFL++
AFL++源代码库:AFL++源代码
摘要
本文提出了一个社区驱动的开源软件AFL++,它结合了最先进的模糊研究,使得具有可比性、可重复性、可组合性,以及它的最重要的特点,可用性。它提供了自定义的Mutator API,使得用户能在多个阶段扩展模糊过程,编写针对特定目标的变异器。同时,本文对精心挑选的模糊化技术进行了评价,指出每一种新的模糊化方法虽然可以提高某些目标的性能,但会降低其他目标的性能。这是未来模糊研究在评估时应该考虑的一个问题。
背景
-
模糊测试是当前一个正在蓬勃发展的领域,而对模糊测试的研究往往是正交和独立发展的,因此把它们结合起来是一个漫长的过程。
-
另一方面,研究人员也很难把他们自己开发的工具集成到现有的模糊测试器上,去更好的评估他们开发的新工具。
基于此,作者提出构建一个具有如下特点的FUzzer:- comparable
- reproducible
- combinable
- usable
借助于fuzzbench,可以对fuzzer进行多次重复测试,从而实现了它的可重复性,而对于可组合性,作者则开发了一些用户端的mutator API来进行fuzzer功能的扩展。
AFL
在AFL++的实现过程中,作者评估了多个fuzzer,最终选择在AFL的基础上进行AFL++的设计,原因如下:
- AFL 广泛的使用证明它是有效的
- AFL代码开源且已经不再维护
- 许多社区都提供了对AFL的补丁和学术支持
AFL特点
AFL采用基于覆盖率引导的反馈机制,是一种将边覆盖率和一次运行中相应边执行次数相结合的混合度量机制;同时AFL将变异分为两个阶段,确定性变异和非确定性编译;采用Forkserver机制生成子进程来执行测试用例;使用Persistent Mode在目标中修补循环使得在每次迭代中只需要执行一个测试用例。
调度策略
AFLFast
使用低频路径来探索更多的种子并发现更多的bug
通过一个种子产生的输入数量来确定分配给种子的能量
MOpt
使用粒子群优化算法对不同的变异因子分配不同的概率
路障绕过
通常,基于覆盖率引导的模糊测试往往会遇见障碍,阻止探索它们背后的代码。典型的障碍是大量的比较,比如字符串和校验和检查。
LAF-Intel
通过将长字符拆分成更小的字符来解决字符串问题
RedQueen
通过猜测可能会影响比较的输入字节并将其进行替换来实现路径绕过
变异结构输入格式
通常的模糊测试会产生大量无效的输入,使程序在解析阶段之后的状态无法访问。解决这个问题的方法是使用输入模型,有效地减少生成的输入空间。这允许基于反馈的模糊器探索程序中的深层路径
AFLSmart
使用PEACH作为一个标准输入模型,使得重用为PEACH编写的协议规范成为可能
AFL++构建
通过将各种先进的模糊测试技术整合到一起,并对它的一些功能进行了扩展和改进,作者提出了AFL++。
种子调度策略
AFL++ 结合了AFLFast的种子调度策略,包括:
- 种子从队列中被选中的次数
- 具有相同覆盖率的种子产生的输入的数量
- 相同覆盖率下产生的平均测试用例的数量
同时,AFL++添加了mmopt和rare调度策略,mmopt增加了对最新的种子的分数,从而更深入的挖掘新发现的路径;rare则将重点放在其他种子很少覆盖的边上。
变异策略
在编译策略上,AFL++不仅结合了AFL中传统的Deterministic和Havoc,同时还构建了加一些用户变异API,使得用户可以很方便的将自己的变异策略整合到AFL++上,在这篇论文中作者对这些API进行了详细的介绍,读者可以自行了解。同时,AFL++实现了基于REDQUEEN的Input-to-State(I2S)变异策略,改进着色阶段,增加了每次比较时模糊测试概率度量,如果在尝试一次路障绕过后没有产生interesting输入则给比较操作分配一个更低的概率,在这一部分,AFL++使用共享表记录域值。同时AFL++实现了MOpt的core和pilot模式。
插装
AFL++ 支持LLVM、GCC、QEMU、Unicore和QBDI这几种插装技术,针对不同的功能实现具有不同的特点,这些插装技术支持的功能特征如下:
支持平台
AFL++ 支持Android、 iOS、 macOS、FreeBSD、 OpenBSD、NetBSD、 Debian、Ubuntu、NixOS、Arch Linux、FreeBSD、 Kali Linu等多个操作系统。
基于LKM的快照模式
由于AFL的状态存储机制存在性能瓶颈,因此AFL++采用了Linux Kernel Module(LKM)机制来实现了一个轻量级的快照拍摄和存储机制。
AFL++性能评估
接下来作者在fuzzbench下测试了AFL++在不同配置下的表现情况,包括默认设置的AFL,MOpt,基于Ngram4的插装策略,RedQueen,Ngram4和rare结合,Mopt和RedQueen结合这几种情况下模糊测试的效果来评估AFL++ 进行的改进,其中:
Ngram在记录边时,通过考虑目标块和前N-1(这个N为4)个块从而有效的增加了状态反馈机制。
rare将种子的选择重点放在其他种子很少覆盖的边上
测试结果如下:
从图中可以看到MOpt的表现要么非常好,如b、h,要么非常失败如f。通过MOpt的曲线变化可以看到它往往是突然在运行中找到新的路劲,从而开始获得大量的覆盖。而对于图f,可以看到RedQueen的正面效应抵消了Mopt的负面效应。
而对于Ngram,由于依赖于先前产生的分支,有效的增加了状态反馈,rare有时会改善覆盖,(如图i和c),有时则比默认的AFL++ 调度表现更糟糕(如图d)。
综上,可以发现在不同的测试程序中,相同的模糊策略往往会存在巨大的差异,而在相同的测试程序中,不同的模糊策略也会存在着很大的性能差异,因此,针对不同的测试程序,评估并选择合适的模糊策略是非常有必要的。
发现的bug
未来的改进方向
作者提到,尽管AFL++在很多程序中都表现较为优秀,然而依然存在着一些可以改进的地方:
AFL++目前在多线程上表现并不理想,由于过度依赖于文件系统来传递测试用例,至少对于不支持LLVM的后端是这样,以及某些目标对fork调用的依赖导致大部分时间都花费在内核上。作者提到,逻辑上下一步应该采用多线程支持来最大限度的减少并行fuzzer之间的同步开销。
AFL 提供的插装技术采用散列表的方式记录当前地址到下一地址的转换,这往往会带来一定的路径冲突
不同的测试目标往往需要与之相对应的模糊策略,作者提到如何引入一个标志来表示测试目标的性能,指示程序采用最优的模糊策略
尽管AFL++提供了大量的插件功能,但是在反馈机制上仍然存在较大的改进空间
针对AFL近年来的改进
基于AFL++的最新研究成果Papers | AFLplusplus