# 简述

# 资料

𝜇AFL: Non-intrusive Feedback-driven Fuzzing forMicrocontroller Firmware, ICSE 2022

# 背景、意义与思路

使用 Fuzzing 的方法可以发现软件漏洞,但是对于 MCU 来说存在许多挑战。由于 MCU 内容小,不能直接运行 Fuzzer,现在的解决方法一般是在 Host PC 上用模拟的方法做 Rehosting 来运行固件。

虽然能模拟部分开发板的环境,但是对于 IoT 而言还有很多外设,在模拟上存在一定难度。如果采用硬件抽象层 HAL 来使用宿主机的库文件替换掉外设库的话,没有办法对外设进行测试;如果采用请求转发的方式将交互发送给真实设备,开销很大。

因此这篇文章希望能直接利用硬件的特性,不使用模拟的方法进行 fuzz。这样可以提高 fuzz 的可靠性和效率。具体来说需要解决这样一些问题:如何传递测试样例?如何获取覆盖率?如何提高 fuzz 效率?

作者的整体思路是,利用 SEGGER 公司提供的 J-Trace Pro 作为调试器,直接实时获取程序运行的 ETM 数据包,然后对其进行一定程度的解析,使用 AFL 原生的模块进行基于反馈的 fuzz。

# 概览

https://s-sh-3008-c01dkit.oss.dogecdn.com/pics/papers/Snipaste_2022-02-15_18-47-33.png

# 解决方法

# 如何传递数据?

J-Trace Pro 作为 debug dongle,可以直接向开发板写入数据。使用两个 arrays 用于存放 testcase,一个用于存放当前执行轮次,另一个用于存放下一轮次。写入时采用 SEGGER RTT(real time transfer)协议,基于 AHB-AP(Advanced High-performance Bus-Access Point)访问内存。array 声明在.noinit section,不影响 libc 初始化加载。

# 如何获取数据?

基于 ARM 硬件 DWT 设计了两类过滤器:基于地址的过滤器、基于事件的过滤器。当开发板读取 testcase 时启动 ETM 收集,当执行轮次结束后终止 ETM 收集。

基于地址的过滤器可以设定代码段的起始地址、终止地址,有利于分析库函数。基于事件的过滤器可以设定为某一代码段指令执行时启动,或者对某一内存地址进行读写操作时启动。

# 如何提高效率?

采用上述两类过滤器可以过滤掉很多和 Fuzz 无关的 ETM 包。对于开发板重置时间大于实际 Fuzz 时间的测试对象而言,这种过滤可以提高执行效率。另一方面,对于获取到的 raw ETM 数据,作者使用 linear code sequence and jump (LCSAJ)basic block 来表示基本块。和一般的基本块不同是,LCSAJ_BB 只将实际执行跳转作为基本块的边界,从而省略了对汇编指令的反编译、对 ETM 包的解析重建执行流。

# 如何和 AFL 协同?

和 AFL 的区别仅在于确定 block 的地址。在 AFL 中,采用如下的方法建立位图映射:

cur_location =( block_address >>4) ^ ( block_address <<8);
shared_mem[ cur_location ^ prev_location ]++;
prev_location = cur_location >>1;

ETM 数据包可以表示为 (起始地址,arm 指令执行与否,终止地址) 来表示一个 block。作者定义新的表示方式:(base, bitstream) 其中 bitstream 就是 01 串,0 表示不执行,1 表示执行,并设计一个哈希函数来生成无符号整数,相当于上述代码中的 cur_location,实现 AFL 协同。

# 实验结果

https://s-sh-3008-c01dkit.oss.dogecdn.com/pics/papers/Snipaste_2022-02-15_19-20-01.png

# RQs

https://s-sh-3008-c01dkit.oss.dogecdn.com/pics/papers/Snipaste_2022-02-15_19-33-59.png

对 7 个样例进行测试,以不涉及外设的 Fibonacci(1000000)作为 baseline

I2C、UART、USB、SD Card 与 PC 使用对应的协议进行通信,Enet 通过 ipv4 和 PC 通信,MMCAU 使用硬件加密加速单元计算 AES DES3 SHA 等密码学运算,闭源。Table2 后三列数据表示运行 1 小时的测试轮数,数字越大效率越高。

  1. RQ1: Does the LCSAJ_BB-based approach that directly processes raw ETM trace improve performance compared to approaches that fully recover the instruction flow?

Table2 第四列(采用 Capstone 框架进行反编译)、第六列对比,有 1.03x-4.81x 的提升。

  1. RQ2: Do online filters help to improve the performance of 𝜇AFL?

