TSE2019-The Art, Science, and Engineering of Fuzzing: A Survey

摘要— 在当今可用的众多软件测试技术中,模糊测试由于其概念简单、部署门槛低以及发现真实世界软件漏洞的大量经验证据而仍然非常受欢迎。在较高级别上,模糊测试是指重复运行程序的过程,生成的输入可能在语法上或语义上格式不正确。虽然近年来,研究人员和从业者都投入了大量不同的精力来改进fuzzing,但这种工作的激增也使得很难获得全面而一致的模糊测试视图。为了帮助保持和使大量的模糊文献具有连贯性,本文提出了一个统一的,通用的模糊化模型以及当前模糊文献的分类法。我们通过调查使现代模糊器有效的艺术,科学和工程方面的相关文献和创新,有条不紊地探索模型模糊器每个阶段的设计决策。

1介绍

不幸的是,研究人员和从业人员在模糊处理方面的工作激增,也预示着进展受阻。例如,对一些fuzzer的描述并不超出其源代码和手册页面。因此,随着时间的推移,很容易失去对这些模糊器的设计决策和潜在重要调整的跟踪。此外,在各种模糊器使用的术语中有一个可观察到的碎片。例如,AFL[243]使用术语“测试用例最小化”来表示一种减少崩溃输入大小的技术,而在funfuzz中,同样的技术被称为“测试用例缩减”[195]。与此同时,BFF[52]包含了一种听起来类似的技术,称为“崩溃最小化”,这是一种寻求最小化崩溃输入与其原始种子文件之间的位数差异的技术,与减少输入大小无关。我们认为这种碎片化使得模糊知识的发现和传播变得困难,这可能会严重阻碍模糊研究的长远发展。
由于上述原因,我们认为现在是巩固和提炼模糊处理大量进展的最佳时机,其中许多进展发生在2007-2008年出版的三本关于该主题的贸易书籍[82]、[212]、[214]之后。
当我们试图统一这一场时,我们将从§2开始提出我们的模糊术语和模糊的统一模型。保持正确的目的,我们的术语选择密切反映当前的主要用法,和我们的模型fuzzer(算法1,p。3)设计,以适应大量的侦察任务作为当前起毛的分类法分类文献(图1,p . 5)。使用此设置,然后,我们将在§3 -§7中探讨模型模糊器的每两个阶段,并在表1 (p. 6)中详细概述主要的模糊器。在每个阶段,我们将调查相关文献,以解释设计选择,讨论重要的权衡,并强调了许多了不起的工程努力,帮助现代的fuzzer有效地完成它们的任务。

2系统、分类和测试程序

2.1模糊和模糊测试

模糊测试术语的6个定义

2.2论文选择标准

论文选择标准:2008年1月至2019年2月的4个主要安全会议和3个主要软件工程会议的最新会议记录中包括所有关于fuzzing的出版物。(前者包括(i) ACM计算机和通信安全会议(CCS), (ii) IEEE安全与隐私研讨会(标普),(iii)网络和分布式系统安全研讨会(NDSS)和(iv) USENIX安全研讨会(USEC);后者包括(i) ACM软件过程基金会国际研讨会 (FSE)(ii) IEEE/ACM自动化软件工程国际会议(ASE); (iii)软件工程国际会议(ICSE)。对于出现在其他场合或媒介中的作品,我们基于自己对其相关性的判断将其纳入。)

2.3模糊测试算法

模糊测试算法
在算法1中,我们提出了一个用于模糊测试的通用算法,我们想象它已经在模型模糊器中实现了。它足够通用,可以修改现有的模糊测试技术,包括 § 2.4 中定义的黑框、灰盒和白盒模糊测试。算法 1 采用一组模糊配置 C 和超时t限制作为输入,并输出一组已发现的错误 B。它由两部分组成。第一部分是PREPROCESS函数,它在模糊运动开始时执行。第二部分是环路内的五个函数的系列:SCHEDULE,INPUTGEN,INPUTEVAL, CONFUPDATE,和 CONTINUE.此循环的每次执行称为模糊执行,每次 INPUTEVAL 在测试用例上执行 PUT 时称为模糊运行。请注意,某些模糊测试程序不会实现所有五个函数。
在这里插入图片描述
用户提供一组模糊配置作为输入,并返回一组可能修改过的模糊配置。根据模糊算法的不同,PREPROCESS可以执行各种操作,比如将工具代码插入put,或者度量种子文件的执行速度。参见§3。
在这里插入图片描述

