NSFuzz: Towards Efficient and State-Aware Network Service Fuzzing-论文阅读

NSFuzz: Towards Efficient and State-Aware Network Service Fuzzing-论文阅读

Introduction

前作

在nsfuzz之前的一些工作是如何对有状态的网络应用的灰盒模糊测试的。

AFLNet

原理:

  • aflnet通过从响应消息中提取响应码来表示服务状态,并使用响应码序列推断协议实现的状态模型,进一步利用推断的模型指导模糊测试过程。
  • 利用推断的状态模型指导模糊测试:aflnet根据协议实现的状态模型,在模糊测试过程中指导生成的输入,以更好地探索协议实现的代码路径和增加代码覆盖率。

不足:

  • 状态表示的挑战:aflnet提出的响应码方案假设协议会在响应消息中嵌入特殊的编码,这在实际情况下并不总是成立。因此,这种基于响应码的状态表示方案可能不适用于所有的网络服务。
  • 测试效率的挑战:由于没有明确的信号指示被测试的网络服务是否已经完成对一个消息的处理,aflnet使用一个固定的定时器来控制模糊测试器发送消息给被测试的网络服务。然而,定时器的时间窗口要么太短(这样被测试的网络服务可能会错过模糊测试器发送的消息),要么太长(这样模糊测试器会在等待中浪费太多时间),从而影响了模糊测试的效率。
statefuzz

原理:

  • statefuzz通过抽象符号执行和动态二进制分析技术,捕获和表示网络服务的状态信息,并在模糊测试过程中持续更新和利用这些状态信息。通过准确地表示网络服务的状态,statefuzz能够更好地引导模糊测试过程,提高测试用例的质量和效率。
  • 利用状态信息优化模糊测试:statefuzz使用状态信息来引导探索测试路径,通过符号执行技术生成具有高覆盖率的测试用例。同时,statefuzz还利用状态信息的汇总来生成更多的有效测试用例,从而增加网络服务中漏洞的发现几率。

不足:

  • 运行时开销较大:statefuzz需要对网络服务进行动态二进制分析和抽象符号执行,并在运行过程中捕获和更新状态信息。这些额外的运行时操作会导致较大的性能开销,使得模糊测试的过程变得较慢。
  • 对协议解析的依赖:statefuzz需要分析网络服务的协议实现来获取状态信息。如果协议实现复杂或者没有明确定义的协议规范,statefuzz可能会遇到困难,难以准确捕获和表示网络服务的状态。

待解决的问题

  1. 状态表示的困难性:现有的模糊测试工具对网络应用的状态表示还存在问题。例如,AFLNET采用了从响应消息中提取响应码的方式来表示服务状态,但这种方法假设协议会在响应消息中嵌入特殊代码,而实际情况并非都是这样。此外,如STATEAFL所指出的,响应码只能提供服务状态的很差指示,甚至可能导致冗余的状态。

  2. 测试效率的挑战:由于没有明确的信号表明被测系统是否已经完成处理一个消息,目前的模糊测试工具使用固定的定时器来控制模糊器向被测系统发送消息。然而,定时器的时间窗口要么太短(这样被测系统可能会错过模糊器发送的消息),要么太长(这样模糊器将浪费太多时间等待)。此外,STATEAFL需要进行后执行分析来收集状态序列和推断状态模型,这会引入额外的运行时开销,并进一步降低测试吞吐量。

nsfuzz的贡献

作者通过研究多个代表性的网络服务程序,发现这些程序通常使用程序变量直接描述程序状态。此外,网络服务往往包含一个网络事件循环,负责分发传入的消息。

  • 为了解决第一个挑战,作者提出了一种轻量级基于变量的状态表示方案,以更高的准确性表示服务状态。
  • 对于第二个挑战,可以利用网络服务的内在事件循环来产生适当的信号反馈,从而实现网络服务与模糊器之间的高效同步,并促使模糊器发送新消息以减少等待时间开销。
  • 此外,基于信号的同步还可以使模糊器主动进行状态序列收集和状态模型推断,从而避免STATEAFL所使用的繁重的执行后分析。

具体:
作者使用静态分析自动识别网络服务的网络事件循环和状态变量,并进行轻量级的编译时插桩,以实现状态感知模糊测试和基于信号的快速I/O同步。评估结果表明,NSFuzz在模糊测试过程中能够推断出更准确的状态模型,并且其模糊测试吞吐量显著高于AFLNET和STATEAFL。此外,NSFuzz能够在更短的时间内达到更高的覆盖率并触发崩溃。