Table2 第五列(不使用 online filter)、第六列(使用 online filter)对比,对于 BB 较多的测试样例而言提升不大,对于 BB 较少的简单测试样例而言提升明显。这里 Enet 大小和 I2C 相近,但性能提升不大,猜想可能是 ipv4 网络连接相关操作的时间开销远大于 filter 节约的开销。

https://s-sh-3008-c01dkit.oss.dogecdn.com/pics/papers/Snipaste_2022-02-15_19-35-58.png

  1. RQ3: How much overhead does 𝜇AFL introduce to (each sub-process of) a single round of fuzzing?
  • Reset2Start:从设备启动直到读取 testcase(fuzzing start point)的时间
  • StartTrace:传输 testcase、设置 ETM、DWT 的时间
  • Start2End:从 fuzzing start point 到 end point 的时间,在这一时间内收集分支信息
  • StopTrace:关闭 ETM 追踪、等待 ETM 传送完数据的时间
  • Analysis:对 ETM 数据包进行分析的时间

本文对每个测试样例进行 1000 轮测试并取平均耗时,制图 4。可见从设备启动到 fuzzing start point 时间、启动 trace 时间基本相当。随着测试样例变复杂,生成的 ETM 数据包增加,解码、分析量增加,消耗时间也随之增加。

  1. RQ4: What is the overall performance of 𝜇AFL and how is it compared with existing work?

https://s-sh-3008-c01dkit.oss.dogecdn.com/pics/papers/Snipaste_2022-02-15_19-37-03.png

Table3 为运行 μAFL 两天的结果。存在的问题:当生成的 trace 很大(超过 200MB)时,dongle 内部 buffer 被填满,可能会造成溢出,从而丢失 trace。当这种情况发生时,需要强制退出执行并重启,导致了更低的执行数,因为这些错误的执行不被计入成功执行数。一种很少见的情况是 dongle 内部出现了无法检测到的错误,产生 FP,当重试能产生 crash 或者 hang 的 testcase 时无法复现。

和现有工作的对比:μAFL 是首个有效对 MCU 外设进行 fuzz 的工作。最相关的工作包括 Avatar 等在 qemu 内模拟固件并转发外设操作到真实设备,以及完全模拟(比如 P^2IM,μEmu)。前者的工作只是利用真实硬件完成固件初始化,并符号化分析那些不访问外设的代码,需要进行工程处理才能 fuzz;后者不能保证对 driver fuzz 时的可靠性,无法启动那些使用复杂外设的固件。

  1. RQ5: How effective is 𝜇AFL in locating bugs in the peripheral drivers of real-world firmware?

在 USB 驱动进行两天的 fuzz,新发现了 STM32 SDK 的 10 个 bug,NXP SDK 的 3 个 bug,获取到了 8 个 CVE 编号。

# Q&A

以下是发邮件询问 Lead Author 的一些结果

Q1: 在一轮 testcase 执行过程中,不同的 sub-process 是严格依次进行的吗?

A1: In our design and implementation, they are executed in order. StartTrace() need the halt state of MCU. We choose to execute StartTrace() after Reset2Start since trace before the start is unnecessary and will bring overhead. I think Analysis could be executed in parallel with Start2End(), in other words, before StopTrace().

Q2: testcase 使用的 array 保存的位置是任意的吗?

A2: The location of the testcase array is arbitrary which is decided by the compiler. We only define its length and attribute .non_init. So it’s in the RAM.

Q3: case study 对 USB 进行测试时 testcase 需要特殊设计吗?

A3: No, we run the demo from SDK without any modification and dump its input from the USB device as the initial testcase.

Q4: 每一次执行都 reset board 是必要的吗?

A4: Yes, you may trigger reset in multiple ways and ARM provides soft reset by the register AIRCR. In fact, we provide this in our implementation. However, without fully resetting, even bug found, we do not know the context from old executions and it’s hard to decide if a false positive. It looks like the persistent mode of AFL.

# 相关工作

μAFL 是第一个对 MCU 外设驱动进行高效 fuzz 的工作。Avatar 虽然也使用真实设备,但它使用的是转发技术,只使用真实硬件完成固件初始化阶段,一般不对外设驱动进行 fuzz。基于模拟的方法如 P^2IM 和 μEmu 虽然具有很好的可扩展性,但是不能保证高可靠性,而且不能支持复杂外设。

# 讨论、总结与展望

μAFL 是对 MCU 固件的非侵入式的、反馈驱动的 Fuzz 平台,主要目标是低层次的外设驱动。其很大程度上依赖于 ARM 架构的硬件特性,并使用硬件调试器来提高运行效率。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

c01dkit 微信支付

微信支付

c01dkit 支付宝

支付宝

c01dkit qqpay

qqpay