AFLNET:一种用于网络协议的灰盒模糊器-论文笔记

现有服务器模糊测试的困难性:

  1. 服务器具有庞大的状态空间
  2. 服务器的响应依赖于当前消息和内部服务器状态
  3. 现有模糊测试方法在处理服务器模糊测试时的局限性
  4. 协议规范和实际协议实现之间的不匹配

AFLNet的创新(解决问题):

  1. 变异方法:AFLNet采用了变异方法,通过对初始语料库中的原始消息序列进行变异来构建测试输入。这样可以生成多个变体,用以增加代码或状态空间覆盖率,进一步提高测试效果。
  2. 利用状态反馈:AFLNet利用服务器的响应代码作为状态反馈来指导模糊测试过程。通过分析反馈信息,AFLNet能够确定模糊测试中所涵盖的服务器状态,从而实现针对状态空间的引导和优化,提高测试效率和发现潜在漏洞的几率。
  3. 无需协议规范或消息语法:与现有协议模糊测试器不同,AFLNet不需要手动提供协议规范或消息语法。它以实际客户端与服务器之间记录的消息交换作为初始语料库,减少了对规范的依赖,并能更好地捕捉到实际协议实现中可能存在的差异。

现有模糊器无法有效地检测协议漏洞的原因:

  1. 协议具有状态:协议通常涉及到服务器和客户端之间的消息传递和状态转换。服务器根据先前消息的处理结果和当前状态生成响应。然而,经典的模糊测试工具往往无法理解协议的状态信息,无法模拟真实场景下的消息交互。
  2. 消息结构和顺序:协议规定了消息的结构和顺序,只有按照规定的方式发送消息,服务器才能正确处理。经典的模糊测试工具通常不了解消息的结构和顺序要求,只是随机生成字节进行模糊测试,无法产生有效地触发协议漏洞的消息序列。
  3. 缺乏协议规范:有些协议没有明确的规范或文档,只有实现的代码可供分析和测试。这使得模糊测试工具很难确定有效的测试输入和预期的响应,无法充分覆盖协议实现中的所有漏洞。

Introduction

网络协议漏洞发现的必要性

网络协议用于互联网服务器之间或与客户端之间进行高效可靠的通信。协议指定了两个或多个在线方之间可以交换的消息的确切顺序和结构。然而,从世界任何地方都能与服务器进行通信的能力为远程代码执行攻击提供了充分的机会。

现有模糊器面临的几个挑战

(基于覆盖率的灰盒模糊器CGF和有状态的黑盒模糊器SBF)

  1. 服务器是有状态且驱动消息的。它接收客户端的一系列消息(也称为请求),处理这些消息并发送适当的响应。然而,实现的协议可能并不完全对应于指定的协议。
  2. 服务器的响应取决于当前消息和当前内部服务器状态,而这些状态受之前消息控制。同时,像AFL和其扩展版本这样的基础CGF模糊测试器既不知道服务器状态信息,也不知道要发送的消息的所需结构或顺序。这些CGF模糊测试器主要被设计用于测试无状态程序(例如文件处理程序),这些程序针对当前输入生成输出,在这种情况下不维护或考虑任何内部状态。

目前的CGF为测试协议所实现的解决办法

  1. 开发人员需要为单元测试特定程序状态编写测试环境。
  2. 或者将消息序列连接成文件,并将其用作种子进行普通的变异文件模糊测试。
这些解决方案的问题
  1. 尽管单元测试在某些特定的程序状态下是有效的,但它可能无法全面测试多个程序状态之间的交互/转换。而且,编写新的测试环境以维护正确的程序状态并避免误报通常需要大量努力。更重要的是,它不适用于无法获取源代码的整个服务器的端到端模糊测试。
  2. 使用连接文件的方法在漏洞发现中效率和效果都很低。首先,对于每个模糊测试迭代,需要变异整个选择的种子文件。假设消息m_i 是最有趣的消息(例如,探索它将获得更高的代码覆盖率和潜在漏洞),CGF会重复变异不感兴趣的消息m_1 到 m_(i-1) ,然后再处理消息m_i ,它并没有关注消息m_i 的知识。其次,由于缺少状态转换信息,CGF可能会产生许多无效的消息序列,这些序列很可能会被SUT拒绝。

