FuzzGuard

directed grey-box fuzzing (DGF)

与基于覆盖的模糊测试(其目标是增加代码覆盖范围以触发更多错误)不同,DGF旨在检查一段潜在的错误代码(例如,字符串操作)是否确实包含错误。

本文提出了一种基于深度学习的方法来在执行目标程序之前预测输入的可达性(即是否错过目标),以帮助DGF筛选出无法到达的输入以提高模糊测试的性能。为了运用DGF进行深度学习,本文设计了一套新技术(例如,step-forwarding方法,代表性数据选择)来解决标签数据不平衡和训练过程中时间不足的问题。此外,本文实现了提出的称为FuzzGuard的方法,并为其配备了最新的DGF(例如AFLGo)。 对45个实际漏洞的评估表明,FuzzGuard将vanilla AFLGo的模糊处理效率提高到了17.1倍。

Introduction

directed fuzzing 导向fuzz

模糊测试是一种自动程序测试技术,通常分为两类:基于覆盖率的模糊测试和定向模糊测试。 前者的目标是实现较高的代码覆盖率,希望触发更多崩溃。 而定向模糊测试旨在检查给定的潜在错误代码是否确实包含错误。例如AFLGo,SemFuzz和Hawkeye,都是已有的导向fuzzer。

定向模糊测试(DGF)

众所周知,随机输入不太可能到达错误代码,更不用说触发错误了。 因此,大多数工具都会对目标程序进行插桩,以观察运行时信息并利用该信息生成可能到达错误代码的输入。

理想的DGF应该生成所有可以到达错误代码的输入。 不幸的是,在实际情况下,大量生成的输入可能会错过目标,特别是当buggy code嵌入受许多(例如数千个)约束的代码中时。面对这种情况,各种技术(例如,基于退火的Power Schedules)被设计为生成可到达的输入。 但是,即使对于最先进的DGF工具(例如AFLGo),无法访问的输入比例仍然很高。 根据本文使用AFLGo进行的评估,平均而言,超过91.7%的输入无法到达错误代码。

如此大量的无法到达的输入会在模糊测试过程中浪费大量时间。 理论上,传统的程序分析方法(例如符号执行)可以使用目标程序中所有分支的约束来推断输入的执行结果。 但是,解决约束所花费的时间将随着约束复杂性的增加而急剧增加。

Challenges

C1

Lack of balanced labeled data.训练深度学习模型需要均衡的标签数据,但是fuzzing过程中的输入是不平衡的。尤其是在模糊测试的早期,甚至没有可到达buggy code的输入。没有均衡的标记数据,训练后的模型将容易出现过拟合的情况。

C2

新生成的可及输入看起来可能与训练集中的可及输入完全不同,从而使训练后的模型无法预测新输入的可及性。新输入可能会通过以前从未见过的不同执行路径到达错误代码。 因此,仅沿一条执行路径使用输入来训练模型可能无法正确预测新输入的可达性。

C3

Efficiency。在训练传统模式识别模型的任务中,在训练上花费的时间没有严格限制。 但是,在模糊测试过程中,如果花费在训练模型和预测输入的可达性上的时间大于花费在执行有输入程序上的时间,那么进行预测是没有用的。

FuzzGuard

FuzzGuard分三个阶段工作:模型初始化,模型预测和模型更新。

  1. 在第一阶段,模糊器生成各种输入,并使用它们运行目标程序,以检查是否触发了错误。 同时,FuzzGuard保存输入及其可达性,并使用标记的数据训练初始模型,该数据可能不平衡(C1)。 为了解决这个问题,本文设计了一种step-forward的方法:选择buggy code的主导者(称为“主导节点” )作为中间阶段目标,然后让执行首先到达主导节点 。 这样,就可以更早地获得平衡数据,以训练仅针对主导节点的模型,从而将执行时间降至最低。
  2. 在第二阶段中,在Fuzzer生成大量新输入之后,FuzzGuard利用该模型预测每个输入的可达性。 如C2中所述,训练后的模型可能不适用于新生成的输入。 为了解决这个问题,本文设计了一种有代表性的数据选择方法来对每一轮突变中的训练数据进行采样,从而最大程度地减少了采样数据的数量,从而提高了效率。
  3. 在第三阶段,FuzzGuard使用第二阶段收集的标记数据更新模型,以提高其准确性。本文通过谨慎选择更新时间来应对挑战C3。以前的模糊研究主要集中在生成各种输入,覆盖更多的代码行(CGF)或获取错误的代码(DGF)。 设计了输入上的各种变异策略。 相比之下,本文的研究并未直接对输入进行突变(本文依赖于当前的突变策略,例如AFLGo),而是筛选出无法到达的输入。 这样,DGF不需要使用无法到达的输入(肯定无法触发目标错误)来运行目标程序,从而提高了整体效率。