2.4模糊分类

黑盒,白盒,灰盒

2.5 Fuzzer谱系和概述

图1(第5页)按时间顺序展示了我们对现有模糊器的分类。 从米勒等人的开创性工作开始。 [152],我们手动选择了流行的模糊器,这些模糊器要么出现在大型会议上,要么获得了超过100个GitHub星星,并以图表的形式显示了它们的关系。黑盒模糊器在图的左半部分,灰色和白盒模糊器在图的右半部分。 此外,根据PUT使用的输入类型将模糊器细分:文件,网络,UI,Web,内核I / O或线程(对于并发模糊器)
在这里插入图片描述

表1(第6页)详细介绍了图1中最著名的模糊器所使用的技术。由于空间限制,我们不得不省略图1中的某些模糊器。 每个模糊器都是基于其对模型模糊器的五个功能的实现进行总结的,而其他部分则提供了有关该模糊器的其他详细信息。 我们在下面的每一列中描述了属性。
在这里插入图片描述
相应的 模糊测试 器派生自 AFL,它更改了这部分模糊测试算法。

3 预处理

预处理通常是检测被测程序,包括插桩,去除冗余配置(种子选择),修剪种子,生成驱动程序,还有准备生成输入的模型。

3.1插桩

白盒和灰盒fuzzer可以通过插桩获得执行反馈或者执行时的内存镜像,获取信息的多少取决于fuzzer的类型。除了插桩之外,通过指令流和API序列也可以获得PUT的内部信息。但相比较而言,插桩能够获得更好的反馈信息。插桩分为动态插桩和静态插桩。静态插桩发生在编译之前,PREPROCESS这个阶段,也就是在PUT运行之前,而动态插桩则在程序运行的时候发生,也就是每个INPUTEVAL阶段。因此,静态插桩相较于动态插桩有更优的开销,而动态插桩则更加容易对DLL进行插桩。除了基于源码的插桩,还有基于二进制文件的插桩,即未知源码的插桩技术。常见的动态插桩工具有DynInst 、Dynamo、RIOPIN、Valgrind、QEMU等。

3.1.1执行反馈

通过反馈来进化测试用例。

AFL使用bit vector来存储边覆盖率,这会导致路径碰撞。(可能的意思是,两条执行路径有交集)
CollAFL通过路径敏感哈希函数,来解决路径碰撞问题。
LibFuzzer和Syzkaller使用节点覆盖率反馈
Honggfuzz允许使用者选择执行的反馈方式。

3.1.2线程调度

现有的工作证明,通过显式地控制线程的调度方式,插桩,随机显示的调用线程,可以有效的触发竞争条件。

3.1.3内存模糊测试

在处理启动时间较长或者有分析大程序的部分功能的需求的情况下,每次fuzzing都要启动一遍程序的话效率很低,并且会带来不必要的开销,例如GUI程序在接收输入之前通常需要很多秒的处理时间,网络应用中客户端和服务器的交互很频繁。一种可行的解决方案可以通过拍摄启动后快照的方法来对这种类型的程序fuzzing,这种方法称为in-memory fuzzing(e.g. GRR)。

AFL采用类似于in-memory Fuzzing的做法,使用一个fork server来避免启动PUT所需要的开销。部分 fuzzer采用in-memory API fuzzing,这种技术不需要在恢复PUT状态的情况下执行in-memory fuzzing(e.g. AFL persistent mode,重复调用一个函数)。
缺点:

  1. 主要依赖于被测程序的入口函数,这种函数难以寻找
  2. 难以构造这样的输入能够触发bug或者crash,可能无法复现
  3. 忽略了多函数调用之间的作用

3.2种子选择

如何减小种子池大小的问题称为Seed Selection。
找到最小的种子集,以使覆盖率(例如节点覆盖率)最大化,此过程称为计算最小集(minset)。
这一步可为CONFUPDATE的一部分。