贡献点:

  1. 提出了一种基于变量的状态表示方案,用于识别网络服务的状态并推断其状态模型,并将其用于指导模糊测试过程。
  2. 提出了一种基于网络服务系统的网络事件循环的高效同步机制,实现网络服务模糊测试的更高吞吐量。

相关工作

早期的黑盒测试

早期的黑盒测试方法主要是使用基于生成的模糊测试工具。对于网络服务,这些方法依赖于对协议格式的事先了解,通过生成有效的测试用例进行模糊测试。

灰盒测试

关于网络服务的灰盒模糊测试,一般会使用响应代码、状态模型或覆盖率等指标来表示网络服务的状态,并根据这些指标来引导模糊测试过程。灰盒模糊测试可以帮助发现网络服务中的安全漏洞、协议错误或异常行为,并对网络应用程序进行细粒度的状态分析和引导,以提高模糊测试的效率。

程序状态模型推断

通过推断程序的状态模型,可以得知程序在不同状态下可能触发的行为和可能的状态转换。这有助于设计更有针对性和具有代表性的测试用例,从而增加发现漏洞的机会。例如,可以针对每个可能的状态和状态转换创建测试用例,以覆盖各种情况。此外,了解状态模型还有助于测试人员确定测试的边界条件和特殊情况,以提高测试用例的有效性。

程序状态模型推断可以通过多种技术实现,如流量分析、动态污点分析、二进制标记结合网络跟踪等。这些技术可以从程序执行过程中收集信息,并根据这些信息推断出程序的状态模型。推断出的状态模型可以用于指导模糊测试的输入生成过程,从而提高测试的效果和效率。

网络服务的研究

网络服务的实现

  • 服务初始化阶段:在这个阶段,网络服务进行初始操作,如读取配置文件和根据启动参数初始化相关的数据结构。此外,服务会使用网络编程接口(如Glibc中的socket()函数)来创建套接字、绑定网络端口,并监听套接字等待远程客户端的连接请求。

  • 服务处理阶段:在处理阶段,网络服务运行在一个事件循环中。服务会不断地处理来自客户端的请求并返回响应。当客户端请求到达时,服务会解析消息,调用相应的函数处理请求,并返回响应消息。网络服务只有在客户端主动退出或遇到异常时才会退出这个阶段。

  • 服务清理阶段:当网络服务主动终止时,这个阶段负责进行程序清理工作,如释放资源,并最终退出停止提供服务。

由于网络服务需要为任意远程客户端提供长期的服务,它们通常以后台持久运行或作为守护进程运行。因此,网络服务程序大部分时间都在第二个阶段运行,即在网络事件循环中不断地处理远程客户端发送的请求消息。此外,需要注意的是,在网络服务的实现中,开发人员通常使用一些变量来表示服务器的状态,以支持运行有状态协议的功能。

Snipaste_2023-08-11_15-42-56.png

如List 1所示(Service Processing状态),从第3行到第6行是一个网络事件循环,Bftpd在第3行接收请求消息并在第5行进行解析。Bftpd FTP协议服务会重复执行这些操作,直到远程客户端用户主动关闭网络套接字或服务因任何异常而结束。在Bftpd中,开发者使用命令结构来存储每种请求的类型名称、处理程序的函数指针和状态要求。在parsecmd()函数中,Bftpd首先尝试匹配传入请求消息的类型(第13行),并进行状态检查(第16行),然后只有在通过状态检查后才调用相应的处理程序(第18行),否则根据当前服务状态向客户端响应一个失败消息。

基于上述研究的发现(理解)

以Bftpd代码片段作为例子,说明网络事件循环的功能。在Bftpd的消息处理阶段,事件循环的入口可以表示Bftpd服务器已经处理完前一个FTP请求消息,并准备接收下一个FTP请求消息。因此,事件循环的入口可以作为一个同步点,主动通知模糊测试工具发送下一个请求消息,从而避免无用的等待时间。此外,这样的同步也可以告诉模糊测试工具进行状态收集,避免在执行后进行状态转换的分析。

网络服务通常使用变量来表示运行时的服务状态。例如,当Bftpd接收到PASS请求消息(用于用户登录)时,会调用pass函数,将请求的密码字段作为函数参数(第18行),并根据当前服务状态执行不同的代码分支(从第37行到第44行)。当登录成功时,Bftpd会将服务状态更新为STATE CONNECTED。值得注意的是,网络服务使用一个枚举的全局变量state来表示服务的状态。它在网络事件循环中经常被读取(例如第21行)或更新(例如第42行)。此外,与响应代码相比,使用程序变量来表示服务状态也更加准确合理。在上述Bftpd代码片段中,不同服务状态下的失败响应消息的响应代码都是503(从第22行到第30行),这表明不能使用响应代码来区分网络服务的实际状态。

