这篇论文 fuzz 的对象是带状态的网络服务。

在第一篇参考资料中,我发现了这张图:

这对我们理解协议模糊测试的历史应当有一定的帮助。

回到 NSFuzz 中,先看一下作者们指出的问题:

  1. 传统灰盒 fuzz 不了解状态,不能很好地 fuzz 网络服务;
  2. 网络服务涉及多次 I/O 操作,fuzzer 需要与目标服务多次交互,需要提升测试效率。

目前比较先进的协议 fuzzer 都有一些问题:

  • AFLNET 假定协议在响应信息中存在特定的代码来表示状态,不够准确;
  • SGFuzz 使用 enum 变量作为状态变量而且没有筛选,不够准确;
  • STATEAFL 使用内存状态来表示服务状态,有额外开销。

作者们提出两种方法改进:

  1. 利用程序变量表示服务/协议状态;
  • 嗯,这和 StateFuzz 的思想很像啊。唔,原来一作和指导老师是都是同一位,也算是一脉相承了吧。
  1. 引入 I/O 同步机制。
  • 说实话,这个点我没有看懂。
  • 按照作者们的意思,他们进行了一些定义:
    • I/O 同步点:事件循环中可以引发信号反馈的位置
  • 作者们认为,基于信号的同步可以促进 fuzzer 发送新消息,减少等待时间开销,还可以让 fuzzer 收集状态,转换序列,主动推断状态模型,避免类似 StateAFL 的执行后分析。
    • 那么怎么证明的呢(异步更新序列和状态模型会更好吧,也许这是一个工程上的点但不是学术上的点)

接下来重点关注几个方面:

  1. 识别状态变量的方法
  2. 怎样建立的状态模型,怎样验证模型的准确性
  3. 怎样找到信号反馈位置的,在那个位置都做了什么
  4. 如何在收到 observer/feedback 之后高效更新状态模型

首先看第 3 节,简单来说就是将网络服务分成了三阶段,初始化、服务和清理阶段;其中初始化和清理阶段指的是程序的开始和结束(而不是一次服务的开始和结束),fuzz 的点一般都位于服务阶段。

  • 在网络服务中总会有一个大循环处理消息,这个循环点就可以作为 I/O 同步点。具体的,作者们将循环点的入口(也就是循环体的开始位置)作为 I/O 同步点。
    • 可以认为是一次 fuzz 的结束标志。
  • 在作者们的例子中,对于 Bftpd,所有的失败响应消息错误码均为 503,但错误原因可能是不同的。

架构

接下来看一看 NSFuzz 的整体框架:

猜测

  • 和 StateFuzz 的架构相比,在状态变量与建立的方法上似乎比较相似,而在 fuzzing loop 中,多了一个状态模型推理的模块,猜测是因为仅通过静态分析无法建立完整的状态模型,需要在 fuzz 的过程中触发新的状态才能继续构造新的模型。
    • 在 fuzz 中触发了什么才能算新的状态呢?这需要监视一些变量,本文又是怎样在源码上插桩的呢?
    • 在触发新状态后,本文是怎样在原本的状态机上建立新状态的呢?这个操作会消耗多少时间呢?(这似乎不是本文的重点?)

首先看静态分析部分(4.2 节),这一部分主要是为了识别主循环以及提取状态变量。

  • 我比较关心状态变量的提取,根据三种启发式规则:
    1. 只分析网络循环中的变量,缩小分析范围;
    2. 只提取同时加载和写入的变量(对应状态检查和更新);
    3. 只保留全局整数变量和用户定义的结构体中分配的常量变量。
    • 这一部分看上去是对 SGFuzz 的优化。

在提取变量后,NSFuzz 提供了两个 API:

  • _NSFUZZ_SYNC 用来同步状态(也就是所谓的 I/O 同步点),告诉 fuzzer 一次 fuzzing 已经结束;
  • _NSFUZZ_STATE 用来标记状态变量,另类的覆盖率(或者说反馈)信息。

哦原来 I/O 同步是为了解决 AFLNET 和 STATEAFL 中的痛点:

Quote

为了提高模糊测试效率,AFL 引入了 FORKSERVER 来进行 fork 的创建和回收,AFLNET 和 STATEAFL 都是基于 AFL 来实现的,当执行一个 testcase 时,他们首先通知 FORK-SERVER 创建一个进程进行模糊处理,然后依次按照手动指定的时间间隔发送每个请求消息,最后等待 FORKSERVER 在服务结束后通过通信管道写入执行结果。而 NSFuzz 实现了一个 NET_FORKSERVER,通过它与反馈信号进行合作从而实现快速 I/O 同步,从而避免了手动指定的时间等待间隔,如下图所示,每次 NSFuzz 发送一个请求消息后,NET_FORKSERVER 等待 raised 信号来判断目标是否已经完成了一轮 I/O 交互或者发生崩溃,并将这些信息发送给 fuzzer。

简单来说就是 AFLNet 和 StateAFL 对于一次 fuzzing 结束的判断是依赖超时的,而 NSFuzz 实现了一个类似 hook 的方法(也就是所谓的 endpoint,这一思想在 trapfuzzer 中也有体现)。

嗯,感兴趣的看完了,最后上一下 I/O 同步机制图吧,以后要是需要作图的时候可以参考一下。

参考资料