IEEE T RELIAB2018-Fuzzing: State of the Art

摘要:模糊技术是目前最流行的软件测试技术之一,它可以通过生成大量的测试输入来发现程序中的各种缺陷,如软件bug和漏洞等。由于其有效性,模糊算法被认为是一种很有价值的bug搜索方法。在本文中,我们概述了模糊的一般过程和分类,然后详细讨论了关键的障碍和一些最新的技术,旨在克服或减轻这些障碍。我们进一步研究和分类几种广泛使用的模糊工具。我们的主要目标是让涉众更好地理解模糊化,以及改进软件测试和安全领域的模糊化方法的潜在解决方案。为启发今后的研究,本文还对未来的研究方向进行了展望。

I. INTRODUCTION

A. Motivation

B. Outline

II. REVIEW METHOD

A. 研究问题

本调查主要是为了回答以下关于fuzzing的研究问题。
1)RQ1:模糊化研究的关键问题和相应的技术是什么?
2)可用的模糊器和它们已知的应用领域是什么?
3) RQ3:未来的研究机会或方向是什么?

B.纳入和排除标准

C.来源资料和搜索策略

其中包括1990年1月至2017年6月的350多篇论文。首先,我们搜索了一些主要的在线知识库,如IEEE XPlore, ACM数字图书馆,施普林格在线图书馆,Wiley InterScience, USENIX和Elsevier ScienceDirect在线图书馆,并收集了在标题、摘要或关键字中包含“fuzz testing”、“fuzzing”、“fuzzer”、“random testing”或“swarm testing”的论文。其次,根据我们的选择标准,我们使用文集的摘要来排除其中的一些。如果不能通过摘要来判断论文的内容,我们确实是通读了一遍。这一步由两个不同的作者执行。在我们的调查范围内,候选论文减少至171篇。这些论文被称为初级研究[20]。

D.结果总结

1990年1月1日至2017年6月30日发表的Fuzzing论文。(a)每年出版物数目。(b)每年出版物的累积数目。
在这里插入图片描述
1)发表趋势:图1(a)为1990年1月至2017年6月30日关于模糊化的发表数量。曲线图显示,自2004年以来,这一主题的论文数量一直在持续增长,尤其是在2009年之后。
在这里插入图片描述
2)发表地点:171项初步研究在78个不同地点发表。这意味着模糊文学所涉及的领域非常广泛。这可能是因为这种技术非常实用,已经应用于多个测试、可靠性和安全领域。就研究地点类型而言,大多数论文是在会议和座谈会上发表的(73%),其次是期刊(15%)、研讨会(9%)和技术报告(3%)。表二列出了至少三篇模糊论文的发表地点。
3)出版物的地理分布:我们将每个主要研究的地理起源与其第一合著者的所属国家联系起来。有趣的是,我们发现所有171项初级研究都来自22个不同的国家,如表三所示,美国、中国和德国是前三名(只有论文超过四篇的国家)。按大陆划分,43%的论文来自美国,32%来自欧洲,20%来自亚洲,5%来自大洋洲。这表明,模糊社区是由为数不多的国家组成,但分布在世界各地。
4)研究人员和组织:我们在171项主要研究中确定了125位不同的共同作者。表四展示了关于模糊化的主要作者和他们最近的合作关系。

III. GENERAL PROCESS OF FUZZING

在这里插入图片描述
目标程序: 目标程序是受测程序。它可以是二进制代码或源代码。但是,实际软件的源代码通常不容易访问,因此 模糊测试器 通常以二进制代码为目标。
监视器:此组件通常内置于白盒或灰盒模糊器中。监视器利用代码检测、污点分析等技术来获取目标程序的代码覆盖、污点数据流或其他有用的运行时信息。在黑盒模糊器中不需要监视器。
测试用例生成器:模糊测试用例有两种主要方法:基于突变和基于语法的[1]方法。第一种方法通过随机突变格式良好的种子文件或使用预定义的突变策略来生成测试输入,这些策略可以根据运行时收集的目标编程信息进行调整。相反,第二种方法不需要任何种子文件。它从规范(例如语法)生成输入。在许多情况下,模糊测试用例通常是半有效输入,其有效性足以通过早期解析阶段,并且无效到足以触发目标程序的深层错误。
Bug检测器:为了帮助用户在目标程序中发现潜在的bug,在模糊测试器中设计并实现了bug检测器模块。当目标程序崩溃或报告某些错误时,bug检测器模块收集并分析相关信息(例如,堆栈跟踪[22])以确定是否存在错误。有时,可以手动使用调试器来记录异常信息 [23]–[25] 作为此模块的替代方法。
bug过滤器:测试人员通常关注正确性或与安全相关的bug。因此,从所有报告的bug中过滤可利用的bug(即漏洞)是一项重要的任务,通常手动执行[23],这不仅耗时而且很难解决。目前,一些研究工作[26]提出了各种方法来缓解这一问题。例如,通过对fuzzer的输出(bug诱导的测试用例)进行排序,不同的、有趣的测试用例被划分了优先级,测试人员不需要手动搜索需要的bug,这就像大海捞针一样。

IV. BLACK, WHITE, OR GRAY?