总结:建议使用网络服务中的特定变量来准确表示服务状态,并利用网络事件循环作为指示器实现高效的I/O同步。

方法论

NSFuzz主要由两个主要组件组成:静态分析和模糊测试循环。

首先,NSFuzz将网络服务源代码作为输入,进行静态分析,以识别网络事件循环并提取状态变量。

然后,它利用静态分析的结果进行编译时插桩,使目标服务具备基于信号的同步和基于变量的服务状态跟踪功能。

在模糊测试循环中,NSFuzz将初始种子作为输入,并根据代码覆盖率和状态信息进行种子选择和消息变异,生成测试用例。

在执行测试用例时,NSFuzz每次发送一个请求消息,并等待同步信号。

一旦NSFuzz接收到信号,它收集程序状态并更新状态模型,执行基于状态的模糊测试。

NSFuzz重复这个过程直到停止模糊测试循环,以找到程序崩溃问题。

Snipaste_2023-08-11_16-30-03.png

静态分析

静态分析查找两个重要信息:网络事件循环和服务状态变量。

网络事件循环负责在服务器处理阶段处理传入的请求消息。

表示程序实现中关键状态变量的相关信息。

  • 静态分析可以提供网络事件循环的时机反馈,帮助fuzzer避免浪费时间。与基于响应代码的状态表示方案相比,基于变量的状态表示方案可以更真实地反映网络服务的状态,从而推断出更准确的状态模型。

  • 此外,nsfuzz通过使用预执行的静态分析来提取状态变量,并在编译过程中对被测试的服务进行了工具化,实现了状态变量值与共享内存的实时映射,从而进一步提高了fuzzing的效率。

网络事件循环标识

识别事件循环的难点在于:将其与网络服务程序中的其他循环区分开来,因为在实现中存在太多不同的循环。

例如,服务初始化阶段。许多服务可能使用文件I/O循环来读取配置。此外,事件循环本身也可能包含嵌套循环,这也给静态分析器准确识别网络事件循环带来了困难。因此,nsfuzz跟踪服务处理阶段的网络I/O操作,并通过回溯来区分外环以解决问题。

具体解决方式:

  1. 在网络服务完成初始化并进入服务处理阶段时,在与系统调用相关的输入上设置断点,如read、recv、recvmsg等。
  2. 模糊测试工具建立与被测系统的套接字连接并发送探测消息。当命中断点时,被测系统保存函数调用栈的回溯。
  3. 将回溯作为静态分析器的辅助输入,用于识别网络事件循环。
状态变量提取

静态分析器根据网络服务实现的特性以及对服务程序中状态变量特征的分析,采用以下启发式规则来减少提取状态变量时的误报率:

  1. 网络服务中与状态变量相关的操作通常在网络事件循环中执行。因此,静态分析器只在网络事件循环内进行分析,以减少分析的范围。
  2. 网络服务中的状态变量通常在网络事件循环或消息处理程序中被读取(用于状态检查)或写入(用于状态更新)。因此,静态分析器只提取同时进行加载和存储操作的变量。
  3. 网络服务中的状态变量通常是全局枚举变量或数据结构中的整数成员变量,并且它们只被分配常量值以表示特定状态。因此,静态分析器只保留在存储操作中分配了常量值的全局整数变量或用户定义的结构成员。
编译时插桩

nsfuzz在编译时的两种插桩技术:

  • 网络事件循环插桩
  • 状态变量存储插桩

网络事件循环插桩:通过在网络事件循环的入口处插入raise (SIGSTOP)语句,使得服务在处理完每个请求消息后,可以向模糊器发送信号反馈,表明准备好接收下一个请求消息。

状态变量存储插桩:通过对每个状态变量的STORE操作进行插桩,将写入的变量值作为键更新SUT和模糊器之间共享的状态相关内存。为了区分记录代码覆盖率的共享内存,这里将记录状态信息的共享内存称为共享状态。具体的映射方法是使用每个状态变量的唯一字符串ID进行哈希运算,并将哈希值与要写入的新状态值进行异或运算,将异或结果作为索引更新共享状态。此外,NSFuzz还使用相同的方法根据先前的旧状态值计算索引以恢复共享状态。最后,NSFuzz生成了插桩的程序作为待模糊测试的服务。

Fuzzing loop

与传统的覆盖率引导灰盒模糊器相比,NSFuzz引入了信号提升反馈,使得模糊器在测试用例执行过程中还需要配合仪表化信号反馈来实现快速的I/O同步。此外,在状态变量的STORE操作处的插装使得NSFuzz还需要在适当的时间检查共享状态,并收集状态转换序列,以帮助推断状态模型。

