1. 什么是 LibAFL

LibAFL 是一款用 Rust 语言开发的开源模糊测试框架,它将模糊测试的组件划分成一组模块文件,用户可以基于这组模块,快速实现自定义的 fuzz 引擎。

2. 为什么要设计 LibAFL

现有的 Fuzz 引擎很多是基于 AFL 进行改造的,不同的改造之间存在不兼容的情况,比如 Fairfuzz 是基于 AFL 改造的,但是 AFL++ 不支持 Fairfuzz。如果希望把多种 Fuzz 优化技术集合在一起,工程难度很大。

AFL++ 是 AFL 的进化版,它在 AFL 的基础上集成了很多 Fuzz 优化技术,并支持以插件的方式进行功能扩展,例如可以自定义 mutator。但 AFL++ 还是受限于 AFL 本身的程序设计,与 mutator 无关的优化技术,与 AFL++ 的集成也比较困难。

3. LibAFL 整体架构

(1)Fuzz 引擎的相关组件

  1. Input
    指 fuzz 过程中,传递给 target 的输入数据。Libfuzzer 和 AFL 默认的输入格式,都是字节数组。fuzz 的入口函数在以这个字节数组作为入参,然后对字节数组进行切片和类型变换,转换为 target 中待测函数所要求的参数形式,再对待测函数进行调用。

  2. Corpus
    指 fuzz 过程中,用来存放有效 input 的语料库。AFL 必须要有初始语料库,Libfuzzer 可以不提供初始语料库。语料库可以存放在磁盘中通过 io 读写,也可以全部加载进内存中。前者效率低,后者内存消耗大。

  3. Scheduler
    指 fuzz 引擎从语料库中选择 input 的调度机制。语料库中包含大量的 input,fuzz 每轮执行需要挑选一个 input。调度机制决定了 input 的挑选方法,简单的实现包括先入先出、随机挑选等。对调度机制进行优化,也是改进 fuzz 的一个方向。

  4. Stage
    fuzz 的每一轮执行实际上都包含多个步骤,每个步骤都可以理解为一个阶段。比如变异阶段是对 input 进行随机变异操作,分析阶段可以使用污点分析等技术搜集更多信息,语料库精简阶段是对语料库进行筛选操作。一连串的阶段性操作构成了一次完整的 fuzz 执行过程。

  5. Observer
    观察器用来收集 fuzz 单词运行过程中的信息。在覆盖率引导的 fuzz 引擎中,观察器会看这次执行过程中,input 所经过的代码路径。AFL 中的 bitmap 就是一个观察器,AFL 将代码路径转化为 branch 或 edge 的集合,并记录在 bitmap 中。

  6. Executor
    执行器负责将 input 喂给 target 开启一次 fuzz 执行。不同的 fuzz 工具,可能有不同的执行方式。Libfuzzer 是一个单进程的执行模式,在一个进程中生成 input 运行 target,并不断循环这个过程;AFL 则通过 fork 模式,每次 input 都会 fork 出一个子进程,在子进程中运行 target。

  7. Feedback
    反馈通常是基于观察器收集到的执行结果,来判断这次 fuzz 执行过程中,使用的 input 是不是一个有效的输入,如果是有效输入才会保存到语料库中。在覆盖率引导的 fuzz 引擎中,当一个 input 能命中此前都没有到达的代码区块时,才会被认为是有效的。

  8. Mutator
    变异器接受一个 input 作为输入,通过修改、插入、删除等变异操作,衍生出一个新的 input。在 AFL 和 Libfuzzer 中,input 为字节数组,变异器通过对字节位和字节块进行改变,进而得到新的 input。在 target 输入需要满足指定格式时,自定义变异器是一条可行的途径。

  9. Generator
    生成器是指从头生成一个 input 作为输入,它不是基于已有的 input 进行修改。常用于基于生成的 fuzz 引擎中,例如 peach 中通过定义 input 的数据模型来指导 input 的生成。

(2)LibAFL 的架构设计

LibAFL 的核心架构设计如下图:

其中的一些实体名词含义参见前一部分介绍。在这个架构图中,有三个比较大的组件:

  • State:负责记录和维护 fuzzer 运行过程中的需要持久化的信息。它包括了各类统计数据、测试用例数据、已发现的漏洞、程序执行的路径等。这些信息用于帮助 fuzzer 做出智能决策,优化测试过程。

  • Fuzzer:负责实际执行模糊测试。它使用各种算法和策略来生成或者变异输入数据,然后将这些数据用于测试目标程序,以期发现潜在的安全漏洞。Fuzzer 需要与状态组件紧密协作,以使用状态信息引导自己的测试过程。

  • Event Manager:事件管理器作为 LibAFL 架构中的通信枢纽,它负责协调不同组件间的交互工作。事件管理器处理各种事件,如新发现的错误、状态更新信号等,并确保这些信息及时、正确地在组件间传递。

4. LibAFL 使用方法

  1. 简单的模糊器实例 - LibAFL 模糊测试库
  2. fuzzing-101-with-libafl

5. 参考资料

  1. LibAFL: A Framework to Build Modular and Reusable Fuzzers
  2. LibAFL 学习笔记
  3. LibAFL 中文文档