Please Subscribe Wechat Official Account:信安科研人
发送“嵌入式设备和固件中的自动漏洞检测”,获取原文pdf
目录
摘要
- 研究动机:物联网设备以及固件的漏洞众多,挖掘困难,安全影响大
- 研究角度:各种分析技术
- 研究对象:物联网设备,工控自动化设备等嵌入式设备
一 简介
软件漏洞出现的几种原因:
- 过时的软件架构
- 调用存在漏洞的第三方库
- 与互联网结合,攻击面更广
- 防火墙和防病毒工具因为设备资源受限的问题,无法使用
现有的嵌入式设备漏洞检测对象:
- 二进制程序
- 程序源代码
挑战点:
嵌入式二进制比普通二进制更难分析:
- 固件按照特定标准指定,因此有不同的CPU架构
- 资源受限,虚拟化模拟嵌入式设备进行测试效率很低
- 计算成本受限,很少有内存损坏攻击,格式化字符串和堆栈溢出比较常见
- 固件逆向技术困难
1.1 调研方法
- (挑战与自动化检测)首先列举了通用和嵌入式特定的二进制分析挑战和自动漏洞检测技术,然后根据其应用领域对方法进行分类(第2节)。
- (动态分析、静态分析和符号执行方案)此外,检查了几个现有的动态分析和符号执行工作以及静态解决方案,以更深入地了解所提出的技术、其优势和局限性(第3节和第4节)。
- (按照方案分类)基于嵌入式系统现有方法中采用的三种分析类型设计了一个分类法,包括动态分析、符号执行和静态解决方案(第3节)。
- (分析所用到的固件特征)研究并分类了嵌入式系统二进制分析中使用的现有特征(第4节)。
- (方案评估)此外,在相应的章节中基于不同的标准,即方法、实施和评估,对这些方法进行了比较。
- (未来方向)最后,讨论了本次调查的经验教训,并提出了未来的研究方向(第5节)。
1.2 调研数据
通用平台(如DARPA CGC)和特定数据集
二 嵌入式设备二进制固件分析挑战与方法
2.1 常规二进制程序分析的挑战
1 信息丢失
源码到二进制程序的编译过程中,会丢失一些可用信息,例如变量名、数据结构的大小。
影响:调试信息缺失,二进制分析任务更具挑战性
2 编译器的效果
编译器因为应用性能和内存优化的问题,导致不同配置的二进制表示形式发生变化。
影响:寄存器、控制流图CFG都会发生变化
3 二进制反汇编
- 程序入口点和函数边界的发现与确认
反汇编程序通常使用符号表来识别函数边界并构造控制流图。但是,当符号表不准确或不可用时,查找函数边界变得具有挑战性 。此外,在某些情况下,例如binary-blob固件,入口点和基地址是未知的。而且,某些功能可能具有多个入口点,需要对其进行识别。
- 代码特定属性的发现
为了对齐指令并提高高速缓存效率,编译器可以在函数之间或函数内插入填充字节。因此,反汇编器可能很难区分填充字节和代码字节,因为填充字节通常被转换为有效指令。
此外,一些函数可能不是连续的,并且有一些间隙,包括数据、跳转表或来自其他函数的指令,这会影响二元分析方法的准确性。
同时,由于无法找到所有代码、识别非返回函数以及处理依赖于计算值的间接跳转,可能无法准确执行控制流图提取。
- 代码转换
代码混淆、加密、打包技术让逆向更难。
4 函数内联
出于优化目的,可能会将一个小函数内联到其调用者函数中。 内联函数与函数的其他部分之间缺乏区别,使得函数内联识别任务非常具有挑战性。
当内联函数的汇编指令由于指令对齐和流水线处理而变得不连续时,这项任务变得更具挑战性。
5 硬件架构
软件程序可以交叉编译或部署在不同的 CPU 架构上,其中指令集、调用约定、寄存器集、函数偏移量和内存访问策略因一种架构而异。 因此,分析从相同源代码为不同 CPU 架构编译的二进制文件更具挑战性。
6 实验评估
- 准确率:实现任何漏洞检测技术的高精度是一项至关重要且不重要的任务。例如,在静态分析代码时,获得低假阳性率通常是具有挑战性的。
- 结果评估:对于几种技术,由于对所识别的漏洞的信息(例如,如何触发)的很难访问,所获得的漏洞检测结果不能被验证。因此,这些技术涉及人工努力来验证结果,因此可能容易出错且效率低下。
- 效率:许多现有的方法在计算上是昂贵的,这表明对于任何二进制代码都需要有效的漏洞识别技术。
- 扩展性:部署软件的数量呈几何级数增长,由于桌面应用程序的增长,物联网设备,嵌入式系统,以及它们之间的互连。
- 测试用例生成:一些方法需要与目标应用程序兼容的初始种子输入才能开始分析。 当目标应用程序提供其所需的输入文件格式时,测试用例很容易生成。 然而,当没有提供配置输入时,测试用例的生成就变成了一项具有挑战性的任务; 因为每个程序都需要提前准备一个特定的测试用例,这需要专业知识和额外的努力。
2.2 针对嵌入式设备分析的挑战
1 硬件架构
同2.1
2 扩展性
与普通二进制文件相比,嵌入式系统会遇到特定的可伸缩性问题。更具体地说,在运行时在其目标设备上或在仿真环境中测试嵌入式固件非常慢。
在桌面环境中,使用多处理或虚拟化的并行技术可以加速测试活动; 这在嵌入式系统中是不切实际,因为它们需要访问一批类似的物理设备,由于财务成本或有限的资源 (例如,电源和空间),这是不切实际的。
此外,测试一下嵌入式系统需要频繁重启,以确保每个新测试一下用例的状态清晰。
3 错误检测
虽然一些动态方法(例如,模糊测试)用于传统计算环境(例如,台式机和服务器),但由于缺少固件组件上的故障检测实现,它们在嵌入式系统上存在局限性。
在传统计算环境中,操作系统实施保护级别(例如,堆栈 Canaries、故障分段、ASLR、堆强化和清理程序)以防止内存损坏。 由于有限的 I/O 能力、计算能力和成本,此类保护通常不会在嵌入式系统中实施。
这使得内存损坏攻击更不易观察且风险更大,因为出站内存损坏可能最终写入内存映射的外围寄存器(例如,闪存清除 = 1)或更糟,如果它嵌入在操作技术 (OT) 中,例如, 触发车辆的制动执行器。
嵌入式系统中的默认内存损坏是一种规则,与传统桌面相比也不例外。 在嵌入式世界中唯一可观察到的此类攻击是与格式字符串和基于堆栈的缓冲区溢出漏洞相关的攻击,因为它们会导致内存损坏,因此通常会导致设备崩溃。
4 固件逆向工程
首先需要以下步骤:
- 固件获取:因为保护措施,可能需要手动拆取以获取固件。同时保护措施让这个手动获取固件比较困难。
- 固件解压与提取:一些供应商使用专有打包程序和文件格式打包他们的固件或使用私钥加密。 在实践中,可以使用不同的解包工具,如 Binwalk、BAT 和 FRAK来提取固件。 然而,执行此类任务的成功率有限,因此无法分析所有嵌入式设备固件(例如,Costen 等人从收集的 23,035 个固件映像中成功解压了 8,617 个固件)。
- 固件和二进制识别:提取固件后,需要进行过滤以获取所有相关信息。 这可以包括二进制文件、配置文件、嵌入式文件和固件本身。存在一些没有底层操作系统 (OS) 的固件类型,它们仅包含一个直接在硬件上运行的二进制文件。 在某些情况下,没有操作系统和库的抽象,而在其他情况下,固件映像不是标准的,也没有提供文档。 因此,初始化运行时环境并加载二进制文件更具挑战性。
2.3 二进制程序分析方法
二进制分析可以通过静态检查代码、动态执行代码或提供一些符号值来执行,分别称为静态分析、动态分析和符号执行。
2.3.1 静态分析
方法特征:静态分析检查给定的二进制程序的代码,而不是执行它。它通常被设计为对整个程序进行推理,并具有探索给定代码的所有潜在执行路径的能力。
局限性:静态分析技术通常受到2.1节中的1,2,3,4,5,6的限制。例如,它们识别导致高误报率的非漏洞,或者它们不能找到产生更多误报的所有漏洞(例如,运行时漏洞)。此外,由于未提供触发所标识的漏洞的信息,因此需要手动验证漏洞检测的结果。与动态分析方法相比,静态分析方法是可扩展的;然而,由于这两种方法都有各自的局限性,研究人员最近倾向于将这两种方法结合起来。
2.3.2 动态分析
动态分析是在程序运行时检查和监视程序行为的过程。现有的动态分析方法可以分类如下:
- Fuzzing。很多资料,不多介绍
- 插桩。插桩是一种收集和插入执行反馈(例如,系统调用、运行时信息和崩溃处理功能)以分析应用程序在执行期间的行为的技术。如果源代码可用,则可以在编译时获得插装信息,或者在运行时获得插装信息。由于源代码很少可用,因此可以使用运行时插装来重写二进制文件并注入插装信息。然而,运行时插装当前仅可用于具有OS并且与当前仿真兼容的嵌入式系统。这些方法受到2.1节中的5、6的限制。
- 动态污点分析DTA。DTA 是一种用于检查应用程序错误和漏洞的程序分析技术。它基本上确定了程序输入及其逻辑之间的依赖关系。因此,DTA 可以检测到由于关键输入缺乏安全检查而导致的不当输入验证漏洞。 DTA还可用于分析二进制代码中的信息流并帮助自动生成程序测试用例。但是,它受到 2.1节中的6的限制。
- 仿真技术。基于仿真的技术为特定平台构建部分/全部仿真,然后通过采用强大和先进的动态分析技术在仿真环境中运行软件。 由于供应商对文档和开发环境设置的限制,部分或完整的嵌入式系统仿真具有挑战性。 该领域的突出举措具有以下缺点:有限的 CPU 架构支持、不支持通用中断处理、外围建模支持数量有限 以及速度非常慢 。 因此,仿真方法面临 5、6限制的挑战。
2.3.3 符号执行
符号执行技术旨在通过生成满足所需路径约束的输入来达到特定的程序状态。 输入不是在动态分析中使用具体值,而是符号值。 因此,与具体执行相比,符号执行可以探索所有潜在路径,具体执行仅探索与提供的具体输入相关的一条路径。
然而,符号执行依赖于计算需求高的的求解器和路径爆炸带来的限制。 由于以下原因,直接在固件映像上使用符号执行具有挑战性:
(i) 符号分析需要基于内存布局假设和内存映射硬件位置的定制配置;
(ii) 固件通过 I/O 外围设备与外部环境进行密集交互。 这些行为对于分析师来说是未知的并且难以建模。 此外,模拟行为是一项具有挑战性的任务,因为某些相关信息仅对供应商可用;
(iii) 固件的事件驱动编程模型经常存在无限循环的设计,例如保持嵌入式设备在线需要while true。 因此,使用启发式方法来避免由于中断可能导致的无限循环可能会降低搜索空间覆盖率。 相反,跟踪所有可能的路径会导致状态空间爆炸;
(iv) 符号执行存在与模糊测试类似的问题,如2.1节的限制6。
在符号执行期间,状态探索直到检测到崩溃或满足终止条件,否则继续执行。因此,如果未检测到损坏,则符号执行将时间花费在无价值的状态上。因此,符号执行具备限制6。
2.4 嵌入式、固件与普通二进制文件的漏洞检测工作分类
在本节中,我们根据其应用领域对现有的漏洞检测工作进行分类。建议的分类包括三个嵌入式系统、固件和普通二进制域,如图1所示。
注:嵌入式系统是硬件和执行所需功能的足够软件的组合,而固件是嵌入在硬件中的代码。因此,将仅关注固件分析的方法归为“固件”类别,而那些还考虑与硬件的任何交互的方法则归为“嵌入式系统”。
2.5 嵌入式设备的分类
嵌入式系统由硬件和软件组成,旨在解决可能涉及通过传感器和执行器与环境进行交互的特定任务。可以将各种设备 (例如数码相机,打印机,硬盘控制器,智能手机,汽车和智能电表) 视为嵌入式设备。可以根据不同的标准 (例如使用范围,计算能力,成本和大小) 对嵌入式系统进行分类。
由于我们专注于嵌入式系统中的漏洞检测,因此提出的基于OS类型的分类。与前述分类 (例如,计算能力) 相比,该分类可以提供关于由给定嵌入式设备提供的安全机制的更多信息。基于此分类,嵌入式设备分为三种类型,定义如下:
- 类型Ⅰ:基于通用操作系统。 它通常代表嵌入式设备,这些设备利用经过修改的轻量级 Linux 操作系统来处理复杂的逻辑,例如接入点和路由器。
- 类型Ⅱ:基于嵌入式操作系统。类型Ⅱ的操作系统是为具有低计算资源(如CPU、内存或电源)的嵌入式设备设计的。OS可能没有类型Ⅲ的OS中存在的内存管理单元(MMU),然而,应用程序和内核之间的逻辑分离仍然存在。这样的OS通常容纳在单一用途的嵌入式设备中,例如LTE调制解调器或DVD播放器。
- 类型Ⅲ:没有操作系统抽象的嵌入式设备。Ⅲ型设备没有操作系统,而是使用单个控制循环和中断处理程序来响应来自外部世界的事件。