Snipaste_2023-08-12_16-07-38.png

快速IO同步

通过实现NET FORKSERVER与服务测试中信号反馈的合作来实现快速I/O同步,从而避免了手动指定的时间等待间隔。在这种情况下,每次NSFuzz的模糊器发送请求消息时,它都通过管道等待NET FORKSERVER的反馈。作为模糊网络服务的父进程,NET FORKSERVER直接等待来自被测试服务的触发信号,根据信号类型确定目标是否完成了一轮I/O交互或者仅仅是崩溃,然后将此类信息传递回模糊器。图2展示了NSFuzz框架中模糊器、NET FORKSERVER和服务测试之间的I/O同步。

状态感知fuzz
  1. 接收来自NET FORKSERVER的消息处理结果:当fuzzer通过通信管道接收到NET FORKSERVER的消息处理结果时,它会计算共享状态缓冲区的哈希值。

  2. 使用哈希值表示当前系统状态:这个哈希值可以用来表示系统当前的状态。原因在于,如果某个消息引起状态转换,它会更新某些状态变量的值,从而更新共享状态缓冲区。因此,当这个消息被处理后,fuzzer将会得到一个与处理之前不同的共享状态缓冲区的哈希值。换句话说,每当系统状态发生变化时,缓冲区的哈希值也会发生变化。因此,fuzzer可以使用缓冲区的哈希值来收集每个同步之后的状态转换序列,从而推断出状态模型。

  3. 使用哈希值进行状态表示:相比于STATEAFL,nsfuzz更充分地利用了基于变量的状态表示方案,通过使用共享状态哈希值来更充分地表示系统状态。这种方式可以比较高效地实现状态反馈。与STATEAFL不同的是,STATEAFL在每个消息处理期间连续地将所有变量值转储到分析队列中,并进行后执行分析以进行状态推断。

  4. 保留触发新服务状态或状态转换的测试用例:除了获取新的代码覆盖率外,nsfuzz还会将触发新服务状态或状态转换的测试用例保留作为有趣的种子,用于后续的fuzzing。

  5. 基于此,nsfuzz会执行类似于AFLNET的状态引导种子选择和消息变异操作,来进行状态引导的种子选择和消息变异。

实验

实验主要评估两个部分:

  1. NSFUZZ推断的状态模块的准确性:NSFuzz是否可以在模糊循环期间基于状态变量推断相对更准确的状态模型?
  2. NSFUZZ状态感知模糊化的有效性:NSFuzz是否可以比其他现有方法实现更高的模糊效率和概览结果?

实验环境:ProFuzzBench作为有状态模糊测试的基准测试。

Snipaste_2023-08-12_16-37-38.png

基线模糊器:AFLNET、STATEAFL、AFLNWE

AFLNET使用消息响应码表示服务状态并推断状态模型,然后在模糊循环中基于该模型进行状态引导模糊。STATEAFL在网络I/O循环期间收集已更改的变量。然后提取状态变量,通过实验后分析推导出状态模型。AFLNWE是AFLNET作者提出的另一种网络服务模糊器。它只是将文件I/O接口由原来的AFL改为基于套接字的网络I/O,实现了网络服务模糊化。

状态模块推断评估(评估1)

静态分析阶段

首先执行静态分析以识别网络事件循环,并使用此类循环作为起点来提取状态变量。表II显示了NSFuzz对7个目标服务的静态分析结果。正如我们所看到的,NSFuzz可以成功地定位来自不同目标服务的网络事件循环,这涉及到多个网络协议,并且NSFuzz还可以通过静态分析提取状态变量。

Snipaste_2023-08-12_16-38-40.png

此外,提取的状态变量的数量和分析时间通常与目标服务(LoC)的规模正相关,这是一致的直觉。应当注意,所提取的状态变量的名称有时可以直接指示其表示网络服务的状态的功能。

例如,通过静态分析从Pure-FTPD中提取的状态变量之一是loggedin,这是一个全局变量,用于指示传入的客户端会话是否已完成FTP登录授权。此外,消息处理器可以根据客户端会话是否已经完成Pure-FTPD中的授权来针对同一请求消息执行不同的代码逻辑。然而,即使已经引入了多个启发式规则,静态分析结果仍然可能包含一些误报。

推断状态模块

