阅读笔记——《A Framework of High-Speed Network Protocol Fuzzing Based on Shared Memory》

参考文献
参考文献
Abstract
- 近年来,基于模糊测试的网络协议安全测试越来越受到关注。与无状态软件模糊测试相比,这是一项极具挑战性的任务,且早期的大多数网络协议模糊测试工具速度较慢,测试效果不佳。自从第一个灰盒和有状态模糊测试工具AFLNET被提出以来,已经设计了多种新方案,从不同方面提升其性能。
- 在研究过程中,一个重要挑战是如何大幅提高模糊测试的效率。基于SNPSFuzzer中的基础分析,本文对13种网络协议在一次模糊测试迭代中的时间消耗进行了更深入的分析,并设计了一种名为HNPFuzzer的高速网络协议模糊测试工具。在HNPFuzzer中,客户端和服务器之间的测试用例和响应消息通过共享内存传输 ,由精确的同步器引导,而不是通过套接字接口 。这大大缩短了每次迭代的时间。此外,我们设计了一种持久模式,基于副作用信息的分析,尝试多次模糊测试内存中的服务实例 。该模式进一步提高了模糊测试的速度。
- 实验结果表明,我们的方案平均可以提高模糊测试的吞吐量约39.66倍,并触发了大量崩溃,其中包括现有模糊测试工具未发现的2个新漏洞。值得注意的是,现有的网络协议模糊测试方案虽然提出的方向不同,但彼此并不竞争,相反,它们可以协同工作以提升整体模糊测试的效果和效率。因此,更多现有工具可以集成到我们的框架中,以获得更好的网络协议模糊测试效果。
1、Introduction
- 从软件模糊测试转移到网络协议模糊测试并非直接了当,以下是总结的五个主要挑战:
- 网络协议更加复杂,涉及一组不同的参与者。因此,模糊测试协议的框架也更为复杂,与软件模糊测试框架有很大不同。
- 在网络协议模糊测试中,初始种子更难生成。通常,协议的技术规范(TS)非常复杂,并且通常会精确定义输入消息的结构。基于突变的随机生成消息(在软件模糊测试中常用)表现不佳。
- 与普通无状态软件相比,网络协议引入了一个新概念,即协议状态。协议的状态极大地增加了发现新程序路径的难度。此外,要到达特定状态,必须遍历所有前置状态,这使得效率更低。
- 模糊测试过程中信息流的路径被拉长。为了与被测服务器(SUT)进行通信,消息通常需要嵌入套接字中并传输到SUT。在服务器端,这些消息还需要从套接字中恢复。与软件模糊测试相比,这种方式效率较低。
- 最后但同样重要的是,在模糊测试过程中,SUT需要反复重启。在重启的初始阶段,SUT需要读取和处理配置文件、初始化变量并准备接收服务请求。这个过程在计算资源和时间消耗方面也是一个巨大负担。
- 如何减少模糊迭代的时间消耗还没有得到深入的研究。本文对模糊迭代中的时间消耗分布进行了详细的分析,发现模糊效率可以从几个方面大大提高。基于这些有趣的发现,我们设计了一个名为HNPFuzzer的高速网络协议模糊框架。
- 首先,通过套接字接口在受控客户端(CUC)和被测服务器(SUT)之间传输消息非常耗时,这是导致网络协议模糊测试效率下降的最大因素。在HNPFuzzer中,CUC和SUT并不通过套接字接口进行通信,而是基于共享内存传输消息 。为实现这一目标,我们分析了客户端/服务器架构,并收集了与套接字接口相关的库函数。特别地,能够读取或写入文件描述符的函数(如
write()或read())也包含在内,因为套接字是文件描述符。然后,我们通过LD_PRELOAD机制挂钩了这些相关函数,并设计了一个连接控制器,用于基于共享内存控制客户端和服务器之间的数据传输。(基于套接字传输效率低) * 其次,在协议模糊测试中,同步过程导致的时间延迟不可忽视,这与软件模糊测试完全不同。如果没有精心设计的同步器,系统很容易变得异步。因此,我们在HNPFuzzer中基于共享内存仔细设计了一个同步器,分别讨论了CUC与SUT之间、父进程与子进程之间、一组事件循环的同步过程。 - 第三,现有模糊测试工具中的分叉服务实例在一次模糊测试迭代后会被直接终止,重启实例浪费时间。如果能够对同一个实例进行多次模糊测试,效率将大大提升。在HNPFuzzer中,我们设计了一个机制来监控实例的环境并在一次迭代后检查其状态。如果实例没有被污染,我们将执行另一轮模糊测试,从而进一步提高模糊测试效率。(重启实例浪费时间)
- 首先,通过套接字接口在受控客户端(CUC)和被测服务器(SUT)之间传输消息非常耗时,这是导致网络协议模糊测试效率下降的最大因素。在HNPFuzzer中,CUC和SUT并不通过套接字接口进行通信,而是基于共享内存传输消息 。为实现这一目标,我们分析了客户端/服务器架构,并收集了与套接字接口相关的库函数。特别地,能够读取或写入文件描述符的函数(如
- 本文详细分析了如何基于共享内存提高模糊测试速度,并实现了一个用于网络协议模糊测试的测试框架。本文的主要贡献总结如下:
- 我们对模糊测试迭代中不同部分的时间消耗分布进行了深入分析。基于分析结果,我们设计了一个名为HNPFuzzer的高速网络协议模糊测试框架,使用共享内存实现。
- 提出了一个连接控制器,通过两个共享内存块在受控客户端(CUC)和被测服务器(SUT)之间交换消息。与基于套接字的消息共享方式相比,这种新方案效率更高。此外,连接控制器还实现了持久模式,可以跳过模糊测试中的初始化阶段。
- 我们设计了一个基于共享内存的精密同步器,用于同步模糊测试过程中不同组件的状态。这对于整个模糊测试过程的稳定性至关重要。
- 我们进行了多项实验来评估HNPFuzzer的性能。仿真结果表明,在模糊测试吞吐量、分支覆盖率以及漏洞发现能力方面,我们的方案表现良好。
2、Related Work
。。。
3、Motivation
。。。
Research on the Time Distribution Analysis of Network Protocol Fuzzing Iterations
- CUC与SUT之间基于套接字的通信开销。
- 同步操作导致的时间延迟。
- 服务器初始化的时间开销。
3.3、The Main Idea of HNPFuzzer
- 通过深入研究模糊迭代过程及其所需的时间消耗结构,我们可以得出结论,在以下几个方面可以显著缩短一个测试迭代的周期。
- 套接字消息传输在CUC(受控客户端)和SUT(被测服务器)之间耗时较多。
- 在HNPFuzzer中,我们使用共享内存模拟网络功能来降低套接字消息传输的时间消耗。
- 我们还能够优化共享内存同步机制。
- 通过引入持久模式,在HNPFuzzer中降低了服务器初始化的时间成本。
4、OVERALL FRAMEWORK OF HNPFUZZER

如图5所示,在HNPfuzzer的工作流程中主要包含两个核心环节:即初始化环节与模糊测试循环环节。本节将重点阐述初始化环节,并并对模糊测试循环这一核心环节进行深入探讨。
4.1、Initialization Phase
- 大多数现有网络协议模糊测试方案均存在以下共同特点:即在完成一轮模糊测试迭代后,默认会对服务实例进行终止操作。这种做法并非完全没有问题,在实际应用中可能存在污染环境的现象影响后续测试效果。为了进一步提升整体效率,在HNPFuzzer中我们引入了持久模式机制。这一概念最早由AFL团队提出并加以发展完善,在该模式下系统将通过持续多次运行目标软件实现更为高效的模糊检测。
- 在将此思路推广至针对有状态的网络协议进行模糊测试时会面临以下主要挑战:即如何保证主事件循环入口处初始状态的一致性不受其他操作的影响。
- 为了确保持久模式下的稳定运行必须严格保证主事件循环入口处程序状态的一致性不受外界因素干扰为此我们特别关注那些可能被修改的数据块并对其生命周期进行精确控制。
- 通过LLVM框架对目标程序进行插桩探测是实现上述功能的关键步骤具体而言我们会在特定存储指令及其相关操作中植入监测逻辑以便实时跟踪所有可能影响系统运行状态的变化点。
- 需要注意的是在当前实现版本中针对堆内存的插桩探测功能仅会在主事件循环启动后才会生效这一设计旨在确保检测流程与算法定义相一致。
- 基于上述原理此类探针统称为"内存监控器"它们构成了HNPFuzzer框架的核心监测机制。

- 在主事件循环中分配的内存区域 (Memory Areas Allocated in the Main Event Loop) * 用户提供的堆内存通常作为系统资源使用,在用户指定的时间前无法被系统回收。因此,在不再需要时未被释放的资源将导致资源浪费,并可能抵消持久模式带来的性能优势。当大量资源未被回收时会浪费大量计算资源,并可能抵消持久模式带来的性能优势。我们仅关注于主事件循环中的分配情况。
* 为了检测此类潜在的问题,在编译阶段我们采用了特定插桩工具来分析程序运行情况。该插桩工具捕获了所有与动态内存管理库相关的函数调用(如malloc()、calloc()和free()),并将结果记录下来以便后续分析。
* 在完成初步分析后进一步检查相关数据以确认是否存在潜在问题。
4.2、Fuzzing Loop Phase
- 在初始化阶段结束后,HNPFuzzer进入模糊测试循环,这是整个模糊测试过程中的主要组成部分。在模糊测试循环中,我们首先需要分析待测目标协议,实现一套特定于协议的消息解析器,并构建模糊测试循环的测试用例。
- 模糊测试循环每次迭代通过
connect()创建CUC(受控客户端)与SUT(被测服务器)之间的连接。特别地,连接控制器负责客户端和服务器之间的通信。然而,HNPFuzzer并不通过套接字接口传输消息,该接口仅用于绕过服务器中的众多与套接字相关的一致性验证,例如在调用getsockname()等函数后的验证。在建立连接后,连接控制器开始将特定的套接字I/O操作转换为共享内存的读写操作。通过这种方式,模糊测试效率得到了极大提高。在控制器中,基于共享内存的同步器被用来确保连接控制器在适当的时间传输消息,从而缩短消息的延迟。 - 派生服务器负责准备作为测试目标的服务实例。通常,一个实例只能用于一次测试迭代,之后它将被终止并生成一个新的实例。然而,HNPFuzzer的持久模式允许一个实例经过多次测试迭代,这进一步提高了模糊测试的效率。
5、CONNECTION CONTROLLER 连接控制器
- 连接控制器是我们系统中最重要的组件。它的第一个功能是实现持久模式 ,第二个功能是支持客户端和服务器之间通过共享内存进行消息交换 。我们将CUC(受控客户端)和SUT(被测服务器)之间的连接分为三个阶段:连接创建、消息交换和连接终止 。整个过程由连接控制器控制,如图5所示。
- 第一个功能与连接创建和连接终止阶段相关。在连接创建后,我们认为服务器已经进入主事件循环。此时,插入的探针被启用以收集信息。收集信息的第一个功能是检测代表全局状态修改的长期数据修改。第二个功能是跟踪内存分配,以保护持久模式下的服务器免受内存泄漏的影响。当连接终止时,连接控制器会检查进程是否违反两条规则,以决定是否终止服务器进程。连接控制器如何检测连接创建和终止的详细信息在第V-A和V-C节中说明。
- 第二个功能是在消息交换阶段实现的,基于LD_PRELOAD挂钩。考虑到网络协议通常通过套接字传输消息,连接控制器通过挂钩与套接字接口相关的特定库函数,干预客户端和服务器之间的消息交换。例如,挂钩的
send()函数将消息写入共享内存,而不是调用真正的send()函数进行发送。更多的实现细节在第V-B节中讨论。
5.1、Creating the Connection
- 在客户端中,我们首先分析了客户端/服务器模型。通常,服务器依次调用
socket()、bind()、listen()和accept()来与客户端建立连接。我们注意到,bind()和accept()对于建立连接套接字非常重要。在HNPFuzzer中,连接控制器会自动从bind()的第二个参数中提取端口号,并与通过“-N”选项提供的目标端口进行比较,从而获取服务器套接字。然后,通过比较服务器套接字与accept()的第一个参数,可以获取连接套接字。然而,仅保存服务器套接字和连接套接字是不够的,因为调用fork()、dup()或dup2()会导致文件描述符(包括套接字连接)被复制。事实上,服务器通常会派生一个子进程并将连接套接字复制到标准POSIX文件描述符中,这是一个常见的设计模式。 - 我们引入了一个引用计数来表示持有连接套接字的进程数量,同时引入了一个名为
fd_table的数组来跟踪dup()和dup2()引起的复制。引用计数存储在共享内存中,用于检测连接的终止,而fd_table位于进程地址空间中,帮助检查当前进程中是否存在连接套接字。显然,dup()和dup2()中的任何套接字复制不会影响引用计数,但会触发fd_table中的复制操作。例如,调用dup2(fd1, fd2)会导致fd_table[fd2] = fd_table[fd1]的操作。当连接套接字及其所有副本在进程中都关闭时,引用计数会减少1;而当accept()创建连接套接字或fork()在连接套接字创建之后被调用时,引用计数会增加1。当引用计数降至0时,我们认为连接已关闭。 - 在获取到连接套接字后,连接控制器会将连接状态更改为“opening”(打开)。连接状态(用符号ρ表示)表示每次模糊测试迭代中客户端与服务器之间建立的连接状态。它有三种可能的状态分配:
- Uninitialized(未初始化):在创建连接套接字之前的状态;
- Opening(打开):连接套接字创建后;
- Closed(关闭):连接关闭后(引用计数为0)。
- 该状态的用途是支持某些阶段中的操作。例如,连接控制器在当前连接关闭之前不应该调用下一次
accept(),以便在进入主事件循环时进行与持久模式相关的检查。 - 在异步服务器中,可能在调用
accept()之前调用用于实现I/O多路复用的库函数,例如select()、poll()和epoll()。这与传统的同步服务器有所不同。在这两种情况下,同步器(synchronizer)负责安排调用这些函数的循环的工作流程。同步器的更多详细信息将在第VI节中讨论。
5.2、Exchanging Messages Based on Shared Memory
当CUC(客户端)与SUT(服务器)建立连接后,在相互之间开始交换测试用例与响应的消息。消息流分为两个方向:一方是从CUC向SUT发送测试用例;另一方是从SUT向CUC发送响应信息。为了实现同时接收与发送信息的需求;HNPFuzzer通过分配固定大小的缓冲区来实现数据传输;并通过重新生成更大的共享内存空间并进行相应映射设置;确保能够处理超出当前缓冲区容量的消息;从而实现了高效的数据流转机制设计意图为此;HNPFuzzer希望通过后续迭代更新覆盖掉尚未读取的数据部分

* CUC首先阻塞自己,直到SUT允许其发送消息(第1行)。
* 然后,在共享结构SA中,`Sizem`被初始化为`SizeM`(第2行),用于告知SUT消息的长度。
* 在主循环中(第4-17行),CUC将消息写入共享内存缓冲区。在内循环中,如果共享内存缓冲区中仍有剩余消息未处理(第10行),CUC会利用同步器通知SUT继续读取消息(第11行)。
* 由于无法控制SUT的接收缓冲区大小,SUT可能需要多次调用`recv()`来读取完整的消息。如果SUT调用类似`recv(fd, buf, sizeof(buf), 0)`的函数,而`buf`的大小小于`SA.buf`,则不能一次读取全部消息。因此,SUT需要多次调用`recv()`,并且每次调用后,CUC必须通过同步器恢复会话状态,以便SUT继续执行`recv()`(第11行)。
* 如果在消息交换过程中,连接被SUT关闭,CUC将返回-1,表示发生了意外行为(第12-15行)。
* SA结构被CUC和SUT共享,用于交换消息。它包括以下三个元素:
* Sizem: 当前要发送消息的长度;
* buf: 固定长度的缓冲区,保存整个消息或部分消息,取决于消息长度是否小于缓冲区大小;
* Sizeb: 缓冲区中未读取消息的长度。
* CUC必须等待SUT清空SA中的`buf`后,才能进入新一轮的循环迭代,以确保消息顺序传递,不会有未读数据残留。
- 算法3描述了SUT(服务器)如何接收消息的过程。SUT 在接收消息之前,必须等待 CUC(客户端)完成发送(第1行)。在主循环中,如果 SUT 的接收缓冲区比共享内存缓冲区小,SUT 会尽可能多地读取消息(第5-10行)。如果消息尚未完全传输,SUT 在完成消息读取后(第12-17行),需要通过同步器等待 CUC 发送剩余消息(第18-19行)。此时,阻塞的 CUC 将恢复并继续发送未发送的消息给 SUT。

- 当SUT向CUC发送响应消息时,在设计中增加了额外的缓冲区bufc。在发送消息时,在bufc中进行写入操作而不是直接放入共享内存缓冲区。仅当开始等待新消息或关闭连接时才会将bufc中的数据发送给CUC。该设计旨在解决SUT向CUC一次性发送多条响应消息的问题。
- 从SUT到CUC的消息发送算法类似于从CUC到SUT的消息发送算法(如算法2和3),不过其接收缓冲区的大小始终保持大于共享内存缓冲区。
5.3、Terminating the Connection Based on Memory Monitor
5.3.1、Memory Monitor
- 在内存检查过程中,首先通过检查由连接控制器设置的连接状态

以确定SUT是否处于主事件循环为目标

的集合中。如果这些内存区域中的某个被释放,内存监视器将从

- 当检测到某块持久化模式中的内存区域被修改时(long-lived memory),系统内的监控机制会自动触发并设置一个标志位 G 为
true。此操作仅用于指示全局状态的变化可能性。 - 需要采取以下两个主要措施:
- 降低额外资源消耗:由于持久化模式旨在加速模糊测试流程,请尽量减少该机制引入的相关开销。
- 确保资源正确释放:我们假设在连接终止时所有分配给该连接的动态内存均会被彻底清除。
5.3.2、Connection Termination
该连接终止的过程由图 6 绘制。
在 HNPFuzzer 中的SUT负责维护并关闭其创建的套接字。
当该连接套接字的引用计数值降至零时,
则认为该连接处于已关闭状态。

也被标记为关闭。
*

- 一旦连接关闭,连接控制器将验证两个规则是否被违反,即内存块集合

应为空且变量 G 未被修改。如果

当空且G为假(全局状态保持不变)时,该控制器将发送SIGSTOP信号以通知forkserver连接已终止,否则该控制器将立即退出随后,forkserver将通过管道传输状态码至模糊测试器
6、SHARED-MEMORY BASED SYNCHRONIZER 基于共享内存的同步器
- 同步器充当控制器的连接者角色,并作为其关键元素发挥作用。当处理模糊信息时,它被用来同步各个组件的状态。
6.1、Implementation of the Two Primitives 两种原语的实现
- 同步器通过称为会话状态的变量来实现功能,并要求所有对会话状态的操作必须是原子操作。我们实现了两个关键函数:
shm_notify()和shm_wait()。
shm_wait()的作用是阻塞线程直到收到通知某个特定的会话状态已经到达;而shm_notify()则用于设置会话状态以恢复被阻塞的线程。 - 除了Futex(快速用户空间互斥锁)和忙等待(busy waiting),还有其他替代方案可实现这些同步功能。其中FUTEX_WAIT 和 FUTEX_WAKE 的功能与我们的同步器一致;然而,在考虑到其他同步机制如互斥锁或条件变量时发现这些方案并不适用。相反地, 由于忙等待不涉及任何系统调用操作, 因此其性能可能优于Futex机制。
- 我们基于修改后的IPC-benchmark平台进行了实验研究,结果显示:使用共享内存的方式在吞吐量上分别比基于互联网套接字的方式提升了1.9倍和61.7倍的增长幅度。值得注意的是, 基于忙等待机制的表现明显优于Futex机制,这一现象可能源于Futex所带来的上下文切换开销问题。
因此,在HNPFuzzer工具中,我们选择了忙等待机制来实现这两个核心同步功能。

本节将介绍实时数据传输与处理系统的运行依赖于一套高效可靠的客户端与服务器间的同步机制
- 在有状态网络协议模糊测试过程中,我们需要对与目标状态对应的消息进行变异,并且有必要对客户端和服务器进行同步。然而,不同的SUT(被测系统)由于其协议和实现的不同,具有各自不同的工作流,这增加了同步的难度。在实际应用中,一些网络协议可能会违反“一请求一响应”的模式。例如,在TLS协议中,客户端可以连续发送“变更密码规范”消息和另一条加密消息;在Lightftp(一种FTP实现)中,服务器可以对一个“list”命令消息发送两个状态码150和451作为响应。
- 挑战在于如何在模糊测试不同协议的上下文中正确匹配请求和响应。通常来说,传统的有状态网络模糊测试工具在调用
send()或recv()之前使用poll()并手动设置超时时间来解决这个问题,然而这种模式会为模糊测试迭代引入额外的时间延迟。尤其是,如果为poll()函数设置了较短的超时参数,结果可能会更糟糕,因为有状态模糊测试工具可能会与其状态机不同步。 - 上述问题的根本原因在于客户端和服务器两端无法预测对方接下来要执行的操作。为了解决这个问题,我们在方案中引入了会话状态(session state),并将其存储在共享内存中。会话状态可以是“C”或“S”两种状态。其中,“C”表示客户端正在发送或接收消息,此时服务器应该阻塞等待,反之亦然,“S”表示服务器正在发送或接收消息,客户端则应阻塞。
- 因此,一旦任一端完成了当前任务,或无法继续执行而需要对方完成其任务时,它应使用
shm_notify()来更改会话状态,从而通知对方执行下一个任务。这种操作本质上是状态转换。通过这种方式,两端的同步可以通过修改共享内存中的一个变量来实现,而无需盲目等待。图7展示了客户端和服务器中的可能会话状态转换,我们会详细介绍每个转换过程。 - 由于会话状态只能是“S”或“C”,因此任何时刻都只有客户端或服务器一方在正常。值得一提的是,使用忙等待时不会出现唤醒信号丢失的情况,因此不会发生一方错过对方唤醒信号导致双方都阻塞的情况。类似地,也不会出现一方在等待某个状态,而另一方等待消息的情况,因为在这种情况下,被hook的
recv()不会阻塞,且会话状态必然会发生切换。- S → S : 该状态转换发生在客户端被
shm_wait()阻塞时(例如,算法2中的第1行)。 - C → C : 该状态转换发生在服务器被
shm_wait()阻塞时(例如,算法3中的第1行)。 - S → C : 该转换发生在以下五种情况中:
- i. 服务器完成消息发送;
- ii. 消息长度超过共享内存缓冲区,服务器通知客户端发送剩余部分;
- iii. 服务器开始接收消息但发现共享内存缓冲区为空;
- iv. 客户端收到
SIGALRM信号; - v. 服务器退出或停止。
- C → S : 该转换发生在以下四种情况中:
- i. 客户端完成消息发送;
- ii. 消息长度超过共享内存缓冲区,客户端通知服务器发送剩余部分;
- iii. 在每个会话开始时;
- iv. 客户端即将结束会话。例如,客户端完成消息读取且没有更多消息发送。
- S → S : 该状态转换发生在客户端被
- 在数据传输过程中,我们通过共享内存区域来传递一方的状态到另一方。通过这种方式,CUC(客户端)和SUT(服务器)都能在适当的时间点做出最佳选择。相比基于套接字接口的数据传输,我们的方案有效减少了同步过程带来的时间延迟。
- 此外,另一个挑战是如何追踪状态转换中的事件。在HNPFuzzer中,事件通过不同方式进行追踪,最重要的两种方式如下所示:
- 通过监控内部变量,如SA.Sizeb和SA.buf的长度,可以检测到一些事件。
- 通过钩取特定的系统函数,如
send(),也可以追踪到事件。有关更多详细信息可以参考第IV和V节。
6.3 父进程与子进程之间的同步 Synchronization Between Parent Process and Child Processes
- 许多SUT(系统在测)在与CUC(客户端)通信时需要调用
fork(),这带来了另一个挑战,即存储在bufc中的响应消息可能会被多个进程重复发送,因为bufc会随着fork()而被复制。因此,我们将bufc创建为共享内存对象,并使用mmap()将其映射到进程的地址空间中,以避免重复。这意味着我们必须在进程间同步bufc的大小,而不能直接使用realloc()来扩展bufc。 - 具体来说,我们引入了两个变量:
bufc的大小(用sizec表示)和sizemax。前者在进程间共享,后者则保存在每个进程的地址空间中。当一个进程需要扩展bufc时,它会更新这两个变量。如果一个进程发现它的sizemax不等于sizec,这表明其他进程已经扩展了bufc,此时该进程需要更新它的sizemax并重新映射bufc。需要注意的是,这些操作通过Futex实现的锁来保证原子性。然而,单靠锁并不能完全保证操作的原子性。因为在获取锁之后,如果线程被信号中断,可能会发生死锁。因此,我们的同步器通过pthread_sigmask()在获取锁之前屏蔽当前线程中的信号,以防止这种情况的发生。
6.4、Synchronization Among Event Loops 事件循环之间的同步
在服务器中存在多个事件循环其中一些对客户端与服务器之间的通信起到关键作用(例如accept循环与select循环)。这些事件循环可以在不同线程或进程中同时运行。例如在OpenSSH环境中父进程会在server_accept_loop()函数中执行accept循环而子进程中则会在client_loop()函数中执行select循环。我们必须保证accept循环不会在客户端循环完成之前调用accept()函数因为模糊测试器仅创建一个连接并且需要通过内存监视器验证θ与G参数。
因此挑战在于如何协调这些函数的工作顺序我们的同步器会检查传递给这些函数的文件描述符集合(例如在accept()函数中的sockfd参数)。如果发现存在服务器套接字则同步器会随后检查ρ值以确认是否有已建立连接。之后根据当前状态决定是否需要阻塞相关线程直到所有已建立连接完成释放。
值得注意的是当处理I/O多路复用操作时如果将套接字传递给相应的多路复用函数同步器会将其从文件描述符集合中移除这是因为除了建立新连接外多路复用操作不会发送数据包。此外如果超时时间被设置为无限大可能导致无法及时处理某些操作为此我们将超时时间设为0并在结果集中记录被移除的套接字这样能更好地利用共享内存机制提升性能。
7、PERFORMANCE EVALUATION OF HNPFUZZER
- 与其相比(基准网络协议模糊器),HNPFuzzer其模糊效率是否能够实现更高的水平?
其(HNPFuzzer)是否能够在主流网络协议中比现有工作发现更多的漏洞?
7.1、Fuzzing Throughput

7.2、Performance Breakdown

7.3、Code Branch Coverage


7.4、Vulnerability Discovery

8、CONCLUSION
在本文中,我们设计了一种名为HNPFuzzer的高速网络协议模糊测试方法,在降低进程间通信(IPC)的时间开销以及同步初始化阶段的时间开销方面进行了优化设计以提升模糊测试效率。我们实现了基于共享内存机制的复杂连接控制器来管理受控客户端(CUC)与被测服务器(SUT)之间的高速数据传输过程,并在此过程中建立了消息发送与接收之间的同步机制以确保双方能够实时获取彼此的状态信息。这种方法相较于传统手动设置超时时间的方式更具优势。
此外,在利用初始化与准备行为构建的程序环境方面我们实现了持久模式功能该模式通过动态监控内存状态来决定何时退出系统或仅关闭被测服务器从而最大限度地节省初始化时间以减少运行 overhead. 在实验过程中我们发现某些服务中如Forked-daapd终止被测服务器的过程较为缓慢这一现象主要归因于其中包含的信号处理程序耗时较长. 由于HNPFuzzer采用了主动终止策略而非依赖CUC发送的SIGTERM信号导致其在这些情况下表现出了显著的效率提升。
模拟结果显示HNPFuzzer相较于传统网络协议模糊测试工具在测试效率与漏洞发现能力方面均表现出明显优势未来研究方向之一是将本方法与基于快照的网络协议模糊测试方案相结合例如SNPSFuzzer和Nyx-Net等此类工具通过协同工作进一步提升模糊测试效率这一方向既具有理论意义也具备实际应用价值