模糊测试使用各种不同的覆盖率指标。 AFL的最小集基于分支覆盖率,每个分支上都有一个对数计数器。 该决定的基本原理是仅在分支数量的数量级不同时才允许它们被认为是不同的。 Honggfuzz [204]根据已执行的指令,已执行的分支和唯一的基本块的数量来计算覆盖率。 此度量标准允许模糊器将更长的执行添加到最小集,这有助于发现拒绝服务漏洞或性能问题。

3.3种子修剪

减小种子的大小,减少内存开销,提升吞吐率。

AFL使用其代码覆盖率检测来迭代删除种子的一部分
优先选择小而非随机种子。
静态分析保留依赖关系时扩展系统调用减少种子大小。

3.4准备驱动程序

对库和内核不方便直接测试,准备驱动程序。

4 调度

调度意味着为下一个模糊迭代选择一个模糊配置。

对于BFF和AFLFast,其成功的主要原因在于创新的调度算法。

4.1 模糊配置调度(FCS)问题

希望选择的配置可以找到独特的bug或者更大的代码覆盖率。
目标:分析当前可用并选择结果最有利信息
冲突
探索:收集更准确信息以告知未来决策
利用:模糊当前会导致更有利配置
依据:
当前的fuzz configuration集
当前的时间开销
总共的时间开销预算

4.2 黑盒的FCS算法

黑盒fuzzer的FCS算法所能使用的唯一信息就是使用给定配置所得到的fuzz结果,包括crash、bug的数量和时间开销。利用这种信息的方法的自然的想法就是优先选择具有更高成功率(更多的bug或者crash)的配置。使用这种scheduling算法替代均匀采样(uniform-sampling)之后,在CERT BFF Black-box fuzzer超过500万次的运行中发现了85%的新增crash。
这种算法得到了多方面的改进,并在相同的时间内,与现有的BFF相比,获得了1.5倍的效果提升:
伯努利->未知权值的加权券回收WCCP/UW:假设每个配置都有最终成功概率,并随时间推移学习,后者在概率衰减时非法保持一个上限
Multi-armed bandit(MAB)。多武装强盗MAB:精确利用尚未衰减的配置。
标准化成功概率:更快的fuzz收集bug更多或更快减少其未来成功的上限
重新定义了一个模糊迭代,从运行固定数量的模糊运行到运行固定的时间,进一步剥夺了较慢的配置。

4.3 灰盒的FCS算法

灰盒fuzzer的FCS算法所能使用的信息更为丰富,除去黑盒fuzzer所能获取的信息之外,灰盒fuzzer还能获取到覆盖率。
AFL使用遗传算法EA,EA维护一代configuration,每一个都有一些适应值。EA选择适当的配置并且对它们进行扰动和重组来产生后代,后代中的部分会成为新的configuration。使用这种算法的假设前提是遗传产生的新的configuration更加适合产生bug或者crash。
为了理解在FCS的情景下EA算法是如何使用的,需要定义如下三点:
1.什么会使得一个configuration适合?
时间开销更小或者大小更小
2.如何选择configuration
AFL维护一个循环队列,从循环队列中选择
3.选择的configuration’如何使用
使用选定的configuration运行固定次数
AFLFast就是根据以上三方面对AFL的性能进行改进的:
1.修改配置、适应值设置和选择,优先探索新的和罕见的路径
(1) 执行同一控制流的配置,选择更少被选择的配置
(2) 如果(1)存在冲突,则选择对应执行路径执行次数最少的配置
2.放弃round-robin(轮询调度)改为通过执行相同路径的生成输入的数量来标准化能量,从而促进对不太常见的模糊配置的探索。
3.使用一个configuration进行fuzzing的次数不再是固定的,次数取决于power schedule
每一个configuration都会有一个相同的初始energy,初始的energy都很小,这是为了保证每条路径都有机会被执行(exploration)。energy的增长是指数级的,这是为了保证最有可能导致bug或者crash的configuration得到充分的exploitation。
优点是快速检查所有新添加的种子。
AFLGo:对AFLFast的优先级分布进行修改,使得其能够针对特定的程序地址
Hawkeye:通过在种子调度和输入生成中利用静态分析来进一步改善定向模糊。
FairFuzz:通过为每对种子和一根稀有分枝使用突变面具来指导稀有分枝的运动。
QTEP:使用静态分析来推断二进制文件的哪个部分更“错误”,并对覆盖它们的配置进行优先级排序。

5 输入生成