本文基于AFLGo(一个开源的DGF)实现了FuzzGuard。本文在获取到的性能和漏洞结果外,还发现模糊器生成的输入越多,FuzzGuard的性能就越好。此外,如果目标节点更早达到平衡状态,则可以节省更多时间。

Motivation

当前的DGF旨在生成可能到达特定错误代码的输入,并进一步期望触发错误。在模糊测试过程中,很多输入最终都无法到达错误代码(不可能触发错误)。 根据本文的评估,平均超过91.7%的输入无法达到错误代码。如果存在一种足够快的方法来预测输入的可到达性,则fuzzing过程不需要使用不可达的输入来执行目标程序。 这样,可以提高模糊测试的整体性能。

受到深度学习在模式识别领域的最新成功的鼓舞,本文想探讨深度学习是否可以应用于识别(不)可达输入。

Methodology

Overview

本文提出了FuzzGuard的设计,这是一种基于深度学习的方法,可以帮助DGF过滤掉无法到达的输入,而无需真正执行目标程序。这样的数据驱动方法避免使用传统的耗时方法,如符号执行,以获得更好的性能。

image-20200721104253482
image-20200721104253482

FuzzGuard包括三个主要阶段:模型初始化(MI)、模型预测(MP)和模型更新(MU)。它与DGF(称为”carrier fuzzer”)一起工作。

  1. MI阶段,carrier fuzzer生成大量输入并观察任何异常。FuzzGuard记录程序是否可以为每个输入执行目标错误代码。然后FuzzGuard利用输入及其可达性训练模型。
  2. MP阶段,FuzzGuard利用模型来预测新生成的输入的可达性。如果输入是可到达的,它将被输入到程序中进行实际执行。在这个过程中,FuzzGuard会观察输入是否能够真正到达目标代码。
  3. MU阶段,FuzzGuard通过增量学习进一步更新模型,以保持其效率并提高其性能。无法到达的输入将临时保存在”无法访问输入池”(PUI)中,以便在模型更新后由更精确的模型进行进一步检查。
image-20200721142730282
image-20200721142730282

Model Initialization

但是,为每个前导节点训练一个模型花费的时间太长。 这主要是因为当FuzzGuard前进到下一个前导节点时,需要重新训练模型。 我们的想法是只为所有前导节点(包括buggy code本身)训练一个模型。

本文工作选择CNN,原因有2:

  1. CNN适合处理长数据
  2. 训练CNN模型花费时间比RNN短,适合fuzzing

本文选择使用3层CNN模型。第一层可以学习每个字节之间的关系,而其他两层则可以学习高维特征(例如,将多个字节组合成一个输入字段,并组合多个字段以影响程序执行)

通过这种方式,通过让carrier fuzzer运行一段时间以收集初始训练数据集。 在初始训练数据集达到平衡之后,模型可以学习到输入所有节点的可达性。 该模型的目标是学习目标函数$f$(即$y=f(x)$),其中包含许多卷积运算。 卷积操作使用许多过滤器从数据中提取特征:

Prediction

模型初始化后,FuzzGuard利用模型预测每个输入的标签,并过滤掉那些不可达的输入。

对于输入x,假设模型只能预测$B_t$之间的前导节点,并且预测结果$y^p$

但是,在实际情况下,即使生成许多标记数据,预测结果依然不够准确。

主要原因是,即使新生成的输入可以达到目标,它们看起来也可能与训练集中的可到达输入完全不同。 这是可以理解的:这些输入可能来自不同的种子。

从同一种子变异而来的大多数输入彼此略有不同,而在从不同种子变异而来的输入之间可以发现许多差异。 因此,完全使用以前执行的输入可能无法训练非常准确的模型来预测新生成的输入的可达性。

为了解决这个问题,本文提出了一种代表性数据选择方法,该方法从每一轮突变中选择许多代表性输入以执行和训练。

本文将固定数量的输入(例如5%)作为该突变的代表数据,这些输入是从一轮突变中随机抽取的。

但是,不能直接通过两个种子的相似性,来假设两个输入集合的分布是相似的。 这主要是因为不同的突变策略(例如,位和字节翻转,简单的算术,堆叠的调整和拼接)可能会极大地改变种子,并使后代看起来完全不同。

本文想法是将种子与相应的突变策略一同进行比较。

如果两个种子相似且策略相同,考虑从组合集中选择较少的输入。本文将$s_1$和$s_2$之间的种子相似度(SSD)定义如下:

Model Updating

本文使用增量学习来训练一个动态模型。

更新策略:

  1. 当模型的假阳性率超过阈值时,更新模型
  2. 当到达新的前导节点时,更新模型

Implementation

MI

初始阶段,FuzzGuard只有在收集到足够的平衡的数据(或新数据)后才开始训练(或更新)模型。

DGF需要一个目标(潜在的)buggy code,其位置是Fuzzing已知的。为了设置buggy节点的前导节点,本文生成目标程序的调用图(CG)和控制流图(CFG),并设置前导节点。本文实现中使用NetworkX和LLVM生成的CG和CFG中自动寻找前导节点。

MP&MU

本文将SSD的$\theta _s$设置为0.85,并且每轮突变的默认采样率为5%。当SSD超过阈值时,采样率将降低到$(1-\theta _s)/5$(即小于3%)。根据本文评估,该取值可达到最佳性能。

考虑到不同程序的模型精度差异很大,本文根据之前的执行情况动态地改变$\theta _f$:$\theta _f=1-acc_{avg}$。$acc_{avg}$代表先前更新的模型的平均精度。

Model Implementation

对于模型训练,本文使用PyTorch实现CNN模型。

我不搞深度学习,这一块我就略过了

Deployment of FuzzGuard

为了实现数据共享,团队在AFLGo中的fl-fuzz.c中添加了一个函数Checker()

image-20200722150025547
image-20200722150025547

Evaluation

本文实验结果表明,FuzzGuard比AFLGo提高了17.1倍的fuzzing性能。

Settings

本文选择了15个处理10种常见文件格式的真实程序,包括:

  • 网络包(如PCAP)
  • 视频(如MP4、SWF)
  • 文本(如PDF、XML)
  • 图像(如PNG、WEBP、JP2、TIFF)
  • 压缩文件(如ZIP)

不幸的是,三个程序(mupdf、rzip、zziplib)无法编译,而两个程序(apache、nginx)没有给出漏洞的详细信息。

所以本文选择了剩下的10个作为目标程序,以及过去3年中对应的bug。

对于不同的输入格式,本文使用AFLGo提供的测试用例作为初始种子文件开始fuzzing(实验前提是相信AFLGo使用自己选择的初始种子文件将表现良好)。

所有的实验和测量都是在两台运行Ubuntu16.04的64位服务器上进行的,该服务器有16核(Intel(R)Xeon(R)CPU E5-2609 v4@1.70GHz)、64GB内存和3TB硬盘以及2个GPU(12GB Nvidia GPU TiTan X)和CUDA8.0。

Effectiveness

  • The earlier the model is trained, the more time could be saved
  • The more reachable inputs generated by the carrier fuzzer, the less effective FuzzGuard is

Accuracy

本文自称”不会遗漏任何PoC,因为过滤后的输入将保存在PUI中,PUI将由更新的模型进一步检查”,理论上不会产生误报。但是FuzzGuard设置了timeout,所以如果在时限内没有找到一个false negative input,那么它将会丢失。但是幸运的是,评估中的45个bug,由于准确模型,PUI中没有发现PoC。

本文给出的FuzzGuard准确率为92.5%到99.9%,平均准确率为98.7%。所有漏洞的误报率平均为1.9%。

假阳性和假阴性的主要原因是缺乏平衡的代表性数据。

Discussion

Benefit to input mutation

目前的fuzzer大多集中在对输入进行变异以提高fuzzing的性能。本文思路不同,本文想法是帮助DGF过滤掉无法到达的输入。

基于对FuzzGuard提取的特征的理解,本文发现FuzzGuard可以学习影响执行的字段。因此,FuzzGuard可以进一步帮助DGF进行输入变异。

Memory usage

理论上,可以将无法访问的输入永久保存在内存中,以避免丢失PoC。然而,在实际情况下,记忆是有限的。所以本文的想法是删除那些不可能到达buggy code的输入。

笔记

  1. 误报、漏报情况如何
  2. 图2中给的例子,这个前导节点看起来是唯一路径,但是实际上应该有多种路径到达某个buggy code,并且fuzzer应当是对全局进行fuzzing,这个标签会相当复杂,FuzzGuard是怎么管理这个标签和dominator tree的。它的策略不会是一个一个漏洞分析过去吧。
  3. 两个组成部分之间的通信是否会产生性能损耗以及通讯延迟
  4. 这篇东西做的是用深度学习加速,但是它的加速方式不是解决”会阻碍fuzzing进行的难题”,而是优化”fuzzing的无效操作”
  5. Discussion第一项,FuzzGuard在一定程度上可以起到污点分析的类似作用。