FishFuzz: Throwing Larger Nets to Catch Deeper Bugs
开源于:https://zenodo.org/record/6405418
论文基本信息
发表年份:2022
发表会议或期刊(简称,CCF级别):预印版
论文标题(论文简称):FishFuzz: Throwing Larger Nets to Catch Deeper Bugs
论文作者所在团队:网络中心、兰州理工、西电、海南,EPFL
论文一句话概述:论文提出XX方法,解决了XX问题。
论文实验情况:实验工具(是否开源),实验测试集(是否开源),实验环境,实验规模,简要过程
论文概述
定向模糊测试是在开发中发现漏洞的一种标准方法。模糊测试会执行许多输入来最大化测试的代码。最近,定向模糊测试提出了一种策略,不仅仅是最大化覆盖率。而是让测试导向特定区域。定向模糊测试有两个阶段,exploration(探索有趣的区域)和exploitation(触发漏洞)。目前的定向模糊测试的探索阶段都是用覆盖率来引导,exploitation阶段是通过切换不同目标来间接实现的。具体来说,文章发现了现有定向模糊测试的两个局限。(i)距离指标在对多条路径和多个目标进行计算的时候不是很准确。(2)分配能量到种子的粒度比较粗糙,没有考虑调整目标的优先级。
文章提出了FishFuzz,灵感来源捕鱼。首先放一个大网,获取比较高的覆盖率,然后慢慢收网来最大化抓到的鱼。FishFuzz的核心是两个理念:(1)一种新的距离指标,准确率和目标的多少无关。(2)动态的目标排名,能够自动排除已探索过很多次的target。这个策略让FishFuzz能够无缝从单目标到多目标的切换,并且能够动态地在exploration和exploitation中切换。
评估部分,将所有的sanitizer打的标签当作是target。并与三个DGF和两个CGF作笔记,结果表示,FishFuzz能够实现更高的覆盖率,并且复现现有的bug更快,最后在44个程序中发现了25个新的bug。
研究背景
问题是什么?
现有的定向模糊测试存在以下两个问题:
- 种子爆炸:fuzzing的过程提供了大量的种子,放在一个池子里。导致很多好的种子没有得到足够的重视。
- 不准确的距离度量:对大量目标计算距离会引入不准确性,也是现有定向模糊测试的种子调度算法无法处理的。
意义是什么?
可以处理大规模目标,而不会丢失准确性。
相关工作
相关工作主要介绍了定向模糊测试和多阶段模糊测试。
定向模糊测试
定向模糊测试是模糊测试的一个分支,专门去测试给定的区域。AFLGO将种子到目标的距离建模为调和平均距离。然而,AFLGo对于大规模的目标会丢失准确性。Hawkeye和FuzzGuard都尝试处理距离计算的间接调用问题,其中hawkey使用重量级的静态分析,Fuzzguard使用深度学习过滤不可达的输入。
后面的DGF扩展性会更好一些。比如ParmeSan和SAVIOR。他们两个把target当成是所有sanitizer打上的标签。此外,SAVIOR也使用了开销比较大的可达性分析来选择有趣的输入。但他们都有AFLGo的局限性,就是把种子到目标的距离折叠为一个标量。
CAFL的目标是给定一个crash,然后生成一个PoC。但CAFL只考虑一个目标。AFLChurn通过分析github仓库选择可能存在bug的位置去测试。这和本文算是一个正交的工作。Beacon使用复杂的静态分析来移除不可达的路径,从而提高了exploration的效率。这和fishfuzz提升的维度不一样。
多阶段模糊测试
多阶段的模糊测试使用exploration和exploitation来到达和触发多个目标。AFLFast使用马尔科夫链来概率性地选择种子来提高覆盖率。FairFuzz使用一种新的变异策略和种子选择方式来命中稀有的分支。他们的贡献是提高代码覆盖率。而fishfuzz是最大化触发的目标。Yue将适应性能量调度和博弈论结合起来,来防止测试没用的种子。wang基于软件分析选择有趣的目标,然后结合一种新的队列策略。然而,他们的方法只考虑了时间不变的target,也就不会自适应地调整fuzz的能量到更有可能发现漏洞的位置。FishFuzz的队列切换方式是自适应的,而且可以被用来提高wang的工作。
原理
给定一个目标程序,会编译并用sanitizer插桩,并且提取一些有用的信息。整体流程和通常的模糊测试差不多。主要修改的地方是距离指标和种子选择的实现。
Program Preparation
在程序分析阶段,主要是提取sanitizer插入的target。但由于有些target可能会是不可达的。现有的方法使用静态分析来剔除,但静态分析有可能会误删。因此,FishFuzz将所有的目标都视为有效地,通过动态排名来过滤不理想的目标。
在编译阶段,提取了控制流图和调用图,此时的图没有考虑间接调用。然后,FishFuzz依赖CFG和CG的过程间距离来选择靠近目标的种子。这些操作都是基于LLVM IR上做的。
Queue Culling Algorithm
队列选择算法灵感源于捕鱼技术。在fuzzing的初期,Fishfuzz采取exploration模式,类似广撒网。当没有发现新的函数时,FishFuzz会去聚焦于最大化到达的目标,类似收网。当到达了足够多的目标时,cull的逻辑改变,尝试去触发有趣的目标(尽可能地抓到更多的鱼)。由于每个步骤都需要不同的指标(到达函数的数量,到达目标的数量,触发目标的数量),所以也像别的工作一样分阶段来做。
主要分为三个阶段:Inter-function exploration,intra-function exploration ,exploitation。
inter-function exploration:到达感兴趣的函数。
intra-funcion exploration:函数内测试,主要是去尽可能地命中更多的目标。
exploitation:尽可能地触发更多可以到达目标。
他们的切换过程如下图所示,当没有发现新的函数的时候,就会从inter-function转为intra-function。当发现了新的函数,就会从intra-function转为inter-function。如果没有到达新的target,就会从intra-function切换到exploitation阶段。没有触发新的target,就会从exploitation回到intra-function。
inter-function exploration过程中,给定一个种子队列和一个函数集合。对于那些经过未探索的函数,并且包含目标的种子,将favor设为1。在把favored的种子提交给程序后,FishFuzz更新探索过的函数列表,并且重复这个过程。getClosestSeedToFun会去找到离目标函数f最近的种子。
exploitation过程中,FishFuzz会尝试触发已到达的目标。他的思路是通过不同的种子来命中同一目标,能够增加发现bug的概率。首先,使用那些能到达的目标。在trgs_to_visit中,选择前20%命中的目标。对于每个合适的目标,getFastestSeedToTarget返回最快到达t的种子s。这个过程中,有很大的概率选择命中目标的种子(seed target distance=0)。
距离指标
距离指标分为:
- 静态函数距离
- 动态种子到函数的距离
- 动态种子到多目标的距离
静态函数距离指的是调用图上两个函数最短的边的数量。
动态种子到函数的距离,分为以下两种情况,如果种子经过了目标函数,距离则为0,如果没有经过,距离为最近的那个函数到种子的距离。
动态种子到多个目标的距离,是由多个种子到各个目标的距离组成的一个向量。会在这个函数用到getFastestSeedToTarget
种子到单个目标的距离为前面的距离,加上一个目标是否被触发的条件。
这里很奇怪,给了一个向量,要怎么比距离?向量的比较方式,论文中没有说明。
关于间接调用的问题。种子到函数的距离被表示为最小函数的距离,作者认为这种方法可以找到近似最佳的结果。当一个种子遍历到间接调用时,fishfuzz可以使用附近的函数来估计种子执行路径到目标函数的距离。如果一个函数没有和其他函数直接联系,模糊器要么生成一个到达该函数的种子,要么生成一个无法到达的种子。实际上,这种方法和以前一个使用fuzzing来探索间接调用的工作相同。
具体实现
基于AFL 2.57b实现,插桩使用的是LLVM 12.0.1。实现函数内探索和利用阶段,用了2500行的代码。对于插桩部分,代码有1500行。
源码和复现相关的材料在被接收后就会开源。目前已开源在:https://zenodo.org/record/6405418
实验结果及分析
回答6个问题:
- FishFuzz能到达多少目标?
- FishFuzz能够平衡能量吗?
- FishFuzz发现漏洞的效率怎么样?
- FishFuzz能发现新漏洞吗?
- FishFuzz是如何重新分配exploration和exploitation?
- 其他的fuzzer能够从我们的策略受益吗?
对比工具选择了TortoiseFuzz,ParmeSan和SAVIOR。同时AFL++和AFL也被作为baseline。
benchmark方面,选择了TortoiseFuzz、SAVIOR和ParmeSan测试的程序。TortoiseFuzz用的程序会被ASAN插桩,在文章中叫ASAN benchmark。SAVIOR测的程序只包含UBSan sanitizer,就叫UBSAN benchmark。
RQ1
这个实验评估的指标主要是覆盖率和目标覆盖率。
对比ParmeSan和TortoiseFuzz。
和SAVIOR进行对比的结果。
RQ2
这个部分评估FishFuzz为目标重新分配能量的能力。与AFL进行对比,跑3轮24小时。下面的图展示了FishFuzz尝试去分配能量给那些测试比较少的target。
RQ3
这个实验中是评估exploitation阶段触发漏洞的能力。主要是比发现的漏洞的数量。
RQ4
找了28个顶会里用的程序,对于每个程序用ASan和UBSan插桩,用一周的时间去找漏洞。最后发现了25个新的漏洞,其中18个被确认为CVE。
RQ5
这个实验主要是看三个阶段的覆盖率,触发的目标和轨迹。下面这个图展示了各个fuzzer阶段覆盖的边的情况。蓝色是inter-function,绿色是intra-function,红色是exploitation。覆盖率在exploration阶段的时候,快速上升。在exploitation(红色)阶段,覆盖率趋于平稳。两种exploration阶段在开始阶段比较频繁出现,exploitation阶段则倾向于在后期出现。
RQ6
和其他fuzzer结合的能力如何,明显比afl和qsym的相性好。
论文总结
自己的感受
读完论文后,自己的想法
论文有哪些优点和亮点
论文还有哪些问题没有解决
有哪些启发,可以继续探索
作者很贴心地附上了画韦恩图的工具:jvenn: an interactive venn diagram viewer
tortoisefuzz我得看看,之前给我的印象并不是定向模糊测试。
Mann-Whitney U test,这个概念在windranger中也看到过,当时没有特别注意。有时间再搜搜看。
文章留了很多阈值调参来作为后续的工作。阈值是不是也是程序无关的呢?
arxiv上的写作上还有些瑕疵。