分为两种:基于模型生成的模糊测试器,基于突变的模糊测试器。

5.1 基于模型的模糊测试器

基于模型的模糊器基于描述给定PUT可以接受的输入或执行的给定模型来生成测试用例,例如精确表征输入格式的语法或不太精确的约束(例如标识文件类型的魔术值)。

5.1.1预定义的模型

Peach, Protos, Dharma等: 允许用户指定输入语法
Autodafe, Sulley, SPIKE, SPIKEfile, LibFuzzer:有API能够让用户创建自己的input models
Travor: 允许EBNF(Extended Backus-Naur form)语法的输入说明
PROTOS, SNOOZE, KiF, TFuzz: 用户需要指定network protocal specification
Kernel API fuzzers:定义了system call templates,指定系统调用的参数的类型和个数
Nautilus: general-purpose; grammar-based input; grammar-based seed trimming for general-purpose fuzzing
cross_fuzz,DOMfuzz:随机 Document Object Model Objects(DOM)对象
jsfunfuzz:生成随机但语法正确的JavaScript代码
QuickFuzz:在生成测试用例时描述文件格式的Haskell库
Frankencerts,TLS-Attacker,tlsfuzzer,llfuzzer:根据特定网络协议(如TLS和NFC)的模型设计
Dewey等: constraint logic programming,生成不仅语法(grammatically)正确而且语义(semantically)正确的test case
LangFuzz: 解析作为输入提供的一组种子生成代码片段。然后它随机地结合片段,并将种子与片段进行变异,以生成测试用例。已被应用于 JavaScript and PHP
BlendFuzz: 和LangFuzz类似,只不过针对的是XML和正则表达式的解析

5.1.2推断模型

尽管有大量的有关于输入格式自动化和协议逆向的研究,仍然只有一小部分fuzzer使用到了这些技术。和插桩技术类似,模型推断可能会出现在PREPROCESS或者CONFUPDATE两个过程。
Model Inference in PREPROCESS
TestMiner:在待测程序中搜索例如常量之类的数据,用于预测可行的inputs
Skyfire:使用数据驱动(data-driven)的方法推断一个概率上下文敏感的语法(probabilitistic context-sensitive grammar),
然后使用这种语法产生一个新的seed的集合。关注点在于产生语义合理的输入。
IMF:通过分析系统的API日志,学习一个kernel API model,然后使用这个模型产生调用某个API序列的C语言代码
CodeAlchemist:分解JavaScript 代码成“code bricks”,然后计算组合约束(assembly constraints),
组合约束条件决定独立的code brick是否可以被组合到一起来产生语义合法的测试用例。
约束条件的计算包括静态分析和动态分析。
Neural and Learn&Fuzz:使用神经网络机器学习算法从一个给定的测试文件的集合学习一个模型,然后使用这个模型产生测试用例。
Liu et al.:与Neural and Learn&Fuzz类似,针对文本输入
Model Inference in CONFUPDATE
PULSAR:从一系列捕获PUT产生的网络包中推断出一个网络协议模型,然后使用这个模型进行fuzz。PULSAR在内部构造了一个状态机,
将message token映射到一个状态。这种映射关系之后会被用于生成覆盖状态机中更多状态的测试用例。
Doupe et al:提出了一种通过观察I/O行为推断出web服务的状态机,然后使用这个模型去扫描web漏洞。
Ruiter et al.:与Doupe et al工作过程类似,基于LearnLib实现,针对TLS协议
GLADE:从I/O样例集合中总结出上下文无关(context-free)的语法,然后使用这种语法对PUT进行fuzz
go-fuzz:灰盒fuzzer,根据添加到seed pool的seed建立一个模型,这个模型会被用于产生新的输入
Shen等人:使用神经网络来解决困难的分支条件

5.1.3编码器模型

文件有一定的格式。打开特定格式的文件,需要对应的软件。如果我们想测试处理mp4,.xls等文件格式的程序,我们需要将文件格式作为一种隐式模型。
MutaGen:利用包含在编码器程序中的隐式模型来生成新的测试用例。与大多数基于突变的模糊器不同的是,它们会突变一个现有的测试用例(见§5.2)来生成测试用例,MutaGen会突变编码器程序。具体来说,为了生成一个新的测试用例,MutaGen计算编码器程序的一个动态程序切片并运行它。其基本思想是,程序切片将稍微改变编码器程序的行为,从而产生稍微不规范的测试用例。

