设为首页 | 加入收藏 | 返回首页
保密技术  
保密技术
·当前所在的位置:首页 > 保密技术

嵌入式环境下代码安全分析与研究

发布日期: 2025年02月28日

 【摘 要】 为有效提高嵌入式软件在投入生产环境前发现潜在安全问题的效率,本文对嵌入式环境下软件开发中的代码安全控制进行了深入分析与研究,阐述了在资源受限环境下软件安全测试的方法和技术,并重点介绍了在软件编译链接之后,通过对二进制文件进行测试进一步发现嵌入式软件安全问题的方法。

 【关键词】 嵌入式 代码安全 模糊测试

 1 引言

 据调查显示,全球嵌入式系统市场收入在6年内增长达40%,从2015年的1590亿美元增长到2021年的22534亿美元。这一增长的主要驱动力是市场对节能、智能的电子设备日益增长的需求。此外,行业提供的新可能性及在嵌入式系统中使用多核架构提供的新应用也加速了这种增长。嵌入式系统是一种包含微处理器和软件的电子产品,广泛应用于工业生产、医疗电子、汽车电子、网络通信、军事航天等领域。嵌入式系统一般都包含相对固定的组件,如芯片、闪存、固件等。组件组成主要包括硬件和软件部分,其中软件部分直接与硬件交互,因此对于其安全性和可靠性有着更高的要求。

 近20年来,有关嵌入式软件的零日(0Day)漏洞层出不穷,而分析其中大多数漏洞成因往往是较为低级的错误导致的。如果能在软件的开发阶段或应用验证阶段通过一系列测试方法及流程,将可能引发的安全问题尽可能规避掉,将大大提高软件的安全性。这一需求在无法经常更新迭代的嵌入式环境下显得尤为重要。本文将针对C/C++环境的嵌入式系统中常见的软件安全问题进行讨论,并介绍几种常见的测试方法,以提高嵌入式软件的安全性、健壮性。

 2 嵌入式系统常见的安全问题

 在安全方面,针对嵌入式系统的攻击可大体分为3类,分别是针对嵌入式软件的攻击、针对网络的攻击和侧信道攻击。本文将针对嵌入式软件的安全问题和几种常见的影响系统稳定性的编码问题进行讨论。

 2.1 缓冲区溢出漏洞

 缓冲区溢出是各类软件中十分普遍的安全问题,不仅在嵌入式软件中存在,在其他应用软件和操作系统中也十分常见。表1为国家信息安全漏洞库(CNNVD)收录的2022年6月漏洞类型统计表,从表中可以看出缓冲区错误类型漏洞占比高达8.4%。缓冲区溢出问题的根本原因在于过于信任输入,而没有正确检查动态空间的边界,开发者将长于目标的数据进行拷贝,因此覆盖了与目标相邻的区域。缓冲区溢出的问题十分严重,可能导致目标系统宕机、命令执行等后果。实践得出,缓冲区溢出可以发生在堆、栈、bss等存放变量的任何区域,攻击者可以通过事先计算好的长度构造payload来修改函数的返回地址,或替换成恶意代码的起始地址,以完成攻击。

