Overview

  • Background:

    随着物联网设备的普及,其安全性变得愈发受人关注,其中一个重要方面就是固件安全,而fuzzing作为一个有效的漏洞检测技术,在IoT固件的安全测试中扮演着重要角色。但是要将fuzzing应用到IoT固件时,有如下几个问题:

    • 缺少实际外设时无法正常运行
    • 缺乏对多外设输入空间的探索
    • 仪器化和收集反馈的困难
    • 缺乏故障检测方法
  • Method:

    文章针对如上问题,提出了一种新颖的fuzzing测试工具: FirmHybirdFuzzer。该工具具有如下特点:

    • 统一虚拟外设:集成虚拟外设,FirmHybirdFuzzer可以在没有实际硬件的情况下运行固件
    • 混合事件生成:采用混合事件生成方法为不同的外设生成测试输入
    • 两级覆盖反馈:通过收集覆盖反馈,工具能够优化测试用例的生成过程。
    • 插件化故障检测: 实现了基于插件的故障检测机制,专注于发现内存损坏等典型漏洞。
  • Evaluation:

    1. 虚拟外围设备的有效性
      • 测试了62个固件图像,结果显示,不同的固件图像能够在系统中成功执行,而无需实际的外围设备。
    2. 混合事件生成的有效性和效率
      • 通过变异不同的外围设备,发现同时变异上下文和网络能够获得更高的代码覆盖率。
      • 通过不同事件生成调度策略的评估,发现使用变异生成能够提高覆盖率并减少时间开销。
    3. 故障检测插件的有效性和性能
      • 故障检测机制能够有效地识别常见的C/C++漏洞。
      • 栈跟踪能够检测栈溢出和越界读写错误;堆跟踪能够识别堆溢出、空指针解引用、双重释放和使用后释放;指令跟踪能够检测除以零和整数溢出漏洞。
      • 故障检测插件在可接受的额外时间开销下有效。
    4. 与其他固件模糊测试工具的比较
      • FirmHybirdFuzzer在硬件独立性、源代码独立性和支持的固件类型方面具有明显的优势。
      • 与Laelaps相比,FirmHybirdFuzzer在基本块覆盖和外围设备访问点覆盖方面都有显著提升,并且所需时间大幅减少。

Challenges

物联网固件的一些特性不同于传统的桌面应用和移动应用,比如**不同的底层环境和基于外设的交互。**这些特性给基于fuzzing的漏洞检测带来了很多新的问题。

  • 缺少实际外设时无法正常运行:

    由于底层操作系统和外设的不同,要将固件运行起来是很困难的。目前有种基于QEMU的动态分析方法,其内置了一个Linux内核的抽象用于模拟固件,这种方法常用于基于LInux的固件动态分析。但是这种方法并不适用于动态分析运行在实时操作系统或裸机上的微控固件,原因是RTOS种类众多且互相不兼容,并且主流的模拟器如QEMU,只能模拟微控的核心外设,当分析未知外设时QEMU就会失效。也有一些方法使用符号执行等技术来模拟未知外设的工作流,如SymDrive,Laelaps,包括提供通用库函数来实现固件分析的HALUcinator,但他们都具有一定的局限性。

  • 不支持多外设输入空间的探索

    IoT固件运行的设备通过不同的外设与环境进行交互,然而主流的fuzzing方法所处理的程序环境接口通常只有单个输入,如Sulley,Peach,AFL++等等。而IoT固件通常有多个输入,如传感器,网络设备等等,并且不同的输入可能由于外设的不同,导致其语法,类型等都不同,而目前还没有一个已知的fuzzing工具可以有效地处理这个问题。

  • 无法仪器化和收集反馈用于引导fuzzing

    通常灰盒fuzzing的关键在于基于反馈的引导和**遗传优化,**对于x86软件来说将编译时和运行时仪器化来收集执行输入的覆盖率信息然后用于引导fuzzing优化输入是当前最好的方法。然而,编译时的仪器化需要源码,而对于IoT固件来说通常没有源码。传统的fuzzing方法依赖于观测运行时的崩溃,通常是软件测试或硬件保护触发的崩溃,但是在微控器上这种方法有很多限制,导致很多崩溃发生但并未报告。

Solution

为了解决上述问题,文章提出了一个不依赖物理设备的混合模糊测试工具,其可以测试主流的逻辑资源和RTOS而不需要外设,并且能检测常见的C/C++漏洞,其针对上述的挑战提出了三个解决方案:

  • 集成虚拟外设组件
  • 采用混合事件生成方法用于为不同的外设生成输入
  • 二级覆盖率反馈机制用于生成测试集

Approach

工具的主体框架如图所示

Untitled

框架的输入包括固件的二进制文件和fuzzing配置(核心文件,ROM/RAM位置和fuzzing设置等),框架的输出是一个发掘出的漏洞。不同于传统的fuzz工具要么检测用户空间要么检测内核空间,FirmHybridFuzzer同时用户空间程序和内核空间程序。该方法的主要技术有如下几点:

  • Symbolic peripheral-based Execution 基于外设的符号执行技术,用于模拟外设的行为。
  • Hybrid Event Generation 混合事件生成器,基于约束和突变为不同外设生成不同输入
  • Multi Feedback Guidance 多反馈引导,用于优化测试输入
  • Fault Detection Mechanism 故障检测机制,检测常见的漏洞