由于CGF在这种问题上的限制,目前对协议漏洞的测试主流仍是有状态的黑盒模糊测试(SBF),这些工具遍历给定的协议模型(以有限状态机或图的形式)并利用在各个状态接受的消息的数据模型/语法生成(语法上有效的)消息序列,并对SUT进行压力测试。但是,它们的有效性严重依赖于给定的状态模型和数据模型的完整性,这些模型通常是根据开发人员对协议规范和客户端与服务器之间的示例捕获网络流量的理解进行手动编写的。这些手动提供的模型可能无法正确捕捉SUT内部实现的协议。协议规范包含数百页的散文形式的文本。实现者可能会对现有状态进行误解,或者添加新的状态或转换。此外,与其他黑盒方法一样,SBF不会保留有价值的测试用例以供进一步模糊测试。具体来说,即使SBF能够生成导致新的未在状态模型中定义的有趣状态的测试用例,SBF也不会保留此类有价值的测试用例,也不会在运行时更新状态模型。

AFLNET

AFLNET - 第一个有状态的覆盖率引导模糊测试工具,旨在解决当前CGF和SBF方法的以上局限性。AFLNET通过使用保留的消息序列的状态覆盖和代码覆盖信息,自动推断状态模型并进行覆盖引导模糊测试,两者相互配合;模糊测试有助于生成覆盖新状态的新消息序列,并使状态模型逐渐变得更加复杂。与此同时,动态构建的状态模型有助于通过使用状态和代码覆盖信息将模糊测试驱动到更重要的代码部分。在两个著名协议的实现(文件传输协议-FTP和实时流媒体协议-RTSP)上对AFLNET进行了评估。初步结果显示,AFLNET在代码覆盖率、状态空间覆盖率和漏洞发现能力方面明显优于最先进的方法。AFLNET在一个RTSP实现中发现了两个之前未知的安全漏洞(已分配CVE编号)。

Example : FTP

一些术语和规定设置

服务器:可以远程访问的软件系统
模糊测试器充当客户端,服务器充当模糊目标。

为了交换信息,网络参与者都发送消息。一条消息是一个独立的数据包。一系列消息是一组消息的向量。消息的有效顺序受协议的规定。来自客户端的消息也被称为请求,而来自服务器的消息被称为响应。每个请求可以推进服务器状态,例如从初始状态到已认证状态。服务器状态是服务器在与客户端通信时的特定状态。

Snipaste_2023-07-27_16-30-06.png

列表 1 展示了在文件传输协议(FTP)和 LightFTP服务器之间的消息交换。客户端发送的消息序列用红色突出显示。FTP 规定客户端必须先在服务器上进行身份认证。只有在成功认证后,客户端才能发出其他命令(即传输参数命令和服务命令)。对于客户端的每个请求消息,FTP 服务器都会回复一个包含状态码的响应消息(例如 230 [登录成功] 或 430 [用户名/密码无效])。响应中的状态码确保客户端的请求被确认,并向客户端提供有关当前服务器状态的信息。

工具设计与实现

Snipaste_2023-07-27_16-30-068fd887463669d4e6.png

AFLNet基于AFL架构进行扩展

为了便于与服务器进行通信,首先实现了通过套接字进行网络通信的功能,这是原始的AFL所不支持的。

AFLNET支持两个通道,一个用于发送消息,一个用于接收服务器的消息/响应。接收响应的通道形成了状态反馈通道,除了所有CGF方法实现的代码覆盖反馈通道。AFLNET使用标准的C套接字API(即connect、poll、send和recv)来实现此功能。为了确保AFLNET与被测试的服务器之间的同步,我们在请求之间添加了延迟。否则,一些服务器实现在发送和确认响应之前接收到新消息时会断开连接。