表1 2022年6月漏洞类型统计表(只截取前10种)


 2.2 内存泄漏

 内存泄漏是指程序中已被动态分配的堆区内存由于编程人员或者其他原因而未进行释放,造成的系统内存浪费,内存泄漏问题并没有泄漏大小之分,无论内存泄漏多么轻微,都会导致程序运行性能降低,最终将会在有限的时间内消耗掉全部内存,导致系统的崩溃。内存泄漏问题在嵌入式系统下显得格外重要,嵌入式系统的内存资源通常比其他平台要小得多,如果存在内存泄漏问题,将在更短的时间内造成严重后果。

 2.3 空指针引用

 空指针引用顾名思义就是使用了一个没有指向合法地址空间的指针,通常是由这个指针没有被初始化、正确赋值或原本指针指向的内存空间已经被释放等原因导致的。如果编程人员在使用一个指针之前没有对其进行非空判断,都有可能造成空指针引用,原因是在C/C++环境中即使使用了malloc/new内存分配函数对其赋值,如果不对返回结果进行检查,也无法确保此时的内存分配是成功的。空指针引用问题比内存泄漏问题更为严重,因为前者可能导致系统直接崩溃。

 2.4 格式化字符串漏洞

 格式化字符串漏洞主要利用C语言中print系列的函数,如printf、sprintf、fprinf等C库函数。格式化是为了控制显示文本的样式,如%d是以整数的形式输出,%p打印指针地址等,在使用此类函数前,如果能给定预料之内的参数,并不会有任何安全问题。但是若对输入格式不进行控制,支持用户任意输入,将会造成严重的安全问题。其攻击原理可以泄露特定寄存器和栈上的值,从而给攻击者创造了发挥的空间,造成系统内存信息泄露、控制代码执行逻辑、远程命令执行(RCE)等严重后果。

 3 嵌入式软件安全测试的方法和技术

 3.1 静态测试

 静态测试主要通过静态测试工具对软件的源代码进行安全扫描,一般静态测试常用的工具有Fortify SCA(Static Code Analyzer)、VCG(Visual Code Grepper)等。此类工具的基本思想都是从源代码中提取原始特征,如字符串、基本块、指令序列、语法树、函数调用图等,之后再对这些特征与先准备的软件安全规则库进行匹配来确定源代码中是否存在相应的漏洞。静态分析是在不执行源程序的情况下对代码进行安全检测的方式,它包含很多方面的技术,如控制流分析、数据流分析、常量传播和指针分析等。静态测试作为一种保证源代码安全的测试方法,可以较为有效地检测出空指针引用、格式化字符串等问题,将软件的安全问题控制在编码阶段。静态测试的流程如图1所示。

图1 静态安全测试流程

 3.2 动态测试

 动态测试是针对软件或系统非常有效的测试方法,同时也是使用最多的针对嵌入式设备的动态漏洞分析技术。动态测试是在真实环境或者模拟环境中对运行中的程序通过对输入进行随机变换,观察在不同的输入下程序的运行结果,分析和判断其结果是否满足预期。例如,对于内存泄漏问题,通常可以使用一些开源的内存泄漏扫描工具,在被测程序源码中进行插桩,检查程序从开始到运行结束的内存释放情况。当然,无论何种工具,都存在误报的情况,但使用工具的好处是可以尽量缩小范围,再由研究人员分析当前结果是否为安全问题。

 动态测试在理论上几乎可以验证所有存在的安全问题,其误报率也比静态测试少。但是,动态测试也存在着过于依赖程序运行、程序分支路径覆盖不全、漏报等缺点。动态测试还与测试人员的能力及测试用例的准备密切相关,如果被测系统规模过大,测试用例集合也随之增大,则会导致漏报率提高。

 3.3 嵌入式软件二进制模糊测试

 静态和动态测试方法可能无法有效避免全部的安全问题,若要进一步挖掘安全问题,还需要借助一些其他测试方法。发现嵌入式系统中的安全问题是一项具有挑战性的工作,因为嵌入式系统与其他传统计算机相比,具备体积小、可移植性好、直接与应用程序集成等特点;在运行时,它们占用较少的内存资源和空间,而相应的安全机制占用较多的存储空间,降低了内存的可利用率。因为在受限的嵌入式系统没有额外的安全机制,模糊测试技术(Fuzz)作为寻找安全问题最有效的手段之一,一直受到安全测试人员的青睐。在安全程序中使用模糊测试技术可以帮助发现系统中未知的漏洞。对于嵌入式环境下的安全测试,针对二进制文件的模糊测试是十分必要的选择,此方法可用来排除在编码过程中出现的大部分安全问题。模糊测试通过向目标插入事先构建的输入来发现漏洞和故障,对于查找程序问题的效率较高,如内存错误、空指针引用、格式化字符串、死锁、无限循环、不当的资源管理等。如图2所示,二进制模糊测试一般分为以下5个阶段。

