- 【参考文献】Pham V T, Böhme M, Roychoudhury A. Aflnet: a greybox fuzzer for network protocols[C]//2020 IEEE 13th International Conference on Software Testing, Validation and Verification (ICST). IEEE, 2020: 460-465.
- 【注】本文仅为作者个人学习笔记,如有冒犯,请联系作者删除。
目录
[2、Example: File Transfer Protocol](#2、Example: File Transfer Protocol)
[3、Tool Design and Implementation](#3、Tool Design and Implementation)
[3.1、Request Sequence Parser](#3.1、Request Sequence Parser)
[3.2、State Machine Learner](#3.2、State Machine Learner)
[3.3、Target State Selector](#3.3、Target State Selector)
[3.4、Sequence Selector](#3.4、Sequence Selector)
[3.5、Sequence Mutator](#3.5、Sequence Mutator)
[4、Case Studies](#4、Case Studies)
[4.1、Code coverage and state coverage](#4.1、Code coverage and state coverage)
[4.2、Vulnerability discovery](#4.2、Vulnerability discovery)
[5、Future Work](#5、Future Work)
Abstract
- 对服务器进行模糊测试很困难。服务器有巨大的状态空间,只有使用良好的输入消息序列才能有效地遍历该状态空间。
- 本文提出了AFLNET,针对协议实现的灰盒fuzzer。与现有的协议fuzzers不同,AFLNET采用突变的方法,并且使用状态反馈来指导模糊测试过程。AFLNET以服务器和客户端之间记录的交换消息作为种子,不需要协议规范或消息语法。
- AFLNET充当客户端,重发原始消息序列的变体到服务器,并保留那些有效增加代码或状态空间覆盖的变体。为了标识由消息序列执行的服务器状态,AFLNET使用服务器的响应码。根据响应码,AFLNET识别状态空间中的前进区域,并系统地转向这些区域。
- 用AFLNET对两种流行的协议实现进行测试的案例表明,与最先进的技术相比,AFLNET的性能有了实质性的提升。并且AFLNET发现了两个新的CVEs。
1、Introduction
- 对于最先进的fuzzers,如基于覆盖率的灰盒fuzzers (CGF)和有状态的黑盒fuzzers (SBF),存在一些挑战。
- 服务器是有状态的且由消息驱动的。它从客户端接收一些列消息(又称请求),处理这些消息并发送对应的响应。然而,实现的协议可能不完全对应于指定的协议。
- 服务器响应依赖于当前消息和由早期消息控制的当前服务器内部状态。同时,普通的基于覆盖率的灰盒fuzzers(如AFL)即不知道服务器的状态信息,也不知道要发送的消息所需要的结构或顺序。这种fuzzers主要用于测试无状态程序(例如,文件处理程序),为这些程序生成输入,不维护或考虑内部状态。
- 开发人员只在当前基于覆盖率的灰盒fuzzers上寻求解决方案。他们需要编写测试工具来对被测服务器的特定程序状态进行单元测试,或者将消息序列连接到文件中,将它们作为种子来执行对种子进行变异的模糊测试。这两种方法存在不足:
- 虽然单元测试在某些特定的程序状态下是有效的,但它可能无法彻底地测试几个状态之间的转换。此外,编写新的测试工具来维护正确的程序状态并避免误报通常需要大量的工作。重点是,它不适用于端到端的模糊测试来测试整个服务器,该服务器的源代码可能不可得。
- 处理连接的文件会导致寻找bug的效率低下和无效。首先,每次迭代时需要选择特定的种子文件进行突变。给定一个文件f,该文件是通过连接m1到mn的消息序列构建的,GCF会平等地改变所有的消息。假设mi是最有趣的消息(例如,探索它会导致更高的代码覆盖率和潜在的错误),CGF在处理mi之前重复地对消息m1到mi-1进行变异,并且不关注mi的信息。其次,由于缺乏状态转换信息,CGF可能会产生许多无效的消息序列,这些消息序列很可能被SUT拒绝。事实上,AFL的用户也非常清除这些限制,因此他们向开发者提出了几个请求和问题。图1显示了AFL用户请求有状态模糊测试支持的两个请求。
- 由于前面提到的CGF对有状态服务器模糊测试的局限性,最流行的技术仍是有状态黑盒fuzzers (SBF)。如:Sulley、BooFuzz和Peach。这些工具以有限状态机或图的形式遍历给定的协议模型,并利用数据模型生成消息序列对SUT进行测试。然而,它们的有效性在很大程度上取决于给定状态模型和数据模型的完整性,这些模型通常是基于开发人员对协议规范的理解和客户端与服务器之间捕获的流量样本手动编写的 。这些手动提供的模型可能无法正确捕获SUT内部的协议实现。协议规范包含数百页的离散文本,开发人员可能误解现有状态或添加新的状态或转换。此外,SBF没有为进一步的模糊测试保留有趣的测试用例。更具体地说,即使SBF可以产生导致新的有趣状态的测试用例,这些状态没有在它的状态模型中定义,SBF也不会为进一步的探索保留这些有价值的测试用例。并且,它也不会在运行时更新状态模型。
- 在这项工作中,我们介绍了AFLNET------第一个有状态CGF (SCGF)工具,以解决当前CGF和SBF方法的上述局限性。
- AFLNET使用自动状态模型推理和覆盖引导模糊测试协同工作;模糊测试有助于生成新的消息序列来覆盖新的状态,并使状态模型逐渐更加完整。同时,动态构建的状态模型通过使用保留消息序列的状态覆盖和代码覆盖信息,帮助将模糊测试推向更重要的代码部分。
- 本文评估了AFLNET对两个著名协议的模糊测试:文件传输协议(FTP)和实时流协议(RTSP)。
2、Example: File Transfer Protocol
- 本案例,fuzzer充当客户端,服务器充当测试对象。两个网络参与者都要发送消息。消息是一个独立的数据包。消息序列是消息的向量。消息的顺序由协议控制。来自客户端的消息称为请求,来自服务器的消息称为响应。每个请求可以推进服务器的状态,例如,从初始状态到身份验证。服务器状态是服务器与客户端进行通信的特定状态。
- 列表1展示了客户端和LightFTP之间根据文件传输协议(FTP)进行的消息交换。客户端发送的消息序列用红色突出显示。FTP客户端首先在服务器上验证自己。只有认证通过后,客户端才能发出其他命令。对于来自客户端的每个请求消息,FTP服务器用包含状态码的响应消息进行应答(例如,230[登录成功]或430[用户/通过无效])。响应中的状态码确保客户端请求得到确认,并通知客户端当前的服务器状态。
3、Tool Design and Implementation
- AFLNET作为AFL的扩展,其结构如图2所示。为了方便与服务器进行通信,我们使用套接字进行网络通信。AFLNET支持两个通道,一个用于发送,一个用于接收来自被测服务器的响应。
- 响应接收通道除了代码覆盖反馈通道之外,还形成了状态反馈通道。AFLNET使用标准的C Socket API(即connect、poll、send和recv)来实现这一功能。
- 为了确保AFLNET与被测试服务器之间的正确同步,我们在请求之间添加了延迟。否则,如果在发送响应并确认之前收到新消息,某些服务器实现会断开连接。
- AFLNET的输入是包含捕获的网络流量的pcap文件(例如FTP客户端和FTP服务器之间的请求和响应,如表1所示)。为了在pcap文件中记录客户端和服务器之间的真实消息交换,可以使用网络嗅探器(例如tcpdump)。可以使用数据包分析器提取相关的消息交换。例如,我们使用数据包分析器Wireshark自动提取FTP请求序列。
3.1、Request Sequence Parser
- AFLNET使用其**请求序列解析器 (Request Sequence Parser)**组件来生成消息序列的初始语料库。AFLNET利用消息结构的协议特定信息,从捕获的网络流量中按顺序提取单个请求。它首先从pcap文件中过滤掉响应。然后,它解析过滤后的流量以识别每条消息的开始和结束。
- 我们实现了一种轻量级方法,该方法根据给定协议找到消息的头部和终止符。例如,每条FTP消息以有效的FTP命令(如USER、PASS)开始,并以回车符和换行符(即0x0D0A)终止。捕获的FTP通信流量如下图所示。
- 此外,SCGF(有状态的灰盒fuzzer)将序列中每条消息与相应的服务器状态转换关联起来(如图3所示)。这是通过逐条发送消息并解析响应来完成的。
3.2、State Machine Learner
- 状态机学习器 (State Machine Learner) 获取服务器响应,并将新观察到的状态和转换加入到已实现的**协议状态机 (IPSM)**中。
- AFLNET将服务器响应读取到字节缓冲区中,提取协议中指定的状态码,并确定执行的状态(转换)。如果服务器响应中有新的状态码,则添加一个表示新状态的新图节点。
3.3、Target State Selector
- **目标状态选择器 (Target State Selector)**从IPSM中获取信息,以选择AFLNET接下来应该关注的状态。AFLNET采用几种启发式的方法来帮助目标状态选择器选择下一个状态,即通过计算IPSM中的统计数据。
- 例如,为了识别模糊测试的盲点,即很少被执行的状态,它选择状态s的概率与执行s的突变消息序列的比例(#fuzz)成反比**(状态s被选择的概率随着它的选择次数而减小)** 。为了最大化发现新状态转换的概率,AFLNET优先选择那些在之前选择时对增加代码或状态覆盖率特别成功的状态(#paths)。
- 值得注意的是,AFLNET只有在模糊测试过程运行足够长时间以积累统计数据后才开始应用这些启发式方法。在一开始,目标状态选择器会随机选择目标状态。
3.4、Sequence Selector
- 一旦选定目标状态s,**序列选择器 (Sequence Selector)**会从序列语料库中选择一个能够到达状态s的消息序列(即种子输入)。AFL/AFLNET将种子语料库(此处包含消息序列)实现为一个队列条目的链表。队列条目是一种数据结构,包含有关种子输入的相关信息。
- 此外,AFLNET维护一个状态语料库,该语料库由以下两部分组成:
- 状态条目列表,即包含相关状态信息的数据结构。
- 一个哈希映射,将状态标识符映射到执行对应状态的队列条目列表。
- 序列选择器利用这个哈希映射随机选择一个队列条目所表示的序列,以执行状态s。
3.5、Sequence Mutator
- **序列变异器 (Sequence Mutator)**通过协议感知变异操作符增强了AFL的fuzz_one方法。AFLNET是一种基于变异的模糊测试方法,即从语料库中选择一个种子消息序列,并对其进行变异以生成新序列。
- 基于变异的优点:
- 可以在没有协议规范的前提下利用真实网络流量生成新的有效新序列。相比之下,基于生成的方法需要详细的协议规范,包括具体的消息模型和协议状态机。
- 允许生成有趣的消息序列语料库。生成的导致发现新状态、状态转换或程序分支的序列被添加到语料库中,以进一步模糊化。
- 给定一个状态s和一个消息序列M,AFLNET通过突变生成一个新的序列M'。为了确保突变序列M'仍然执行到选择的状态s,AFLNET将原始序列为三个部分:
- 前缀M1 ,用于到达选定的状态s;(先到达选定状态,再对选定状态进行fuzz)
- 候选子序列M2,包含所有在执行M1后仍然保持在状态s的消息;
- 后缀M3,简单来说就是剩余的子序列,使得M1, M2, M3组合起来等于M。
- 变异后的消息序列。通过保持原始子序列M1,M'仍然可以到达当前fuzzer关注的状态s。变异的候选子序列mutate(M2)在选定状态s上生成一个替代消息序列。在我们最初的实验中,我们观察到替代请求可能不会立即显现,但会传播到后续的响应中。因此,AFLNET继续执行后缀M3。
- AFLNET提供了多种协议感知变异操作符来修改候选子序列M2。为了变异候选序列M2,AFLNET支持消息的替换、插入、重复和删除。除了这些协议感知变异操作符外,AFLNET还使用灰盒模糊测试中常见的字节级操作符,如位翻转以及字节块的替换、插入或删除。变异是堆叠的,即使用若干协议感知和字节级变异操作符来生成变异的候选序列。
- 生成的消息序列M'若被认为是"有趣的"会被添加到语料库c中。如果服务器响应包含以前没有观察到的新状态或状态转换(即,它们没有记录在IPSM中),则认为该序列是有趣的。如果一个序列覆盖了服务器源代码中的新分支,也被认为是有趣的。
- 现在我们将演示AFLNET的所有这些组件如何协同工作以模糊LightFTP服务器。假设AFLNET启动时只有一个包含网络流量的pcap文件,如表1所示。
- 首先,请求序列解析器解析pcap文件以生成一个单独的序列(如图3所示),并将其保存到语料库C中。
- 同时,状态机学习器基于响应码构建初始IPSM;这个初始IPSM包含图4中的黑色节点和转换。假设目标状态选择器选择状态331(USER foo OK)作为目标状态,序列选择器随后会从序列语料库C中随机选择一个序列,此时语料库C中只有一个序列。
- 之后,序列变异器识别出序列前缀("USER foo"请求)、候选子序列("PASS foo"请求)和剩余子序列作为后缀。通过使用堆叠的变异器对候选子序列进行变异,序列变异器可能会生成一个错误的密码请求("PASS bar"),导致进入错误状态(530 未登录)。在这个错误密码之后,它会重放后缀(例如,"MKD demo"、"CWD demo"),因为所有这些命令在成功认证之前都是不允许的,导致在状态530中循环。
- 最后,发送"QUIT"请求,服务器退出。由于生成的测试序列(如图5所示)覆盖了新的状态和状态转换(如图4中的红色部分所示),因此将其添加到语料库C和IPSM中。
4、Case Studies
- 我们评估了AFLNET的有效性,并与Boofuzz和AFLNWE进行比较。具体来说,我们比较了在两个协议实现上的24小时模糊测试活动中的平均分支覆盖率、状态覆盖率和暴露的漏洞数量,如图6所示。
- 为了减轻随机性的影响,我们对每个测试对象分别运行了BOOFUZZ、AFLNET和AFLNWE的20个独立实例。
4.1、Code coverage and state coverage
- 分支覆盖率、语句覆盖率和状态覆盖率。
4.2、Vulnerability discovery
- 对于所有的fuzzers,我们计算了发现的漏洞数量,并测量了他们暴露这些漏洞所花费的时间。AFLNET在所有错误上都优于这两种fuzzers。
5、Future Work
- 在未来的工作中,我们计划在其他流行且关键的协议(例如安全外壳协议(SSH)和简单邮件传输协议(SMTP))上进行更多实验,以评估AFLNET的有效性和效率。
- 此外,我们还计划通过增强AFLNET的状态机学习算法,使其支持不产生响应码的协议实现,从而扩大AFLNET的适用范围。