FuzzGen: Automatic Fuzzer Generation

当fuzz运行库时,由于无法作为一个独立程序运行,需要其它应用调用。出发运行库的深度代码较难,因为需要特定的API调用建立必要的状态。运行库都是各种各样的并且有独特的接口,需要独特的fuzzer。

为了解决这个问题,本文提出了FuzzGen,在给定的环境下可以自动为给定的复杂库合成fuzzer。FuzzGen利用对库完整的系统分析,合成fuzzer,不需要人类交互并且可以应用到很多运行库上。生成的fuzzer可以利用LibFuzzer获得更好的代码覆盖率,暴露更深层的bug。

在Debian和Android AOSP上评估了FuzzGen,选择了7个库生成fuzzer,找到了17个漏洞并且6个赋予了CVE。平均可以实现54.94%的覆盖率,比手动写的fuzzer提高了6.94%。

Motivation

非法输入很快就会导致错误并推出,所以代码覆盖率是一个很好的程序状态指示器。

但是库函数的fuzz比较麻烦。库暴露一系列的API,但是没有给出依赖关系。库中的函数是需要按正确的顺序、正确的参数调用,来建立不同函数调用共享的复杂状态。这种库函数之间隐含的依赖关系经常在文档中写出来,但是没有形式化指出。使用随机参数调用随机函数不太可能是一种有效率的fuzz方法。

LibFuzzer方便了对于库的fuzz。分析人员需要写一个小的fuzzer stub,1)调用需要的库函数建立必要的状态并且2)利用随即输入fuzz状态和控制流。分析人员必须为每一个感兴趣的组件写fuzzer stub,确定API调用,API依赖,API参数。虽然减少了API fuzz的压力,但是需要很多人力,无法扩展到很多不同的库。

Design

1658454453253

FuzzGen利用如下特性:系统中已有的代码在多个方面利用了库函数。对于可能的库依赖建立抽象图可以用于推断复杂的库API,API的不同方面通过基于推断的API自动生成的fuzzer stub进行测试。自动化生成的fuzzer会按顺序执行API调用,和真实的程序类似,但是不会像真实程序那样臃肿,移除了所有对于建立状态无关的计算。这些fuzzer提高了深度代码覆盖率,因为考虑到了真实API的使用部署。

许多库包含单元测试库,测试库的简单方面;使用库的程序会对于某个函数建立一个深度状态。只使用单个测试用例会导致相对于复杂库来说太简单,导致较低代码覆盖率。因为所有程序功能都与目标库一起执行。自动化构建复杂fuzzer stub的机制可以更高效地fuzz复杂API函数。大量不同的测试用例隐含地定义了一个抽象API以来图(A2DG)。基于A2DG就可以自动化创建测试库不同方面的fuzzer stub了。

FuzzGen包含三个部分:

  • API推断:基于所有的测试用例和程序建立A2DG
  • A2DG构建机制:记录所有的API交互,包括参数值和可能的交互
  • Fuzzer生成器:利用A2DG生成fuzzer stub,从而触发深度代码,构建复杂状态。

1658455796043

Result

FuzzGen 对整个系统分析,迭代使用所有测试用例和程序推断库的A2DG。 然后它会自动对 A2DG 进行编码并使用 libFuzzer 对单个 API 组件进行模糊测试的(范围从 1, 000 到 10,000 LoC)。 FuzzGen 在 Debian 和 Androi 上进行了评估

发现了Android Media Framework上发现了17个漏洞,6个赋予了CVE: CVE-2019-2176 [16], CVE-2019-2108 [15],CVE-2019-2107 [14] and CVE-2019-2106 [13] (critical), CVE-2017-13187 [12] (high) and –duplicate– CVE-2017-0858 [11] (medium).

贡献

  • 设计整个分析系统,根据现有程序和使用目标库的库推断给定库的有效 API 交互——将信息抽象到A2DG中;
  • 基于A2DG创建fuzzer stub,可以构建复杂的程序状态
  • 在AOSP和Debian上评估了FuzzGen,发现了17个漏洞,6个赋予CVE,并且代码覆盖率54.94%