模糊技术可以分为三种:黑盒、白盒和灰盒,这取决于它们在运行时[28]需要从目标程序获得多少信息。这些信息可以是代码覆盖率、数据流覆盖率、程序内存使用情况、CPU使用情况,或者任何其他用于指导测试用例生成的信息。

A. Black-Box Fuzzing

黑盒:使用一些预定义的规则来随机改变给定的格式良好的种子文件,以创建格式不正确的输入。利用语法或特定于输入的知识来生成半有效的输入。

B. White-Box Fuzzing

白盒:使用动态符号执行(也称为concolic execution)和最大覆盖率启发式搜索算法。白盒模糊利用目标程序的源代码或二进制代码系统地探索所有的执行路径。通过使用圆锥执行和约束求解器,白盒模糊可以确保生成的测试用例将引导目标程序探索新的执行路径。

C. Gray-Box Fuzzing

灰盒:插桩;污染分析。仅利用目标程序的一些运行时信息(例如,代码覆盖,污染数据流等)来决定哪些路径已经被探索了。此外,灰盒模糊化只使用获得的信息来指导测试用例的生成,但它不能保证使用这段信息一定会生成更好的测试用例来覆盖新的路径或触发特定的bug。

D. How to Choose?

如何选择?对于测试人员来说,选择哪种模糊器主要取决于两个因素:1)目标程序的类型和2)测试要求(时间/成本等)。

V. STATE OF ART IN FUZZING

在构建模糊测试时应考虑以下问题:
1)如何生成或选择种子和其他测试用例;
2) 如何根据目标程序的规范验证这些输入;
3) 如何处理那些诱发崩溃的测试用例;
4)如何利用运行时信息;
5)如何提高模糊测试的可扩展性。

A.种子的产生和选择

如何生成或选择合适的种子文件以发现更多的bug是一个重要的问题。为了解决这个问题,已经进行了一些研究工作。Rebert等人测试了六种选择算法:
1)来自Peach的集合覆盖算法;
2)随机种子选择算法;
3)最小集覆盖(与最小集相同,可通过贪婪算法计算);
4)按大小加权的最小集覆盖;
5)基于执行时间加权的最小集覆盖;
6)一个热集算法(它模糊测试每个种子文件t秒,根据唯一发现的bug数量对它们进行排序,并返回列表中排名靠前的几个种子文件)。
他们得出了以下结论。
1)采用启发式的算法比完全随机抽样的算法性能更好。
2)在六种算法中,未加权最小集算法表现最好。
3)在实际应用中,减少的种子文件集比原种子文件集具有更高的效率。
4)减少种子集可以应用于不同的应用程序,解析相同的文件类型。

Kargén和Shahmehri[48]声称,通过对生成的程序的机器码执行突变,而不是直接对格式良好的输入执行突变,得到的测试输入更接近于被测程序所期望的格式,从而产生更好的代码覆盖率。为了测试复杂的软件(如PDF阅读器),这些软件通常采用嵌入多个对象(如字体、图片)的各种输入,Liang等人[49]利用字体文件的结构信息,在异构字体中选择种子文件。Skyfire[50]以一个语料库和一个语法作为输入,并利用大量现有样本中的知识生成分布良好的种子输入,用于处理高度结构化输入的模糊程序。在[51]中提出了一种算法,在给定一个程序和一个种子输入的情况下,最大限度地增加黑盒突变模糊处理中发现的bug数。这背后的主要思想是对给定的程序种子对的执行跟踪利用白盒符号分析来检测输入位位置之间的依赖关系,然后使用这种依赖关系来计算该程序种子对的概率最优变异比率。此外,考虑起毛优惠券收集器的概率问题的实例分析,阿库里等。[52]提出并证明了非平凡,最优下界的预期数量的测试用例由随机抽样测试覆盖预定义的目标,尽管在实践中如何实现范围目标不是。
对于面向对象程序的单元测试的随机生成,Pacheco et al.[53]提出在序列被构造时使用执行过程中获得的反馈,以引导搜索到产生新的合法对象状态的序列。因此,创建冗余或非法状态的输入永远不会被扩展。然而,Yatoh等人[54]认为反馈引导可能会过度引导生成,限制生成测试的多样性,并提出了一种名为反馈控制随机测试的算法,该算法自适应地控制反馈量。
我们如何在第一时间获得原始种子文件?对于一些开源项目,发布的应用程序带有大量用于测试的输入数据,这些数据可以作为优质的fuzzing种子免费获得。在具有一定格式的多种文件集的情况下,利用格式转换器可以获得合适的种子进行模糊处理。例如,cwebp可以将TIFF/JPEG/PNG转换为WEBP图像。此外,逆向工程还可以为模糊建模提供种子输入。Prospex[57]可以提取包括协议状态机在内的网络协议规范,并使用它们为有状态模糊器自动生成输入。**自适应随机测试(ART)**对随机测试进行了修改,它对测试空间进行采样,并且只执行那些距离之前所有执行的测试最遥远的测试(由输入上的距离度量决定)。ART并不总是能够有效地应用于复杂的实际程序[59],它主要应用于数字输入程序。
与上面提到的方法相比,通过Internet爬行来收集种子文件更为普遍。基于特定的字符(例如,文件扩展名,魔术字节,等等),测试人员可以下载所需的种子文件。如果采集的语料库数量大,问题并不严重,因为存储成本低,可以将语料库压缩到较小的规模,同时达到等价的代码覆盖率。为了减少错误插入文件的数量并保持最大的测试用例覆盖范围,Kim等人提出在目标软件解析文件时,通过跟踪和分析堆栈帧、汇编代码和寄存器来分析二进制文件的字段。