AFLNET的输入是包含捕获的网络流量(例如FTP客户端和FTP服务器之间的请求和响应)的pcap文件。要在pcap文件中记录客户端和服务器之间的真实消息交换,可以使用网络嗅探器(例如tcpdump)。可以使用数据包分析器(例如Wireshark)来提取相关的消息交换。例如,我们使用数据包分析器Wireshark自动提取FTP请求的序列。

AFLNET使用其请求序列解析器组件来生成初始的消息序列语料库。AFLNET使用消息结构的协议特定信息从捕获的网络流量中提取单个请求,并按照正确的顺序进行提取。它首先过滤掉pcap文件中的响应,以获取客户端请求的跟踪。然后,它解析过滤后的跟踪,以识别跟踪中每个消息的起始和结束。实现了一种轻量级方法,根据给定协议中指定的消息格式来查找消息的头部和终止符。例如,每个FTP消息以有效的FTP命令(例如USER、PASS)开头,并以回车符后跟换行符(即0x0D0A)结束。此外,SCGF将序列中的每个消息与相应的服务器状态转换相关联(参见图3)。这是通过逐个发送消息并解析响应来完成的。

Snipaste_2023-07-27_19-47-00.png

状态学习器

状态机学习器使用服务器的响应来扩展已实现的协议状态机(IPSM),并添加新观察到的状态和转换。AFLNET将服务器响应读入字节缓冲区,提取协议中指定的状态代码,并确定执行的状态(转换)。如果服务器响应中有新的状态代码,将添加表示新状态的图节点。

目标状态选择器

目标状态选择器使用IPSM中的信息选择AFLNET应该关注的目标状态。AFLNET使用可以从学习得到的IPSM中的统计数据计算的多个启发式方法来帮助目标状态选择器选择下一个状态。例如,为了识别模糊测试中很少执行的状态,即模糊测试盲区,它选择一个状态s的概率与执行s的变异消息序列的比例成反比。为了最大化发现新状态转换的概率,AFLNET选择一个具有更高优先级的状态s,该状态在以前的选择中已经成功地对增加代码或状态覆盖率做出了贡献。值得注意的是,只有在模糊测试过程运行了足够长的时间以积累统计数据之后,AFLNET才开始应用这些启发式方法。在开始阶段,目标状态选择器随机选择目标状态

序列选择器

一旦选择了目标状态s,序列选择器从序列语料库中选择一个可以达到状态s的消息序列(即种子输入)。AFL/AFLNET将种子语料库(在这里包含消息序列)实现为队列条目的链表。队列条目是包含有关种子输入的相关信息的数据结构。此外,AFLNET还维护一个状态语料库,它包括:

  1. 状态条目的列表,即包含相关状态信息的数据结构
  2. 哈希映射,将状态标识符映射到用于执行与状态标识符对应的状态的队列条目的列表。

序列选择器利用哈希映射随机选择可以执行状态s的序列(如队列条目)来执行状态s。

序列变异器

序列变异器使用具有协议感知的变异操作符来扩展AFL的fuzz_one方法。AFLNET是一种基于变异的模糊测试方法,即从语料库中选择一个种子消息序列并进行变异以生成新的序列。与从头开始生成新消息序列的现有基于生成的方法相比,变异方法具有几个优点。首先,基于变异的方法可以利用真实网络流量的有效跟踪来生成可能有效的新序列,尽管完全没有协议规范。相比之下,基于生成的方法需要详细的协议规范,包括具体的消息模板和协议状态机。其次,基于变异的方法允许演化一个特别有趣的消息序列语料库。生成的序列已经导致了新的状态、状态转换或程序分支的发现,这些序列会被添加到语料库中以供进一步模糊测试。这种演化方法是基于覆盖率的灰盒模糊测试取得巨大成功的关键