在进行网络服务的有状态模糊测试时,NSFuzz能够推断出服务的状态模型。通过对LightFTP进行12小时的模糊测试后,NSFuzz推断出了一个包含5个顶点和12条边的状态模型。在LightFTP中,静态分析提取了一个名为Access的状态变量,用于表示客户端会话的访问权限。经过手动分析源代码,发现Access有4个固定值,分别代表客户端用户的不同权限(未登录、只读、新建、完全权限),LightFTP会根据用户权限进行不同的消息处理过程。与其他模糊测试工具相比,NSFuzz推断的状态模型在准确性和解释性方面更优秀。同时,NSFuzz能够识别网络服务中更细粒度的状态,用户可以选择监视哪些状态变量来构建状态模型,实现不同粒度的状态模型推断。

Snipaste_2023-08-12_20-01-55.png

Snipaste_2023-08-12_20-02-35.png

Fuzz有效性评估(评估2)

  1. 模糊测试吞吐量:模糊测试吞吐量表示每秒执行的测试用例数量。显然,更高的模糊测试吞吐量意味着被测试程序执行了更多的测试用例,整体测试效率也更高。表V显示,NSFuzz的模糊测试吞吐量明显优于AFLNET和其他工具。在不同的目标服务中,NSFuzz的模糊测试吞吐量提高了1倍到50倍以上。由于STATEAFL需要在模糊测试过程中收集变量值以进行后执行分析以进行状态模型推断,STATEAFL引入的额外开销导致其模糊测试吞吐量较AFLNET下降。值得注意的是,AFLNWE是唯一一个没有状态感知的模糊测试工具,与AFLNET相比,它的模糊测试吞吐量也有所提高。这主要是因为AFLNWE只是AFL的一个支持网络I/O的版本,只发送一次数据给被测服务,从而节省了多次网络交互中的等待延迟和状态相关的开销。然而,即使在这种情况下,AFLNWE的模糊测试吞吐量仍不如NSFuzz,这证明了基于轻量级插桩的NSFuzz的同步机制可以显著提高整体模糊测试效率。

Snipaste_2023-08-12_20-03-13.png

  1. 代码覆盖率:代码覆盖率一直是评估模糊测试工具的标准指标,它表示在整个模糊测试过程中执行了被测试服务中多少代码。通常,代码覆盖率越高,可能触发的程序漏洞就越多。表V显示,NSFuzz在几乎所有目标服务上都能达到更高的代码分支覆盖率。此外,虽然AFLNWE在这些模糊测试工具中具有相对较高的模糊测试吞吐量,但由于缺乏多个网络I/O交互和状态指导,在模糊测试网络服务时无法实现良好的代码覆盖率。另外,STATEAFL在12小时的模糊测试中所覆盖的代码分支平均数量与AFLNET之间没有显著差异。图4显示了几种模糊测试工具在12小时模糊测试过程中探索的代码分支数量随时间的增长情况。从图中可以看出,NSFuzz不仅在大多数目标服务上能够覆盖更多的代码分支,而且能够比其他任何模糊测试工具更快地探索这些分支。

Snipaste_2023-08-12_20-03-34.png

  1. 崩溃触发:除了模糊测试吞吐量和代码覆盖率之外,崩溃触发直接反映了模糊测试工具的漏洞发现能力。表IV展示了不同模糊测试工具在模糊测试目标网络服务时触发第一个崩溃所花费的时间。如表所示,与其他竞争对手相比,NSFuzz在相同的目标上能触发崩溃,且触发第一个崩溃的平均时间明显较短。特别是在对TinyDTLS网络服务进行模糊测试的过程中,NSFuzz总能在不到1秒的时间内触发程序崩溃,这在一定程度上表明NSFuzz在模糊测试网络服务时能更快地触发潜在的漏洞。

Snipaste_2023-08-12_20-03-49.png

总结与展望

首先,NSFuzz的静态分析部分仅支持分析C语言目标,而不支持C++目标的分析。这主要是由于C++中的虚函数生成了间接调用,导致难以构建准确的调用图,从而影响了静态分析的结果。其次,一些网络应用程序使用事件驱动库(如libevent)来构建其服务程序。在这种情况下,我们定义的网络事件循环是在库中实现的,而不是在服务代码中,这给静态分析器找到在哪个位置插入raise函数以实现同步带来了挑战。受IJON和其他相关工作的启发,研究人员计划将注释机制引入NSFuzz,作为静态分析器的补充。他们将设计几个API来帮助用户在SUT中手动注释状态变量和同步点,这有望提高NSFuzz的适用性和可扩展性。

此外,当前的初步评估缺乏充分的消融研究,即评估基于变量的状态表示方案对整体模糊测试效率的影响。因此,研究人员将在未来进行相应的消融实验,以研究准确状态表示在网络服务模糊测试中的影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值