B.输入验证和覆盖

1)完整性验证:校验和机制,神奇字节
为了模糊这种系统,应该在模糊器中添加额外的逻辑,以便计算新创建的测试用例的正确校验和值。否则,开发人员必须使用其他方法来消除这个障碍。

TaintScope首先使用动态污染分析和预定义规则来检测可能污染目标程序中敏感的应用程序编程接口(api)的潜在校验和点和热输入字节。然后,它改变热字节来创建新的测试用例,并改变校验和点,让所有创建的测试用例通过完整性验证。最后,通过符号执行和约束求解,修复了那些可能导致目标程序崩溃的测试用例的校验和值。
Höschele和Zeller[63]使用动态污染来跟踪每个输入字符的数据流,并将这些输入片段聚合成词汇和语法实体。
Steelix轻量级静态分析和二进制仪器,不仅提供覆盖信息,而且还可以与模糊器比较进度信息。这样的程序状态信息告知模糊器测试输入中神奇字节的位置,以及如何执行突变以有效匹配神奇字节。

2)格式验证:这个问题的大多数解决方案是利用输入特定的知识或语法。

Ruiter和Poll评估了9个常用的传输层安全(TLS)协议实现,将黑匣子模糊与状态机学习结合使用。他们提供了一个抽象消息列表(也称为输入字母),可以通过测试工具将其翻译成发送到测试系统的具体消息。Dewey等提出了一种利用约束逻辑编程(CLP)生成使用复杂类型系统的良好类型程序的新方法,并将其应用于生成Rust或JavaScript程序。
Cao等人首先研究了Android系统服务的输入验证情况,并针对Android设备构建了一个输入验证漏洞扫描器。这个扫描器可以创建半有效的参数,这些参数可以通过由目标系统服务方法实现的初步检查。

3)环境验证:只有在特定的环境下(例如,特定的配置,特定的运行时状态/条件等),许多软件漏洞才会暴露出来。

Dai等人提出了配置fuzzing技术,即在某些执行点改变正在运行的应用程序的配置,以检查仅在特定条件下出现的漏洞。
FuzzDroid还可以自动生成一个Android执行环境,在这个环境中,应用程序可以暴露其恶意行为。FuzzDroid结合了一组可扩展的静态和动态分析,通过基于搜索的算法,将应用程序导向可配置的目标位置。

4)输入覆盖率:

Tsankov等定义了半有效输入覆盖率,它是模糊测试的第一个覆盖标准。
Bastani等人提出了一种算法,用于合成上下文无关的语法,从一组输入示例和黑盒访问程序的有效程序输入语言编码。
ArtFuzz的目标是捕获非崩溃缓冲区溢出漏洞。它利用类型信息并动态地发现可能的内存布局来帮助模糊处理。
克罗齐等提出了一种低成本的有效方法,称为群测试,增加的多样性(随机生成)测试用例,它使用一个多样化的群体的测试配置,每个故意省略了某些API调用或输入功能。
定向群测试利用群测试并记录过去测试结果的统计数据来生成针对任何给定源代码元素的新的随机测试。
Marinescu和Cadar提供了一个自动生成测试套件,实现高覆盖率的软件补丁。

C.处理诱发碰撞的测试用例

目前,只有很少的研究集中在如何过滤原始的模糊输出,使模糊结果对测试人员更有用。
Chen等人提出了一种基于排序的方法,将诱发不同bug的测试用例排列在列表的最前面。因此,测试人员可以专注于分析顶部诱发碰撞的测试用例。
除了直接过滤导致崩溃的测试用例外,还有一些其他的方法来帮助减少昂贵的手工工作,例如生成独特的导致崩溃的测试用例,调整测试用例,以及提供有用的调试信息。诱发崩溃的测试用例的唯一性可以通过目标线程的调用堆栈和导致故障的指令的地址非常可靠地确定[82]。
与记录调用堆栈相比,跟踪执行路径更简单但这不是确定独特性的可靠方法。AFL[27]是最流行的fuzzers之一,如果它找到了新路径或没有找到公共路径,它就会将导致碰撞的测试用例视为独特的。这种易于实现的方法类似于AFL的基础——执行路径记录方法。
在fuzzing过程中,定期对生成的测试用例进行裁剪,可以提高整体效率,从而减少人工分析诱发碰撞的测试用例的工作量。修剪的原则很简单:被修剪的对象的行为应该与原对象的行为一致;换句话说,它们应该遵循相同的执行路径。修剪的一般步骤是依次从测试用例中删除数据块,并重新评估测试用例的其余部分;那些不能影响执行路径的数据块将被删除。
评估fuzzing输出的可利用性通常需要代码分析和调试工作,这些工作可以从专门的工具中获益,如GDB、Valgrind[41]、AddressSanitizer[83]等。这些工具提供目标程序的运行时上下文(例如,调用堆栈和寄存器的状态,故障诱导指令的地址,等等),或者可以检测特定类型的程序故障,如内存错误。在他们的帮助下,测试人员能够更有效地发现和评估程序错误。此外,Pham等人[84]提出了一种方法来生成到达给定“潜在崩溃”位置的输入。由他们的方法生成的测试输入作为crash的见证人。