给定一个状态s和一个消息序列M,AFLNET通过变异生成一个新的序列M’。为了确保突变序列M’仍然执行所选择的状态s,AFLNET将原始序列M分成三个部分:1)前缀M1需要到达所选择的状态s,2)候选子序列M2包含在M1之后可以执行的同时仍然保留在s中的所有消息,以及3)后缀M3仅仅是剩余的子序列,使得(M1,M2,M3) = M。突变的消息序列M’ = (M1,mutate(M2),M3)。通过保持原始子序列M1,M仍将到达状态s,这是模糊器当前关注的状态。突变的候选子序列mutate(M2)在所选择的状态s上产生备选消息序列。在我们最初的实验中,我们观察到替代请求可能“现在”不可观察,但会传播到以后的响应。因此,AFLNET继续执行后缀M3。

AFLNET提供了几个协议感知的突变算子来修改候选子序列。从消息序列C的语料库,AFLNET产生消息池。消息池是来自网络嗅探器跟踪的实际消息(加上生成的消息)的集合,其可以被添加或替换到现有消息序列M ∈ C中。为了突变候选序列M2,AFLNET支持消息的替换、插入、复制和删除。除了这些协议感知的变异操作符之外,AFLNET还使用从灰盒模糊中已知的常见字节级操作符,例如位翻转以及字节块的替换、插入或删除。突变是堆叠的,即,应用几个协议感知的和字节级的变异操作符来产生变异的候选序列。

被认为是“感兴趣的”的生成的消息序列M被添加到语料库C。如果服务器响应包含先前未观察到的新状态或状态转换(即,未在IPSM S中记录);如果序列覆盖了服务器源代码中的新分支,那么它也是有趣的。

具体结合几个组件后的整体流程

Snipaste_2023-07-27_20-50-55.png

  1. AFLNET从包含网络流量的pcap文件开始。
  2. 请求序列解析器将pcap文件解析为消息序列(图三),并将其保存到语料库C中。
  3. 状态机学习器根据响应代码构建初始IPSM(在图4中包含黑色节点和转换)
  4. 假设目标状态选择器将状态331(USER foo OK)选择为目标状态,序列选择器随后将从序列语料库C中随机选择一个序列,此时语料库C只包含一个序列。
  5. 序列变异器识别出序列前缀("USER foo"的请求)、候选子序列(“PASS foo"的请求)和剩余子序列作为后缀。通过使用堆叠变异器来变异候选子序列,序列变异器可能会生成错误的密码请求(“PASS bar”),导致错误状态(530 Not logged in)。在这个错误的密码后面,它重播后缀(如"MKD demo”、“CWD demo”),导致状态530中的循环,因为在成功认证之前,所有这些命令都不被允许。
  6. 最后,发送"QUIT"请求,服务器退出。由于生成的测试序列(如图5所示)覆盖了新的状态和状态转换(如图4中红色部分所示),它被添加到语料库C和IPSM中。

Snipaste_2023-07-27_20-53-50.png

案例研究(实验)

实验设置

两个基线算法:

  1. 有状态的黑盒模糊器(BOOFuzz)
  2. 无状态的覆盖引导模糊器(AFLNWE【AFL的网络扩展版】)

评估的两种协议:

  1. FTP(广泛用于文件传输)
  2. RTSP(广泛用于流媒体视频传输)

比较数据:

  1. 平均分支覆盖率
  2. 状态覆盖率
  3. 暴露的错误数量

Snipaste_2023-07-28_13-38-51.png

设备:
使用Live555媒体服务器作为RTSP服务器,并将其安装在类似摄像头这样的隐私和安全关键设备上。

AFLNET和AFLNWE在启动时使用同一个初始种子库,BOOFUZZ则是使用了协议的详细模型包括消息模板和状态机。

为了减轻随机性的影响,针对每个实例模糊器都运行了20次。

代码覆盖和状态覆盖

Snipaste_2023-07-28_13-33-47.png

实验结果显示,AFLNET在所有的有效性指标上都超过了BOOFUZZ,其效果显著(效应大小大于0.71)