5.2 无模型(基于突变)的模糊器

通过仅更改有效文件的一小部分,通常可以生成一个新的测试用例,该用例大部分是有效的,但也包含异常值以触发PUT崩溃。下面是各种突变种子的方法。

5.2.1位翻转

位翻转:固定数量;突变率随机数量;指数比例突变率集合并分配更多迭代
SymFuzz[55]的模糊性能对变异率非常敏感,没有一个单一的变异率适用于所有put。幸运的是,有几种方法可以设置一个好的突变比例。
BFF[52]和FOE[53]对每个种子使用指数比例的突变比率集,并对被证明具有统计有效性的比率分配更多的迭代[111]。
SymFuzz利用白盒程序分析来推断每个种子的良好突变比率。

算术突变
字节序列视为整数运算;突变影响尽量小,范围可控
AFL[243]和honggfuzz[213]包含另一种突变操作,它们将选定的字节序列视为整数,并对该值执行简单的算术。然后使用计算出的值替换所选的字节序列。关键的直觉是用一个小数字来限制突变的影响。例如,AFL可以从种子中选择一个4字节的值,并将该值作为整数i处理。然后它将种子中的值替换为i±r,其中r是一个随机生成的小整数。r的范围取决于模糊器,通常是用户可配置的。在AFL中,默认范围为0≤r < 35。

基于块的突变
随机生成块插入种子随机位置
种子中随机删除块
随机块替换为随机值
随机乱序
随机添加块
种子内随机取块插入/替换另一种子随机块

基于字典的变异
使用一组预定义的值,对突变具有潜在的重要语义意义。
AFL[243]、honggfuzz[213]和LibFuzzer[6]在修改整数时使用0、−1和1等值。
Radamsa[106]使用Unicode字符串,
GPF[1]使用格式化字符,如%x和%s来改变字符串[58]。

5.3 白盒模糊测试

并不是所有的白盒模糊测试器,都是动态符号执行器。

动态符号执行
相比较于灰盒或者黑盒方法而言,动态符号执行是很慢的,这是由于它需要分析PUT的每一条指令并插桩。为了解决开销过大的问题,一种缩小动态符号执行范畴的通用策略被提出:让用户确定代码中不感兴趣的部分或者感兴趣的片段、交替使用conclic testing和灰盒fuzzing。

Driller, Cyberdyne: 交替使用conclic testing和灰盒fuzzing
QSYM: 通过快速符号执行引擎提高了conclic testing和grey-box fuzzing的性能
DigFuzz: 用灰盒测试确定每个分支执行概率,让它的白盒模糊聚焦于被认为是灰盒模糊最具挑战性的路径

引导性模糊测试
第一步,进行昂贵的程序分析以获取有关PUT的有用信息。第二步,在先前分析的指导下生成测试用例。

TaintScope通过细粒度的污点分析,找到输入中经常出现的字节。
Dowser[101]在编译期间执行静态分析,以根据启发式找到可能包含bug的循环。具体来说,它查找包含指针解引用的循环。然后通过污染分析计算输入字节和候选循环之间的关系。最后,Dowser运行动态符号执行,同时只将关键字节作为符号执行,从而提高了性能。
VUzzer [176]和GRT [145]利用静态和动态分析技术从PUT中提取控制和数据流特征,并使用它们来指导输入生成
Angora[59]和RedQueen[26]通过首先使用昂贵的仪器运行每个种子,并使用这些信息生成使用更轻的仪器运行的输入来降低分析成本。Angora通过使用污点分析将每个路径约束关联到相应的字节,对“热字节”思想进行了改进。然后在梯度下降算法的启发下执行搜索,以引导其突变解决这些约束。另一方面,RedQueen试图检测PUT中是如何使用输入的,方法是检测所有的比较,并寻找它们的操作数与给定输入之间的对应关系。一旦找到匹配,就可以用它来解决约束。