D.利用运行时信息

符号执行和动态污染分析经常被用来使模糊处理更智能。

1)路径爆炸:函数摘要;冗余路径剪枝;合并不同路径;启发式算法:随机路径选择;自动部分环路摘要;控制流图(CFG)定向路径选择;分代搜索

函数摘要[88]、[89]用来描述低级函数的属性,以便高级函数可以重用,减少执行路径的数量。
冗余路径剪枝是为了避免执行那些与前面提到的路径有相同副作用的路径。例如Boonstoppel等[90]提出了一种通过跟踪目标程序的读写操作来检测和丢弃大量冗余路径的技术。
合并不同路径上的状态[91]也可以减少路径搜索空间,但这种方法加重了求解器的负担。
启发式搜索算法则可以在有限的时间内尽可能快地探索出最相关的执行路径。
随机路径选择[92]和自动部分环路摘要[93]在实践中被证明是成功的,主要是因为它们在遇到某些紧环路时避免了卡死,而紧环路可以快速创建新的状态。另一个例子是控制流图(CFG)定向路径选择[94],它利用静态控制流图来引导测试用例生成来探索最近的未覆盖分支。实验表明,这种贪心的方法可以更快地提高覆盖率,实现更高的代码覆盖率。此外,还有分代搜索[38],它会探索每个扩展执行的所有子路径,给它们打分,最后为下一次执行选择得分最高的路径。

Böhme等人[95]提出并实施了几种策略,通过访问更多隐藏在低密度区域的状态,迫使AFL[27]对高密度区域的状态产生更少的输入。
deepfuzzy[96]为执行路径分配了概率,并应用了一种新的搜索启发式,可以有效地将路径爆炸延迟到所测试的二进制文件的更深层。
给定一套现有的测试用例,Zhang等人[97]利用测试用例减少和优先级划分方法来提高种子符号执行的效率,目标是尽可能快地获得增量覆盖。

2)不精确的符号执行:符号执行的不精确主要是由复杂的程序结构(例如,指针)建模、库或系统调用和约束求解引起的。为了使符号执行切实可行,需要在上述区域采用一些简化方法。因此,对于开发人员来说,关键是在可伸缩性和精确度之间找到一个平衡点。
CUTE[98]简化了指针的操作,在处理符号指针变量时只考虑相等和不相等谓词。
在KLEE[92]中,指针被视为数组。
约束求解还添加了大量的约束优化(例如,SAGE使用不相关约束消除、本地约束缓存、翻转计数限制等,以提高生成约束时的内存使用率和速度),甚至是输入语法(例如:Godefroid等人提出了一种通过符号执行直接生成基于输入语法的约束的方法。然后,这些约束的满足性将由一个定制的约束求解器来验证,它也利用输入语法。因此,它可以生成高度结构化的输入)。
为了模糊测试浮点(FP)代码,这也可能导致不精确的符号执行,Godefroid和Kinder[102]结合了对FP指令的轻量级局部路径不敏感的“可能”静态分析和对非FP指令的高精度全程序路径敏感的“必须”动态分析。Fu和Su[103]将测试FP代码的挑战转化为应用无约束规划的机会——在整个搜索空间中计算函数最小点的数学解。他们从FP代码中派生出一个表示函数,它的任何最小点都是一个测试输入,保证执行被测试程序的一个新分支。

3)欠污染:完全忽略数据传输与控制流关联的隐式数据流、数组操作等,就会发生欠污染。如图4所示,在从纯文本到富文本格式的转换过程中,输入变量的值被转移到输出数组中,而不需要直接赋值。因此,如果输入被污染,忽略这个隐式的数据流将导致污染不足。Kang等[44]在解决这一问题上取得了进展。根据他们的实验,所有隐含流的污染传播也会导致不可接受的大的过度污染。因此,他们只关注于图4中所示的完整信息保存隐式流的污染传播

4)过度污染:当未在更细的粒度上实现污染传播时,就会发生过度污染。它会引起污染爆炸和假阳性。Yadegari等人[104]提出了一种实现位级污染传播的方法来缓解这个问题。处理这个问题的另一种方法是使用欠近似值来检查存在的“for-some-path”属性。Godefroid[89]提出了一种新的测试生成方法,其中测试来自有效性证明一阶逻辑公式,而不是像目前大多数方法那样满足量词自由一阶逻辑公式的赋值。有关符号执行和污染分析的详细信息,请参考专业文献[39],[105]。

E. Fuzzing的可扩展性

针对这个问题,一些方法利用了应用程序感知的模糊云服务模糊方法。Rawat等人[108]提出了一种应用程序感知的进化模糊策略,该策略不需要任何应用程序或输入格式的先验知识。为了最大化覆盖范围和探索更深层次的路径,他们利用基于静态和动态分析的控制和数据流特性来推断应用程序的基本属性。
提高可伸缩性的一种方法是减少分析的范围。DiSE[109]结合了两个阶段:静态分析和符号执行。受影响的程序指令集在第一阶段生成。然后,静态分析生成的信息被用来指导符号执行,以仅探索受更改影响的程序的部分,从而潜在地避免大量未受影响的执行路径。
Liang等人[110]提出了Caiipa,这是一种云服务,用于以可伸缩的方式在扩展的移动上下文空间上测试应用程序,并在一组虚拟机和真实设备上实现,这些设备可以模拟移动应用程序的各种上下文组合。移动漏洞发现管道(MVDP)[111]也是一个针对Android和iOS设备的分布式黑盒模糊系统。

