0 引 言
当前,随着物联网技术的不断发展,嵌入式设备被广泛应用于各行各业中
[1],例如汽车、医疗等领域。这些嵌入式设备通常将软件驱动的微控制器与外围设备结合在一起,运行在此类设备上的软件又称为固件。与传统个人计算机中的处理器相比,微控制器体积小、能耗低、扩展性强,非常适合被嵌入到系统中执行特定的任务,但这是以增加有限的处理资源为代价的,会导致嵌入式设备更加难以编程和与外界进行交互。近年来,由于设备制造商对安全设计的忽视、设备固件更新不及时或难以更新等原因,越来越多的设备漏洞被披露
[2,3]。因此,对嵌入式设备进行安全性测试至关重要。
模糊测试是一种有效的漏洞挖掘技术,该技术被广泛应用于网络协议、浏览器、操作系统内核、图像处理、音视频文件解析等各类软件的漏洞挖掘工作中,并产生了良好的效果。然而,现有的模糊测试无法直接应用到固件测试中,这是因为固件通过外围设备与外界进行交互,缺少直接从外界获取数据运行的接口
[4]。为了解决这一问题,系统仿真、软硬件结合和固件托管等三种固件测试技术被提出。系统仿真
[5,6]对设备硬件进行仿真以在不使用物理硬件的情况下对固件进行测试,可以有效地利用现有的漏洞挖掘技术。软硬件结合
[7,8]既提供了可以有效利用现有漏洞挖掘技术的仿真环境,又可以使用实际的物理设备来处理无法仿真的外设请求。固件托管
[9,10]通过分析嵌入式设备固件与外围设备的交互来理解固件需要的外设输入,用建模替代硬件,进而在软件层面上对固件进行测试。因此通过以上三种技术,模糊测试可直接应用到固件测试中。
使用模糊测试技术对固件进行测试称为固件模糊测试。当前的一些固件模糊测试技术有IoTFuzzer
[11]、RPFuzzer
[12],它们重点研究的是如何在嵌入式设备固件上应用模糊测试,而如何提升应用的效果尚未有明确的案例。上述技术在测试固件时将AFL(American fuzzy lop)简单继承并使用
[13]。作为一个简单的灰盒模糊测试器,AFL并不擅长突破复杂的路径条件,因此测试用例进入到固件执行之后很难访问到新路径。一个典型的例子是固件与外设进行数据传输时通常使用校验和作为错误校验机制以确保数据的完整性,例如USART(universal asynchronous receiver/transmitter)协议设置奇偶校验位,Modbus RTU协议使用16位的CRC(cyclic redundancy check)作为校验,一般的模糊测试很难突破这一复杂的路径条件。对此,Feng等
[14]提出了固件模糊测试方案p2im(processor-peripheral interface modeling)。p2im的解决方法是通过逆向工程手动将固件包含的校验和部分进行注释并重新编译,以在测试阶段获得更多的代码,这些工作需要那些拥有专业知识的人花费大量时间完成。
针对校验和检查这一复杂路径条件,本文提出了一种高效省时的固件测试改进方法,它可以被用于改进现有的固件模糊测试方案。在测试固件时,根据固件与外设交互使用的通信协议来修改模糊测试器产生的测试用例,使得测试用例在输入到固件之后可以突破校验和检查这一复杂的路径条件。我们使用此方法对p2im方案进行了改进,并通过测试两个来自真实设备的固件来对比改进前后的测试性能。
1 基本概念
1.1 模糊测试器
模糊测试器是被用来产生模糊测试所需的测试用例的,大部分模糊测试器实现复杂,但其基本工作流程和功能的相似度较高,存在较多共性
[15]。AFL是一款基于覆盖引导(coverage-guided)的模糊测试工具,它通过记录输入样本的代码覆盖率,调整输入样本以提高覆盖率,增加发现漏洞的概率。它可以配合QEMU (quick emulator) 对闭源的二进制文件进行模糊测试
[16],挖掘可能存在的内存安全漏洞,如堆栈溢出、double free等。其工作流程
[13]大致为:1) 在源码编译程序时进行插桩,记录代码覆盖率;2) 选择一些输入文件作为原始测试集加入输入队列;3) 将队列中的文件按一定的策略进行“突变”;4) 如果变异文件更新了覆盖范围,则将其保留并添加到队列中;5) 上述过程会一直循环,期间使程序崩溃的文件会被记录下来。
1.2 p2im
p2im提供了一种新的固件测试方法,其思想在于提取固件处理器和外设寄存器之间的数据传递模式,构造出模块化的寄存器行为逻辑,并因此在处理器访问外设寄存器时正确判断传递的数据类型和大小,从而在保证固件正常运行的前提下实现直接和模糊测试产生的输入对接。其工作流程分为两步:1) 模型抽象。以ARM Cortex-M
[17]架构为例,根据外设寄存器在固件执行逻辑中的具体功能,p2im将所有寄存器分为4个种类,即控制寄存器、状态寄存器、数据寄存器和控制&状态寄存器,并分别得到每个种类寄存器与固件处理器传输数据时的访问模式和处理策略。2) 模型实例化。在得到各种寄存器的访问模式和处理策略后,p2im在支持ARM Cortex-M指令集的QEMU中运行固件代码,在发现固件尝试访问外设寄存器时,识别出寄存器种类,并根据应对策略返回合适的值。除此之外,外设和固件之间还会通过中断来传递数据。p2im在处理中断时,先收集目前能够触发的所有中断,然后简单地每隔一段固定代码基本块按顺序触发一个中断。
2 本文原理与方案设计
2.1 原理和思路
嵌入式固件在与外界进行数据交互的过程中,通常使用校验和检查机制以确保数据的可靠性。
图1展示了校验和检查在固件中的应用,固件在从外设获得数据之后对其进行校验和检查,只有通过校验和检查后才能够继续执行其他任务。
现有的固件测试方案p2im直接使用AFL生成的数据作为固件的输入进行测试。由于AFL生成数据的过程是随机的,当其对具有校验和检查的固件进行测试时,测试用例很难通过校验和检查。以Modbus RTU通信协议使用的16位CRC为例,在简单考虑数据部分不变的情况下AFL生成正确校验和的概率为,即AFL产生的测试用例将极难通过固件的校验和检查。针对这种情况,p2im的处理方法为删除固件中的校验和检查部分代码。由于p2im是针对固件二进制文件进行测试的,而且固件的源代码很难获得,这种方法需要拥有专业知识的人对固件二进制文件进行逆向分析,将固件中的校验和检查部分进行注释之后重新编译固件进行测试,因此会带来大量的人力和时间成本。
针对AFL产生的测试用例极难通过固件校验和检查的问题,本文的解决思路为对AFL生成的测试用例进行一定的修改,使得测试用例能够成功通过固件的校验和检查。固件往往以二进制文件的形式存在,因此不能够根据固件源代码去分析固件所使用的校验和检查格式。但是通过查看固件的相关文档,可以获得固件与外界进行数据交互的通信协议,通信协议规定了数据的格式以及校验和检查机制。在获得固件对输入数据格式的要求之后,可以使用一个后处理程序对AFL产生的测试用例中的校验和部分进行修改,使其在测试时可以成功通过固件的校验和检查。这种方法简单高效,避免了对固件二进制文件进行复杂耗时的逆向工程。
2.2 方案设计与实施
AFL提供了一个后处理程序的接口,数据生成程序可以调用后处理程序来对所有变异的测试用例进行最终清理。具体来说,AFL将为每个突变的输出缓冲区调用后处理函数,用户可以对测试用例进行修改。
通过查看固件的说明文档获得固件所使用的通信协议,在明确固件与外设之间传输数据的格式之后,利用一个后处理程序对AFL生成的测试用例进行相应的修改,使得每次产生的测试用例都符合数据格式要求。我们设计的后处理程序流程为:1) 分配适当大小的缓冲区,并将测试用例移到该缓冲区中;2) 根据固件使用通信协议的格式读取数据并计算校验和;3) 使用新计算的校验和覆盖原始校验和;4) 返回新的缓冲区指针。
图2展示了使用本文提出方法对p2im方案改进后的固件测试框架。框架以一个固件二进制文件作为输入,使用QEMU运行固件,之后对处理器外设接口建模。在发现固件尝试访问外设寄存器时,识别出寄存器种类并将每个外设寄存器以及寄存器之间的相互依赖关系映射到内存中。在运行时,模糊测试器生成的测试用例经过我们设计的后处理程序处理后,通过数据寄存器访问进入固件执行,固件在获得输入数据后对数据进行校验和检查,校验成功之后执行相应功能对数据进行处理。并将QEMU收集的代码覆盖信息返回给模糊测试器。
3 评 估
使用经本文方法对p2im改进后的固件测试方案(improved p2im,Ip2im)对固件进行24小时的测试,通过对比Ip2im与p2im方案的固件测试结果来评估本方法的效果。除此之外,我们还手动验证了Ip2im可以在固件测试时绕过固件的校验和检查。
3.1 实验配置
选择PLC(programmable logic controller)和Heat Press这两个在真实环境下使用的固件进行测试,不对其固件二进制文件做任何的修改。通过查看固件的相关文档,发现它们通过串行端口连接到总线上,使用Modbus RTU通信协议与外设进行数据交互,获得数据之后都会对其进行校验和检查。对这两个固件的说明如下。
1) PLC:可编程控制器是一种坚固耐用的嵌入式设备,用于控制生产流程。我们选择的固件是消毒机的一部分,并通过工业通信协议Modbus管理PLC与远程SCADA(supervisory control and data acquisition)系统的通信
[18]。
2) Heat Press:该固件对应于纺织品升华生产线中使用的工业热压机。固件实现了配方管理器,用于控制升华过程的温度、时间和压力。该系统具有触摸屏和一个使用Modbus协议的远程工业I/O通道。
3.2 实验结果
表1是Ip2im和p2im基本块覆盖率对比。与p2im相比,Ip2im在对两个固件的测试中基本块覆盖率都有提升。在对PLC的测试中Ip2im的基本块覆盖率比p2im的高3.01%;在对Heat Press的测试中Ip2im的基本块覆盖率比p2im的高5.81%。
表2展示了两种固件测试方案函数覆盖率的对比。从
表2中看Ip2im固件的函数覆盖率比p2im的也有提高,这是因为固件在boot阶段访问了大量的函数进行自检,此类函数不会对输入数据进行操作。基本块覆盖率和函数覆盖率的提升表明使用本文提出的改进方法可以覆盖固件的更多代码。通过反汇编工具Ghidra
[19]查看多出的代码,发现它们是固件对输入数据进行相应处理的部分,可见测试用例已经通过了固件的校验和检查。经过后续实验我们发现,在多出的代码中对输入数据进行处理时没有对数组边界进行很好地检查,固件在执行到这里的时候出现了缓冲区溢出,程序发生崩溃。
固件测试的目的是尽可能多地去探索固件可能存在的路径,得到使得固件崩溃或挂起的测试用例,进而去发掘固件可能存在的漏洞。
图3是两种方案在固件测试过程中探索的路径数量对比,在使用Ip2im之后,路径数量有了显著的增加,这是由于测试用例只有在通过固件的校验和检查之后才能探索更多的路径,执行固件更多的功能。
图4展示了在测试中引起固件程序崩溃的测试用例数量。从
图4可以看出,使用Ip2im后显著提升了测试用例数量,为之后挖掘新的漏洞提供了可能。
表3展示了固件测试发现的漏洞数量,p2im在PLC和Heat Press中都没有发现漏洞,而Ip2im在PLC和Heat Press却发现了漏洞。手动分析漏洞的具体类型见
表4。
表4的结果表明了Ip2im在实际应用中的价值。
综合以上的实验结果可知,本文提出的改进方法在测试具有校验和检查固件存在的问题时,不需要对固件二进制文件进行复杂、耗时的逆向处理,并且取得了较好的代码覆盖率,提升效果显著。
4 结 语
本文研究了在测试具有校验和检查这一复杂路径条件的固件时,现有固件测试方案存在的问题,并给出了相应的改进方法。根据固件与外设交互使用的通信协议来修正模糊测试器生成的测试用例,进而在测试时突破固件中的校验和检查这一复杂路径条件。我们使用该方法对固件测试方案p2im进行了改进,并通过测试两种具有校验和检查的真实固件来评估本方法的效果。实验结果表明,在固件测试中使用此方法可以成功突破校验和检查这一复杂的路径条件,提升了基本块覆盖率和函数覆盖率,并成功发掘了固件存在的漏洞。
国家自然科学基金(U1836112)
国家自然科学基金(61876134)
国家自然科学基金重点项目(U1536204)