图2 模糊测试一般流程

 首先是准备阶段,将准备好的被测二进制格式文件进行输入;其次是模糊数据生成,一般模糊数据生成就是改变特定的数据;接下来将模糊数据作为输入进行执行和检测,如果未结束,将回到数据生成阶段;周而复始,直至程序崩溃;最后生成报告。

 在通过对二进制代码进行模糊测试的过程中,测试人员可能面临的难题是在不同的嵌入式环境下系统所产生的不同二进制代码,如不同的编译器的代码生成算法、不同的指令集等,导致安全测试人员难以通过相似性来判断存在的安全问题。为了克服这种困难,可以借助一些第三方开源模糊器加QEMU等仿真器对嵌入式环境下的二进制代码进行模糊测试。目前常见的模糊器有以下2种。

 (1)American Fuzz Lop

 American Fuzz Lop(AFL)是一款基于覆盖引导的模糊测试工具,其原理是通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,提高发现漏洞的概率,AFL模糊器的工作流程大致如下:

 ①在编译阶段进行插桩(在每个基本块的开头插入一段汇编代码),用来记录源码的覆盖率;

 ②选择输入文件,作为初始测试集;

 ③将读入的文件按照策略进行“变异”(按位反转、替换边界等);

 ④如果文件更新了范围,将其保留;

 ⑤在循环以上步骤时,若触发了crash的文件,将被记录。

 (2)PTFuzzer

 PTFuzzer是在AFL的基础上实现的一款模糊测试工具,它采用了Intel Processor Trace硬件部件来收集程序执行的路径信息,优化了原来AFL通过编译插桩方式获取程序执行路径信息的方法。由于AFL要Fuzz二进制格式文件,需要借助QEMU的虚拟化支持,在这方面PTFuzzer要优于AFL,但是PTFuzzer需要使用Intel系列芯片的PT支持,造成PTFuzzer有一定的局限性,导致在测试嵌入式软件时可能需要解决嵌入式软件的平台支持问题。

 综合比较以上工具特点,使用QAFL(QEMU与AFL的组合)更适合针对嵌入式软件进行模糊测试,其原因是使用QAFL的组合不依赖于特定的芯片支持,能够保证在多变的嵌入式环境下顺利进行软件的模糊测试。

 使用二进制Fuzz的方法可以在不依赖程序源码或者真实运行环境下对嵌入式软件进行测试,当与其他漏洞检测方法如使用代码静态测试工具、人工审查、逆向工程(通过对二进制文件进行反编译,分析各个代码模块的逻辑内容与调用关系,从而发现嵌入式系统中可能存在的漏洞的一种技术手段)进行比较时,基于二进制的模糊测试可以更高效率地发现诸如缓冲区溢出、内存泄漏、空指针引用、格式化字符串等安全问题。此外,它还具有可以进行大规模测试且无人值守的优势,因为模糊过程通常是自动化的。模糊测试的技术特点使其漏洞检测的准确率接近100%,并且可为每个漏洞提供详细的回溯调试信息,降低运维成本,消除误报带来的噪音。但是,由于误报的原因,在进行模糊测试后,还需手动验证测试结果以精确定位程序存在的安全问题。

 4 结语

 本文归纳了嵌入式环境中安全风险较大的几种常见安全问题,并讨论了嵌入式环境下的一些测试方法,主要介绍了静态测试、动态测试和几种二进制的模糊测试工具的特点和原理。但是本文提出的测试方法仅仅是处于软件测试或软件开发周期的其中一个阶段,如果希望嵌入式软件更为健壮、安全,还需要控制好各个环节,从编码开发、测试、维护等阶段来提高嵌入式软件的安全性。


 (原载于《保密科学技术》杂志2023年2月刊)

【返回】