VI. TOOLS IN DIFFERENT APPLICATION AREAS

在这里插入图片描述
在这里插入图片描述
1)种子生成与选择:勾:模糊器可以自动生成种子或采用某种种子选择算法。圈: fuzzer提供了一些高质量的种子供测试人员选择(通常是基于突变的fuzzer)。×:种子由测试人员手工采集。/: fuzzer不需要随机的种子(通常是基于语法的fuzzer)。
2)输入验证和覆盖:模糊器利用输入语法或其他知识来生成测试用例,或者采用一些方法来通过输入验证。:模糊器采用了一些方法来缓解输入验证所带来的问题。×:模糊器不使用任何输入信息或方法通过输入验证。
3)处理导致崩溃的测试用例:fuzzer可以自动分析发现的bug,并生成详细的bug报告。: fuzzer可以提供一些有用的信息,如日志文件,以帮助后续的错误分析。×:模糊器只生成诱发碰撞的测试用例。
4)利用运行时信息:模糊器使用运行时信息来指导测试用例的生成。×:模糊器在运行时不使用任何反馈信息。
5) fuzzing的可伸缩性:fuzzer可以有效地测试真实世界的应用程序,并发现了大量的bug。:该模糊器目前还处于实验阶段,并已应用于一些实际应用程序中。×:模糊器只能测试一些实验程序。

A. General Purpose Fuzzers

  1. Peach: Peach[112]是一种知名的通用模糊器,它最常见的目标是驱动程序、文件消费者、网络协议、嵌入式设备、系统等。它是由以下组件构建的:1)预定义的输入格式定义称为桃坑,这是可用的单个坑或组相关坑称为坑包;2)测试通过,可以加权mutators来执行更多的测试用例;3) minset,它有助于减少测试用例覆盖的文件数量。Peach在这个领域扮演着关键的角色,因为它有许多突出的特性,比如威胁检测、开箱即用的模糊定义(Peach Pits)和可扩展的测试选项。然而,Peach也有一些问题(特别是在开源版本中)。一个主要的问题是,使用Peach提供的语法来描述目标文件格式来构建Pitfile非常耗时。eFuzz[113]建立在Peach上,测试基于通信协议DLMS/COSEM(欧洲使用的标准协议)的智能计量设备,以防止可能的故障。Honggfuzz[114]也是基于Peach构建的。
  2. beSTORM: beSTORM[115]是一款商用黑盒fuzzer。它可以用来测试目标应用程序的安全性或检查网络软硬件产品的质量。它不需要源代码,只需要目标程序的二进制文件。beSTORM采取的模糊策略是首先测试可能的、常见的失败诱发区域,然后扩展到一个几乎无限的攻击变化范围;因此,它可以快速交付结果。beSTORM可用于协议、应用、硬件、文件、WIFI、EDSA (embedded device security assurance)等测试。例如,它能够在实现EDSA 402标准的应用程序中发现bug。

B. Fuzzers for Compilers and Interpreters

1)jsfunfuzz[116]是一个基于语法的黑盒模糊器,专为Mozilla的SpiderMonkey JavaScript引擎设计。它是第一个公开可用的JavaScript模糊器。自2007年开发以来,它已经在SpiderMonkey中发现了2000多个bug。它将差分测试与目标应用的详细知识相结合;因此,它可以在不同的JavaScript引擎中有效地发现与正确性相关的bug和触发崩溃的bug。然而,对于每一个新的语言特性,jsfunfuzz都必须调整自己,以响应fuzzing过程中的新特性。
2) Csmith: Csmith由Yang等[117]于2011年提出。它是一个根据C99标准生成具有特定语法的随机C程序的C编译模糊器。它利用随机差异测试[118]来帮助发现由潜在的未定义行为和其他c特定问题引起的正确性错误。Csmith已经被使用多年,在商业和开源C编译器(例如,GNU编译器集合(GCC),低层虚拟机(LLVM))中发现了数百个以前未知的错误。由于它是一个开源项目,关于Csmith的最新信息和版本可以访问[119]。尽管Csmith是一个实用的模糊器,它擅长生成引起错误的测试用例,就像许多其他模糊器一样,它不会根据重要性对发现的bug进行优先级排序。因此,测试人员必须花费大量时间来决定每个bug的新颖性和严重性。
3) LangFuzz:受jsfunfuzz启发,Holler等人[120]于2012年推出了LangFuzz。LangFuzz并不针对特定的语言对象。到目前为止,它已经在JavaScript和超文本预处理器(PHP)上进行了测试。在应用到JavaScript引擎后,LangFuzz在SpiderMonkey[26]中发现了500多个以前不知道的错误。应用于PHP解释器,它还发现了18个可能导致崩溃的新缺陷。LangFuzz使用随机生成和代码突变来创建测试用例,但将突变作为主要技术。它被设计成一种与语言无关的模糊器,但要使它适应一种新的语言需要做一些必要的修改。
4) CLsmith: Lidbury等人[70]利用随机差分测试和等价模输入(EMI)测试来模糊多核编译器,识别并报告了50多个OpenCL编译器bug,这是商业实现中最多的。具体来说,他们在多核环境中采用了随机差分测试,以生成确定性的、通信的、特性丰富的OpenCL内核,并提出并评估了注入死结构代码以实现OpenCL上下文中的EMI测试。这类的其他Fuzzer包括MongoDB的JavaScript Fuzzer,它在两个发布周期中检测到近200个错误[121];Ifuzzer是另一个使用遗传编程的JavaScript解释器fuzzer[122]。