AFLNET平均增加了60%的分支覆盖率、56%的语句覆盖率和67%的状态覆盖率

这种性能提升是由于AFLNET能够变异真实的消息序列,并且演化出一组已被观察到能增加服务器代码覆盖率的消息序列

在LightFTP中,AFLNET明显优于AFLNWE。

在分支覆盖率、语句覆盖率和状态覆盖率方面,增加了121%、79%和85%。

AFLNWE和AFLNET在Live555中表现相近是因为Live555的实现协议状态机(IPSM)相比LightFTP有较小的深度,即有效序列中的消息数较少。此外,功能状态的数量较少,即大多数状态(除了初始序列已发现的状态)都是错误状态。

漏洞发现

对AFLNET、BOOFUZZ和AFLNWE的漏洞发现能力进行了比较。

AFLNET发现了四个漏洞,其中两个(CVE2018-4013和CVE-2019-7733)是已知的,另外两个漏洞(CVE-2019-7314和CVE-2019-15232)则是0day漏洞。CVE-2019-7314和CVE-2019-15232两个漏洞被评为危急程度9.8分。

Snipaste_2023-07-28_13-49-16.png

BOOFUZZ和AFLNWE都没有能够发现CVE-2019-7314。进一步分析了CVE-2019-7314的根本原因,发现在SETUP消息包含一个RANGE值7时,存在一个未详细指明的INIT和PLAY状态之间的快捷方式(如图9中的红色部分)。虽然这个快捷方式本身是无害的,但它使得我们的技术能够发现一个0day漏洞。AFLNET生成了一个随机的消息序列来发现这个转换,并系统地对其进行演化以找到0day漏洞。要利用这个漏洞,攻击者需要发送两个消息序列。第一个是包含RANGE值的SETUP消息。第二个是长度大于20,000字节的任意消息。攻击者可以读取被释放的内存中的最多8个字节。由于这个转换在标准的RTSP规范中没有文档记录,BOOFUZZ无法测试Live555中的未详细指明的快捷方式。

相关工作

两种不同的网络模糊测试方法:

  1. 基于覆盖率的灰盒模糊测试
  2. 网络适用的模糊测试

基于覆盖率的灰盒模糊测试

基于覆盖率的灰盒模糊测试是指通过生成更多的输入来引导灰盒模糊器,以探索危险或未覆盖的程序语句。与此不同,本文提出了一种基于状态空间的灰盒模糊测试方法,使其能够了解程序的状态空间,例如协议实现。

网络适用的模糊测试

网络适用的模糊测试指的是利用网络进行模糊测试的方法。大多数网络适用的模糊器采用黑盒模糊测试的方法,即根据手动构建的协议规范从零开始生成新的消息序列。此外,大多数网络启用的模糊器还采用基于生成的方法,即根据预先指定的消息模板从零开始生成新的消息序列。与此不同,本文中的方法采用了基于变异的方法,通过变异现有的(记录的)消息序列来生成新的消息序列。

协议实现模糊测试

在协议实现模糊测试方面,传统的方法包括手动构建协议模型和自动逆向工程协议。手动构建协议模型是费时且容易出错的。相比之下,自逆向工程协议可以从给定的消息集合中学习消息的结构,或者在模糊测试过程中动态地发现消息的结构。这些方法可以被归为黑盒学习和白盒学习两类。与这些方法相比,本文提出了一种轻量级的变异方法,不需要手动构建消息模板或学习协议状态机,而是直接对真实消息进行模糊测试。

未来展望

在未来的工作中,计划在其他流行和关键协议上进行更多的实验(例如,安全外壳(SSH)和简单邮件传输协议(SMTP))来评估AFLNET的有效性和效率。此外,还计划扩大AFLNET的适用性,通过增强其状态机器学习算法,以支持不产生响应代码的协议实现。

Logo

加入「COC·上海城市开发者社区」,成就更好的自己!

更多推荐