Mom .
本文提出了一种针对嵌入式系统的模糊测试方法,该方法利用了微控制器普遍具备的调试接口和硬件断点功能。
由于嵌入式系统内部组件的多样性以及软件的不可更改性,使得对其进行模糊测试变得复杂。然而,通过GDB(GNU调试器)控制的调试探针可以设置硬件断点,即使在未插桩的二进制代码上也能提取到代码覆盖反馈,从而有效指导模糊测试。
作者开发的原型工具GDBFuzz在四种不同的微控制器板卡上进行了评估,能够快速达到高代码覆盖率,并检测到已知和新的漏洞。GDBFuzz作为一种通用且易用的覆盖指导模糊测试工具,几乎适用于任何GDB能够调试的程序和系统,对嵌入式系统的安全性测试具有重要意义。
注:由Kimi大模型生成,经过人工校对。
开发了原型工具GDBFuzz,该工具可以与GNU调试器(GDB)接口结合使用,自动化模糊测试过程。
在四种不同的微控制器上对GDBFuzz进行了评估,验证了其在代码覆盖率和漏洞检测方面的有效性。
2 .
控制流程图的支配关系
前支配(Predomination):如果从入口节点到任意节点v的每条路径都包含节点u,则称节点u前支配节点v。
后支配(Predomination):如果从节点v到出口节点的所有路径都包含节点w,则称节点w后支配节点v。
通过支配关系,可以推到出以下定理:
定理 1(可达性):如果到达节点 v,则之前已到达主支配树中的所有父节点,之后将到达后支配树中的所有父节点。
过程间控制流程图和支配关系
过程间控制流程图描述了程序中不同函数的基本块之间的转化关系,其中一个重要挑战是需要通过上下文相关算法来处理实际调用时多入口和多出口的情况。GDBFuzz提出了一种简化的过程间CFG的构建方法:半过程间(semi-interprocedural)控制流程图。通过将所有调用作为边从调用点插入到被调用方来连接函数控制流程图。在构建半过程间 CFG 时,会省略返回边,因此不会引入不正确的流程。对于反转的半过程间控制流图,我们反转局部控制流图,跳过调用边,只添加返回边。同样,通过删除上下文相关的调用边缘来避免插入歧义。然后,可以使用局部控制流图的算法有效地计算相应的半过程间支配者树。与完整的过程间支配者图相比,在最坏的情况下,可能会错过每个调用边缘的一个支配关系,但应该不会真正损害模糊测试性能。
GDBFuzz 的整体设计:利用目标程序的控制流图将可用的硬件断点设置为随机选择的尚未到达的基本块。然后,它通过对语料库中随机选择的输入应用突变来重复生成测试用例,并将测试用例发送到目标输入接口。如果调试探测发出断点命中信号,则 GDBFuzz 会将相应的节点及其主要节点标记为已到达,并将负责的测试用例添加到语料库中。导致崩溃或超时的测试用例单独保存。当在预定义数量的测试用例后没有发生断点中断时,GDBFuzz 会将硬件断点重新定位到新选择的节点。每次重定位后,GDBFuzz 首先再次测试语料库中的所有输入,以检查它们是否已经到达新目标的基本块。与使用完整代码检测的覆盖率引导模糊测试一样,进化算法使输入语料库随时间增长,输入到达不同的代码区域。
GDBFuzz其余部分设计如下:
3.1 提取控制流程图 CFG
GDBFuzz为了使用硬件断点进行模糊测试反馈,需要确定目标程序的内存地址和控制流图。GDBFuzz使用Ghidra工具从二进制文件中提取CFG,因为源代码并不总是可用。由于Ghidra不能检测到所有的控制流,尤其是处理间接跳转或编译器优化时,GDBFuzz在模糊测试期间会迭代优化和更新控制流,详见5.5部分。
3.2 寻找 Entry Point
GDBFuzz将模糊的重点放在固件中对目标输入接口进行输入处理的区域。提取的CFG从输入的处理开始,成为入口点Entry Point。GDBFuzz提供了一种半自动化的方法来寻找Entry Point,具体的步骤如下:(1) 向目标设备发送测试输入并立即中断执行。(2) 使用 gdb find 在设备的内存中重新发现发送的输入。(3) 将数据观察点设置为重新发现的输入数据的第一个地址。(4) 再次发送测试输入。(5) 此时发生的中断上的所有程序计数器地址都是入口点的候选地址。
3.3 检测 Bugs
使用 Bug oracles 来检测执行期间是否触发了错误。GDBFuzz依赖于可观察的bug触发,例如通过连接错误、超时或错误响应代码来检测故障。此外,还可以通过在调试接口上设置断点来捕获错误处理程序的位置来检测错误信号。
3.4 处理 Bugs
当GDBFuzz检测到崩溃或者超时时,需要适当地处理这些错误,具体步骤如下:
(1)Bugs 去重,通过调用堆栈的哈希值来唯一标识和删除重复的bug。
(2)保存触发此错误的输入(如果bugs是唯一的)。
(3)重启目标设备。
(4)继续模糊测试。
Test Data Generator
使用libFuzzer的变异引擎来生成新的测试输入,以触发程序的不同代码区域。
GDB Controller
使用python-gdb-mi包来发送和接收调式命令,管理与待测系统的调试连接。
Target Connection
将测试输入发送到目标设备,根据实际接口处理连接或断开连接事件,以及来自协议的错误反馈。GDBFuzz实现了用于TCP、Serial串口、USB连接的适配器以及用于测试linux应用程序的UNIX 管道。
Ghidra Controller
使用ghidra-bridge包来使用python3在Ghidra和GDBFuzz之间交换请求和数据,获取目标应用程序的CFG。
Dynamic Control Flow Graph Refinement
缺少控制流表现为CFG中没有后续节点的悬空节点(未被Ghidra标记为终点)。GDBFuzz执行以下步骤来处理此类情况:(1)为悬空节点设置一个断点,并将触发该节点的测试输入发送到待测程序;(2)当终端发生时,单步执行;(3)读取程序计数器的值。(4)将找到的edge报告给Ghidra并重新分析二进制文件。
作者在8个研究问题的知道下,在两种不同环境中评估GDBFuzz:
RQ1:GDBFuzz 与嵌入式系统上的黑盒模糊测试相比如何?
发现: 在嵌入式系统上,具有有限断点的覆盖率引导模糊测试非常有效,并且优于黑盒模糊测试。
RQ2:GDBFuzz 与现有的嵌入式模糊测试方法相比如何?
发现:GDBFuzz 在嵌入式系统上对软件进行模糊测试,无需任何检测或其他软件更改。
RQ3:该方法能否揭示嵌入式软件代码中的实际错误?
发现了三个以前未知的漏洞:
STM32 USB设备堆栈中的无限循环,这是由于将uint8_t索引变量计数到for循环中可控uint32_t变量造成的。
Cypress JSON 解析器中的缓冲区溢出,这是由于对固定大小的内部缓冲区的长度检查缺失引起的。
Cypress JSON 解析器中的空指针取消引用,由缺少验证检查引起。
发现:GDBFuzz 揭示了嵌入式软件中的真正漏洞。
RQ4:GDBFuzz 与最先进的模糊测试器 AFL++ 相比如何?
发现:如果可以以很少的成本部署 AFL,请使用它;否则,请将 GDBFuzz 视为一个可能要求较低的替代方案
RQ5:GDBFuzz 从支配关系中获益多少?
发现:在我们的实验中,优势关系将所需的断点中断减少了三分之二以上。
RQ6:GDBFuzz 在多大程度上帮助逆向工程工具揭示无法识别的控制流?
发现:GDBFuzz 显示未检测到的基本块和边缘,以便在模糊测试期间进行逆向工程。
RQ7:可用断点数如何影响模糊测试性能?
发现:随着时间推移,覆盖率呈指数级增长,需要的断点呈指数级增长
RQ8:GDBFuzz 与基于应用程序的设置上的黑盒模糊测试相比如何?
发现:GDBFuzz 在更大规模的基于应用程序的设置中也优于黑盒模糊测试。
原文始发于微信公众号(SecNL安全团队):我猜你看不懂之——物联网的fuzz(挑战下你能看懂多少,留言在文末)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论