C. Fuzzers for Application Software

  1. SAGE: SAGE[14]是微软开发的知名白盒模糊器。它用于模糊运行在x86平台上的大型读取文件的Windows应用程序(如文档解析器、媒体播放器、图像处理器等)。将圆锥执行与启发式搜索算法相结合,以最大化代码覆盖,SAGE尽力有效地揭示bug。自2008年以来,该工具一直在平均100多台机器/核上持续运行,并自动模糊了微软的几百个应用程序。SAGE是第一个实现白盒模糊技术的模糊器,并能够测试真实世界的应用程序。如今,微软正在推广一个名为Springfield的在线fuzzing项目[123]。它提供了多种方法,包括微软的白盒模糊技术来发现客户上传的二进制程序中的错误。SAGE未来的工作包括改进其搜索方法,提高其符号执行的精度,提高其约束求解的能力,以发现更多的bug[38]。
  2. AFL: AFL[27]是一种著名的代码覆盖指南模糊器。它通过代码检测收集运行时路径覆盖的信息。对于开源应用程序,插装是在编译时引入的,而对于二进制文件,插装是通过修改后的QEMU在运行时引入的[124]。能够探索新的执行路径的测试用例在下一轮的突变中有更多的机会被选择。实验结果表明,AFL在实际用例中,如文件压缩库、常见的图像解析等,可以有效地发现bug。AFL支持C、c++、Objective C或可执行程序,可在类似linux的操作系统上运行。此外,还有一些工作是扩展AFL的应用场景,如TriforceAFL[125],它用于模糊内核系统调用,WinAFL[126],它将AFL移植到Windows,以及ORACLE[127],它使用AFL来模糊某些文件系统。虽然AFL是高效和易于使用,但仍有改进的空间。与许多其他强力fuzzers一样,当实际输入数据被压缩、加密或与校验和捆绑在一起时,AFL提供有限的代码覆盖范围。此外,AFL在处理64位二进制文件时需要更多的时间,并且不直接支持模糊网络服务。
  3. QuickFuzz:QuickFuzz[128]利用Haskell的QuickCheck(著名的基于属性的随机测试库)和Hackage (Haskell社区软件库),以及现成的位级突变fuzzer,为十多种常见文件格式提供自动fuzzer。无需提供外部输入文件集,也无需为所涉及的文件类型开发模型。QuickFuzz混合使用基于语法和基于变异的模糊技术生成无效的输入,以发现目标应用程序中的意外行为。为了测试服务器端软件,Davis等人[129]提出了Node。fz是事件驱动程序的调度模糊器,体现在服务器端Node.js程序中。节点。fz随机干扰Node.js程序的执行,允许Node.js开发人员探索各种可能的调度。这类工作还包括Dfuzzer[130],这是一种D-bus服务的模糊器。为了测试移动应用,近年来出现了一些模糊器,如Droid-FF[131],内存泄漏模糊器[132],DroidFuzzer[133],意图模糊器[134],以及Android应用的Android Ripper MFT工具[135]。

D. Fuzzers for Network Protocols

  1. Sulley: Sulley[136]是一个针对网络协议的开源fuzzing框架。它利用一种基于块的方法来生成单独的“请求”。它为用户构建协议描述提供了大量所需的数据格式。在测试之前,用户应该使用这些格式来定义所有必要的块,这些块将在fuzzing过程中进行变异和合并,以创建新的测试用例。Sulley可以对检测到的故障进行分类,并行工作,并追踪到触发故障的测试用例的唯一序列。然而,它目前没有得到很好的维护。Boofuzz[137]是Sulley的继任者。
  2. TLS- attack: Somorovsky[138]提出了一个评估TLS库安全性的开源框架tlsattack。TLS攻击者允许安全工程师创建自定义的TLS消息流,并通过使用一个简单的接口来测试其库的行为来任意修改消息内容。它成功地在广泛使用的TLS库中发现了几个漏洞,包括OpenSSL、Botan和MatrixSSL。还有一些关于模糊网络协议的研究[139],[140]。t - fuzzy[141]是一种基于模型的模糊器,用于电信协议的鲁棒性测试,Secfuzz[142]用于IKE协议,snoze[143]和KiF[144],[145]用于VOIP/SIP协议。