被测试程序变异
fuzzing所面临的一个实际的挑战就是绕过检验和的验证。例如,当一个PUT在解析输入之前计算它的校验和,很多测试用例将不会被PUT所接受。
TaintScope:感知校验和,污点分析技术识别校验和检验的指令,对PUT打补丁来绕过校验和的验证
Caballero et al.:拼接动态符号执行,这种技术能够在存在checksum的情况下生成测试样例。
T-Fuzz:渗透各种条件分支,找到能够被修改掉但是不会影响程序逻辑的branches(Non-Critical Checks)非关键检查
当停止找到新paths的时候,程序会找到一个NCC,在目标程序中转换它
对被修改后的程序再执行测试,如果发生崩溃,用符号执行去跑原版PUT。

6 输入评估

在生成输入后,fuzzer对输入执行PUT,并决定如何处理结果执行。这个过程称为输入评估。

6.1 Bug Oracles

程序可能执行出错(非人为设定意愿的方式执行),但是并没有crash。为了减轻这种情况,研究人员提出了各种有效的程序转换,以检测不安全或有害的程序行为并中止程序。 这些通常被称为sanitizers。
内存和类型安全
内存安全错误可以分为两类:空间错误和时间错误。空间性的内存错误通常在指针在对象之外被间接引用指向它原本指向的对象之外的情况下,比如缓冲区溢出;而时间性的内存通常发生在指针失效后被引用,比如use-after-free的漏洞。
ASan: 快速的内存错误检测器。在编译时插桩,然后维护一个shadow memory,每当一块内存要被解引用的时候就去做有效性检查
MEDS: 维护objects之间或者内部不可以访问的memory red zones,如果被访问了,那很可能时memory crash
SoftBounds/CETS: 在编译时插桩,为每个pointer都结合边界和时间信息,这样就从理论上能够探测到所有的内存问题
CaVer, TypeScan, HexType等: 在编译时插桩,以便检测c++类型转换中的错误转换。错误的类型转换发生在对象被转换为不兼容的类型时,例如基类的对象被转换为派生类型时。
Control Flow Integrity: 检测运行时原本不应当出现的control flow transition,这样就能找到不合法地篡改了程序本身的测试用例

未定义的行为
C语言一类的编程语言有的时候会留下未定义行为。有时程序在不同编译器或者平台上的行为会产生不一致,很多因素都会影响一个编译器实现undefined behaviors,优化设置、架构、编译器甚至是编译器的版本都可能会导致crash或者bug。
Memory Sanitizer: 编译时插桩,使用影子内存用于检测C和C++中使用未初始化memory导致的undefined behaviors
Undefined Behavior Sanitizer: 在编译时修改程序,以此检测未定义行为。UBSan能够检测多种未定义的行为,比如使用misaligned pointers, 除0,解引用空指针,整数overflows
Thread Sanitizer: 编译时修改程序,检测数据竞争,平衡精确度和性能开销。

输入验证
测试输入验证漏洞(如XSS(跨站点脚本)和SQL注入漏洞)是一个具有挑战性的问题。它需要理解支持web浏览器和数据库引擎的非常复杂的解析器的行为。
KameleonFuzz: 用真实的web browser解析测试用例,提取DOM树,并将其与手工指定的表示成功攻击的模式比较来检测XSS attacks
μ4SQLi: 使用了一个数据库代理来拦截目标web应用程序和数据库之间的通信,以检测输入是否触发了有害行为。

语义差异
语义错误通常是通过一种称为差异测试的技术发现的,该技术比较相似(但不相同)程序的行为。
Jung等人[122]引入了黑盒差分模糊测试,该测试在一个程序上使用多个输入的差分测试,将PUT的输入突变映射到输出。这些映射用于标识信息泄漏。

6.2 执行优化

跳过PUT的载入时间能够减少时间开销。
AFL:forl-server,允许每个新的模糊迭代从一个已经初始化的进程中派生。
in-memory fuzzing
Xu et al.:设计一个替代fork()的新系统调用,进一步降低了迭代的成本。

6.3 分流