虚拟外设执行

文章提出了一个统一的符号化的外设对不同外设的行为进行建模,固件中所有IO操作均被截获并转发到这个符号化的外设中,虚拟外设将基于对外设行为的模拟能力做出相应回复。同时虚拟外设还对不同未知外设建立了三种关键行为模型:

  • 外设发现:当处理器通过DMA(Direct Memory Access)访问到一块未知的内存时,该内存区域对应的外设即会做出响应。
  • I/O 交互:通过与外设的读操作进行交互并提供有效/无效的响应,固件可以执行有效的执行路径。其中写操作都是被忽略的因为其不会对控制流产生影响。
  • 中断注入:基于QEMU的机器协议,作者设计了三个QMP命令(activate irqs, inject irq,inject all irqs)并且实现了python接口用于随机注入中断指令。要注意的是注入的中断指令不会被当作fuzzing的输入,我认为这是为了更加接近真实环境所做的行为。

虚拟外设通常会产生有效范围以外的值,作者认为这是可接受的,因为这有利于探索错误处理代码段中的漏洞,我认为这也同时可以增加控制流数量,可能会增加状态空间的大小但是有利于全面的探索。

混合事件生成

混合事件生成器由两个部分组成:基于约束生成和基于突变生成。该方法解决了传统灰盒模糊测试无法对多外设生成有效输入的问题。

  • 基于约束生成:该方法使用一个符号执行引擎生成外设的输入,当固件执行到一个未知外设的内存区域时,QEMU 会暂时挂起,将内存和寄存器信息输入到符号执行引擎中,引擎会输出几条可能的路径,然后根据启发式路径选择策略选择路径并调用 SMT 进行约束求解来生成对应的输入,并将其存储在对应的外设种子队列中。下面时该方法的几个关键技术

    • 基于访问的符号化:顾名思义,每次访问外设或变量都会分配一个新的符号给它,即使之前访问并分配过这个外设或变量。这样做的目的是为了防止外设内存的不确定性造成错误的后果,如下图所示,如果base没有每次都被符号化,那么cnt1 - cnt0将始终为0.

    Untitled

    • 推断式符号执行:采用该技术是为了减少约束求解器调用,该技术要求符号执行引擎积累到一定程度的分支才能调用约束求解器,同时指定三条规则进行路径选择。
      • 优先深层路径
      • 优先新发现的路径
      • 避免无穷循环
  • 基于突变生成:当固件执行到某个外设要进行读操作时,当前已存在的种子将会发生突变,突变产生的新事件将会加入到种子队列中然后喂入QEMU来继续执行。下面是该方法的几个关键技术

    • 外设感知的有效种子生成:初始的种子通常需要符合外设的要求,比如语法和语义正确,这将为之后的突变提供更好的基础。
    • 特定外设的突变能力:考虑到外设交互的特点,设计了一系列特定的突变算子如下:
      • BitFlip:翻转已有种子的1,4,8,16,32,64,128位
      • Arithmetic:在已有种子加或减上一个随机值
      • Interesting:在种子中插入一些有趣的值,例如条件表达式中使用的固定值。
      • Overwriting:通过固定内容(例如,头部)在协议的特定字段上覆盖现有种子的某些块。
  • 基于概率调度:一般来说,基于约束的生成擅长生成事件来驱动固件沿着特定的路径执行。突变型代在生成探索更多路径的多样化事件方面具有优势,包括错误处理代码。作者在这里 的建议是在程序初期使用基于约束生成方法,当外设的种子序列长度大于人工指定的限制,则使用基于概率调度算法调整生成方法。注意这个概率是人工指定的。

双重反馈引导

该方法利用QEMU来实现,由于固件是由QEMU翻译过来,根据QEMU的中间层可以很容易获取运行时信息。这构成了方法动态收集反馈信息的基础,包括已执行的基本块,访问的外设接入点等。同时使用多维度覆盖反馈,针对块到块和外设到外设两个维度。

  • BB2BB覆盖率:BB2BB是指一个外设中的代码块跳转到另一个代码块,在运行时追踪每一个独特的BB2BB操作并将其数量作为FICFG覆盖率的参考。如果一个事件触发了一个新的BB2BB,则认为这个事件是有趣的并将其突变生成更多的种子。
  • PP2PP覆盖率:BB2BB是指一个外设跳转到另一个外设,在运行时跟踪所有唯一的PP2PP,因为它是显示FPADG覆盖率的直接度量。所有访问的唯一的PP2PP存储在一个列表中。该列表作为PP2PP的覆盖图。如果一个事件触发了一个新的PP2PP,则认为这个事件是有趣的并将其突变生成更多的种子。

故障检测机制

该方法借鉴PANDA中用于检测内存损坏的启发式方法,实现了一种基于微控制器的固件故障检测机制。由于最新的QEMU对基于ARM CortexM的设备具有更好的模拟能力,作者将PANDA机制移植到最新的QEMU中,并对其进行扩展,以支持检测更多的漏洞。更具体地说,设计并实现了3个跟踪插件作为故障检测机制中的QEMU TCG插件。

  • 栈跟踪
  • 堆跟踪
  • 指令跟踪