E. Fuzzers for OS Kernels

  1. Trinity:近年来,Trinity[147]在kernel fuzzing领域得到了广泛的关注。它实现了几个发送系统调用的半智能参数的方法。1)如果一个系统调用期望一个特定的数据类型作为一个参数(例如,描述符),它被传递1;2)如果一个系统调用只接受特定的值作为参数(例如,一个’ flags '字段),它有一个列表,所有的validflags可以被传递;3)如果系统调用只接受一个范围的值,传递给参数的随机值通常符合这个范围。Trinity支持多种架构,包括x86-64、SPARC-64、S390x、S390、PowerPC-64、PowerPC-32、MIPS、IA-64、i386、ARM、Aarch64和Alpha。
  2. Syzkaller: Syzkaller[15]是另一个针对Linux内核的模糊器。它依赖于预定义的模板,这些模板指定每个系统调用的参数域。与Trinity不同,它还利用代码覆盖信息来指导模糊过程。因为Syzkaller结合了覆盖率指导和基于模板的技术,所以它比仅提供系统调用的参数使用模式更好。该工具正在积极开发中,但早期的结果看起来令人印象深刻。
  3. IOCTL Fuzzer: IOCTL Fuzzer[148]是一个用来自动搜索Windows内核驱动漏洞的工具。目前,它支持Windows 7 (x32和x64), 2008 Server, 2003 Server, Vista和XP。如果IOCTL操作符合配置文件中指定的条件,fuzzer将用随机生成的数据替换它的输入字段。
  4. kernel - afl (kAFL): Schumilo等人[149]以一种与操作系统无关、硬件辅助的方式提出了覆盖引导内核fuzzing。它们利用管理程序生成覆盖,并利用英特尔的处理器跟踪技术提供运行代码的控制流信息。他们开发了一个名为kAFL的框架来评估Linux、MacOS和Windows内核组件的可靠性或安全性。在许多崩溃中,他们发现了Linux的ext4驱动程序、MacOS的HFS和APFSfile系统以及Windows的NTFS驱动程序中的几个缺陷。
  5. CAB-FUZZ:为了发现商用现货(COTS)操作系统(os)的漏洞,Kim等人[150]提出了CAB-FUZZ,这是一种实用的concolic测试工具,用于探索最有可能触发bug的相关路径。该模糊器对数组和循环的边界状态进行优先排序,利用真实程序与COTS操作系统的交互构造合适的上下文,在没有调试信息的情况下探索深层复杂的内核状态。它在Windows 7和Windows Server 2008中发现了21个未披露的独特崩溃,包括三个关键漏洞。被发现的漏洞中,有5个已经存在了14年,甚至在Windows XP的初始版本中也可能被触发。

F. Fuzzers for Embedded Devices, Drivers and Components

  1. YMIR: Kim et al.[29]提出了使用api级concolic测试自动生成fuzzing语法,并实现了一个工具(名为YMIR)来自动对ActiveX控件进行白盒fuzzing测试。它采用ActiveX控件作为输入,并将fuzzing语法作为输出。api级的concolic测试在库函数级而不是指令级收集约束,因此可能更快且不太准确。
  2. vUSBf: vUSBf[151]在2014年的Black Hat Europe大会上首次提出。它是一个USB驱动程序的模糊框架。该框架实现了一个基于内核虚拟机(Linux)和QEMU中的USB重定向协议的虚拟USB模糊器。它允许使用简单的XML配置动态定义数百万个测试用例。每个测试都使用唯一的标识标记,因此是可重复的。它可以在Linux内核和设备驱动程序中触发以下错误:空指针解引用、内核分页请求、内核恐慌、错误的页面状态和分段错误。在这一领域还有一些其他的工作,如成本效益高的USB测试框架[152],vdf -一个有针对性的虚拟设备进化模糊器[153]。
    除了上述的模糊器,还有许多其他实用的工具,包括用于perf_event_open()系统调用的perf_fuzzer[154]、用于库的libFuzzer[155]、用于互联网工业系统的Modbus/TCP模糊器[156]、用于I/O总线的模糊器[157]、用于数字证书的模糊器[158]、Gaslight[159]用于内存取证框架等。此外,随着内存错误检测器(例如Clang的AddressSanitizer [83], MemorySanitizer[160]等),模糊器可以被加强,以暴露更多隐藏的错误,而不是浅层的错误。

VII. FUTURE DIRECTIONS

A. 输入验证和覆盖范围

为了模糊这类目标程序,模糊器应该生成能够通过输入验证的测试用例。许多针对这个问题的研究都取得了令人印象深刻的进展,例如[162]针对字符串错误,[163]针对整数错误,[164]针对电子邮件过滤器,[165]针对缓冲区错误。这个领域的开放问题包括处理FP操作(例如,Csmith,著名的C编译器模糊器,不生成FP程序),将现有的技术应用到其他语言(例如,在C语言上应用CLP),等等。此外,Rawat等人[108]证明了通过分析应用程序行为来推断输入属性是可行的和可扩展的策略提高了fuzzing的性能,也是未来该领域研究的一个很有前景的方向。正如我们在V-A节中提到的,尽管TaintScope可以准确地定位校验和点并显著地提高fuzzing的有效性,但仍有改进的空间。首先,它不能处理数字签名和其他安全检查方案。其次,加密的输入数据会极大地影响其有效性。第三,它忽略了控制流的依赖关系,并且没有记录所有的×86指令。这些仍然是悬而未决的问题。

B. 智能模糊测试

智能模糊融合了许多其他程序分析技术[167]、[168],如符号执行、动态污染分析等。虽然这些技术带来了许多好处,但也带来了一些问题:如路径爆炸、凹测试中符号执行不精确以及动态污染分析中的欠污染、过度污染。例如,Dolan-Gavitt等人[169]在八个真实世界的程序中注入了数千个错误,包括bash、tshark和GNU Coreutils。他们评估并发现一个突出的模糊器和一个基于执行的符号错误查找器能够定位一些但不是所有的注入错误。此外,以可扩展和有效的方式进行模糊处理仍然是一个挑战。Bounimova等人[107]提出了大规模运行白盒模糊的关键挑战,其中包括符号执行、约束生成和求解、长时间运行的状态空间搜索、多样性、容错和始终在线的使用。这些问题都值得深入研究。

C. 过滤模糊测试的输出

在软件开发生命周期中,修复错误的时间和预算通常是有限的。因此,开发人员的主要关注点是在这些约束条件下解决那些严重的bug。例如,Podgurski等人[80]提出了对报告的软件故障进行分类的自动化支持,以方便对故障进行排序和诊断故障的原因。Zhang等[170]提出了基于测试用例相似性度量选择测试用例,以探索程序的深层语义。差异测试可能有助于确定评估测试结果的成本[171],[172]。总之,目前很少有研究从较大的模糊输出中过滤出更重要的故障诱导测试用例。该研究方向具有重要的现实意义。

D.种子/输入的生成和选择

模糊处理的结果与种子/输入文件的质量有关。因此,如何选择合适的种子文件以发现更多的bug是一个重要的问题。通过尝试最大化输入域的测试覆盖范围,ART[58][173],[174] -[176]中处理测试用例的方法或算法可能是有用的。例如,Pacheco et al.[53]提出了一种面向反馈的随机测试生成技术,其中执行预先设计的输入,并根据一组契约和过滤器进行检查。执行的结果决定输入是冗余的、非法的、违反约定的,还是对生成更多的输入有用的。然而,在大量的实验中,Arcuri和Briand[59]表明,当考虑到测试用例之间的距离计算时,ART即使在微不足道的问题上也是非常低效的。Classfuzz[177]使用一组预定义的突变操作符对种子类文件进行突变,采用马尔可夫链蒙特卡罗采样来指导突变器的选择,并使用覆盖唯一性作为接受有代表性突变的准则。Shastry等人[178]提出通过静态分析程序控制和数据流,自动构造一个输入字典,并将输入字典提供给现成的模糊器来影响输入生成。如何设计和实现更有效、合理和准确的种子生成和选择算法是一个开放的研究问题。

E.结合不同的检测方法

如第四节所述,黑盒和白盒/灰盒模糊方法各有优缺点。因此,如何结合这些技术来构建一个既有效又高效的模糊器是一个有趣的研究方向。在这方面有一些尝试[124],[179],[48],例如SYMFUZZ[51]利用白盒技术增强了基于黑盒突变的模糊化,该方法有助于根据给定的程序种子对计算出一个最优的突变比。从微观角度来看,SYMFUZZ有两个主要步骤来生成测试用例,每个步骤使用不同的模糊技术,即白盒模糊和黑盒模糊。但从宏观上看,这种方法也可以看作灰盒模糊。由于其黑盒模糊化过程的变异率是在白盒模糊化过程中计算的,所以整个模糊化过程利用了目标程序的部分知识,可以认为是灰盒模糊化。将模糊技术与其它测试技术相结合也是一个有趣的研究方向。Chen等人[180]报道了变形测试[181]-[183],这是一种相对较新的测试方法,它观察多个程序执行的输入和输出之间的关系,在真实世界的关键应用程序中检测到以前未知的错误,表明使用不同的视角和结合多种方法可以帮助软件测试实现更高的可靠性或安全性。Garn和Simos[184]展示了一种利用组合测试和模糊的综合方法对Linux内核系统调用接口的适用性。

F.Fuzzing结合其他技术

模糊器受到测试覆盖范围和合适测试用例可用性的限制。由于静态分析可以从一些模糊发现的程序失败开始,对易受攻击的代码模式进行更广泛的搜索,Shastry等人[185]实现了一个简单但有效的匹配排序算法,该算法使用测试覆盖数据将注意力集中在包含未测试代码的匹配上,并证明静态分析可以有效地补充模糊。静态分析技术,如符号执行和控制/数据流分析,可以为模糊处理提供有用的结构信息[186];然而,fuzzing的符号执行有一些限制,因此留下了一些开放的问题:
1)只检查通用属性,没有发现许多偏离特定行为的情况;2)许多程序不能完全服从符号执行,因为它们产生了硬约束,使得程序的某些部分仍然未被发现[187]。Havrikov[188]提出了一种组合方法,通过该方法,模糊可以从不同的轻量级分析中获益。分析利用了目标程序之外的多个信息源,例如输入和执行(例如,以扩展上下文无关语法的形式描述目标输入格式)或硬件计数器。
机器学习技术有助于自动生成基于语法的模糊处理的输入语法[189]。优化理论也可以在模糊中建立有效的搜索策略[83],[190],[191]。[122]、[192]和[193]使用遗传编程或算法来引导它们的模糊器。Dai等人[194]提出了一种新颖的UI fuzzing技术,针对运行的应用程序,可以执行不同的执行路径,这种方法需要测试人员建立一个全面的网络概要文件。我们相信,现有的组合方法和利用其他技术与模糊仍有一定的改进空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

席八

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值