分流是分析和报告导致违反策略的测试用例的过程。 分类可以分为三个步骤:重复数据删除,优先级划分和测试用例最小化。
重复数据删除
触发相同的错误,删除对应的测试用例,保留一个。
当前,实践中使用了三种主要的重复数据删除实现:堆栈回溯哈希,基于coverage的重复数据删除和语义感知的重复数据删除
堆栈反向跟踪哈希:自动工具会在崩溃时记录堆栈回溯,并根据回溯的内容分配堆栈散列。一些堆栈回溯仅仅hash函数名和地址,但是另外一些可能会hash函数名和偏移或者行号。一些实现有两种hash:major hash和minor hash。major hash将不相似的crash聚集在一起,minor hash则更为精确。堆栈回溯哈希的基本假设是,类似的崩溃是由类似的bug引起的,反之亦然。然而,据我们所知,这一假设从未被直接验证过。我们有理由怀疑它的真实性:一些崩溃并没有发生在导致崩溃的代码附近。
基于覆盖率的重复数据删除:AFL是一种流行的灰盒模糊算法,它使用一种高效的源代码工具来记录PUT每次执行的边缘覆盖率,并测量每个边缘的粗命中率。AFL认为,如果(i)事故覆盖了以前未见过的边缘,或(ii)事故没有覆盖所有14起早期事故中存在的边缘,则该事故是唯一的。
语义感知的重复数据删除:RETracer通过分析崩溃转储(核心转储)来检查是哪个指针导致了崩溃,并递归地确定是哪个指令给它分配了错误的值。它最终会找到一个具有最大帧级的函数,并“责怪”该函数。然后使用受责备的函数来群集崩溃。Van Tonder等人[222]利用自动程序修复[137]技术将崩溃的测试用例映射为程序语义变化的函数。此更改近似于修复bug的根本原因。

优先级和可利用性
优先级,是根据其严重性和唯一性对违规测试用例进行排名或分组的过程。模糊测试传统上用于发现内存漏洞,在这种情况下,优先级划分更广为人知的是确定崩溃的可利用性。它非正式地描述了针对测试用例暴露的漏洞开发实际漏洞的可能性。防御者和攻击者都对可利用的错误感兴趣。
严重性与唯一性进行排序分组,判断为可利用性
简化污染分析搭建:可利用>可能可利用>未知>不可利用
!exploitable:使用了几个启发式算法,并搭配了一个简化的污点分析

测试用例最小化
保证触发冲突的前提下尽可能减小测试用例的大小。test case minimization and seed trimming的区别在于minimizer可以利用bug oracle。
BFF:尽可能减小和原种子不同的bit的个数
AFL:适时设置字节为0,减短测试用例的长度
Lithium:指数递减大小删除相邻行或字节块
其他非专门为fuzzing设计的:
format agnostic techniques,e.g. delta debugging
specialized techniques for specific formats, e.g. CReduce for C/C++ files

7 配置更新

黑盒模型所能利用的信息太少,configuration基本不更新;灰盒和白盒模糊测试的特点是它们更复杂的CONFUPDATE函数实现,这允许它们合并新的模糊配置或删除可能已被取代的旧模糊配置。白盒基本上每运行一个新的测试用例都会更新configuration。

7.1 种子库更新

EA最重要的步骤是添加一个新的配置到配置集,大多数基于EA的模糊器使用节点或分支覆盖作为适应度函数。EA模糊器中的一种常见策略是细化适应度函数,以便它能够检测出更细微和更细粒度的改进指标。
AFL通过记录一个分支被取走的次数,改进了适应度函数的定义。
STADS提出了一个受生态学启发的统计框架,以估计如果模糊运动继续,将发现多少新的配置。
另一个常见的策略是度量在计算复杂分支条件时满足的条件的比例
lafi - intel简单地将多字节比较分解为几个分支,这允许它检测新种子何时通过中间字节比较。
LibFuzzer , honggfuzz , go-fuzz,和Steelix仪器都进行比较,并添加任何在与种子池比较中取得进展的测试用例。类似的想法也作为clang的独立工具模块发布。
Steelix检查哪些输入偏移量会影响比较指令。
Angora通过考虑每个分支的调用上下文,提高了AFL的适应度标准。
DeepXplore使用“神经元覆盖”作为适应度函数,使模糊适应神经网络测试。
VUzzer适应度函数依赖于自定义程序分析的结果,该结果确定每个基本块的权重。

7.2维护Minset

解决产生配置过多的问题,最简单的办法是维持一个最大化覆盖率的Minset。

https://blog.csdn.net/qq_40398985/article/details/103585735
https://blog.csdn.net/qq_41513009/article/details/121039888
https://blog.csdn.net/sinat_38816924/article/details/114264772

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值