物联网(Internet of Things, IoT)是由各种拥有唯一标识的计算设备、机械或数字对象、人与物通过通信技术建立连接, 实现自主的人、机、物之间的数据传输与信息交换的系统。随着设备硬件的发展与以5G、NB-IoT为代表的通信技术的进步, 众多物联网设备如移动终端、路由器、交换机、网络监控摄像头、智能家电、智能汽车、智能门锁、智能电表等被接入到网络空间, 广泛部署、应用在智能交通、智能医疗、智能电网等安全攸关的领域。根据 GSMA预计, 到2025年, 全球物联网设备数目将高达 25.3亿。
固件(firmware)是运行在物联网设备上的核心软件之一。IEEE 标准 12207-2008 将固件定义为“硬件设备和以只读软件形式存储于硬件设备中的计算机指令和数据的结合”。大部分嵌入式设备中的软件都是以二进制形式存储在只读存储器、可编程只读存储器、可擦可编程只读存储器、带电可擦可编程只读存储器、闪存等永久存储设备中, 因此该类软件一般称为固件。
固件按照其是否内置操作系统、以及内置操作系统的类型可分的三类:
(1)单片固件, 通常采取单个二进制镜像的形式, 无需底层操作系统, 直接基于底层硬件驱动完成所有功能, 或者只包含部分系统的库;
(2)基于 Linux 的固件, 以 Linux作为底层的系统, 基于 Linux 进行开发;
(3)基于 RTOS 的固件。RTOS(real-time operating system)是指实时处理数据、没有缓冲延迟的操作系统。
在嵌入式应用中使用 RTOS 可以使程序最大化利用有限的计算资源、简化应用程序设计、提高开发人员效率。RTOS 受到了越来越多编程人员的重视,涌现出一批优秀的嵌入式实时操作系统如 VxWorks、QNX、FreeRTOS、RTEMS等,其中FreeRTOS因其开源免费、小巧简单等特点受到了学术界和产业界的广泛采用。
固件是设备上电后最先执行的代码,主要负责系统硬件的初始化、加载操作系统、获取最终控制权、并为上层软件有效使用硬件设备提供调用接口。早期的计算机上的固件叫作基本输入输出系统 (Basic Input Output System, BIOS), 由于其开发效率低,功能扩展性差以及更新机制不完善等缺点,已经逐渐被支持图形界面和鼠标操作的统一可扩展固件接口 (Unified Extensible Firmware Interface, UEFI) 所取代。嵌入式设备由于存储空间小,实现功能与计算机相比较更为单一, 因此嵌入式设备上的固件通常是指嵌入式设备中的整个软件系统, 即包含操作系统、第三方库、应用程序等。上电之后固件负责硬件平台的初始化和之后的嵌入式设备的功能实现。
固件中存在缺陷是造成物联网设备遭受安全攻击的根本原因之一。一方面, 固件主要由C语言实现, 尽管C语言为程序员提供了多种机制和 API(应用程序接口)确保安全, 但也需要程序员做出关键决定,如输入合法性检查、越界检查等等。程序员对代码安全性认识不足导致编程实践中存在疏忽、失误以致程序的关键部分存在缺陷,在连接互联网运行的场景下,这样的缺陷成为安全漏洞,容易被黑客利用并攻击;另一方面,固件的执行权限高于操作系统,能实现对所有硬件设备的直接控制,同时也是操作系统安全机制的盲区所在,始于固件的攻击能够直接或间接地影响上层操作系统或应用软件的安全机制。另外, 越来越多的由早期版本固件驱动的嵌入式设备也接入物联网,早期固件缺乏对联网环境下的安全考虑, 带来了安全威胁。
基于固件缺陷的安全攻击事故频发。典型的, 2018年,思科Talos安全研究团队发现攻击者利用恶意程序VPNFilter感染了全球54个国家的超过50万台路由器; 2016年,攻击者利用物联网设备对美国域名服务器管理服务供应商Dyn发起分布式拒绝服务(DDoS)攻击, 制造了有史以来规模最大的 DDoS 攻击。
有效的固件缺陷检测是保障物联网设备安全的关键。在联网环境下, 日益增长的嵌入式设备数目,日益复杂的固件系统规模,以及嵌入式设备低功耗环境下保护机制的缺失,使得固件安全问题日益凸显,检测固件中的缺陷成为了近年来的研究热点。
固件处于计算系统的核心地位,自身的安全缺陷往往隐藏较深,需要满足特定的条件才能被触发,加之,物联网设备具有多样、异构等特性,这使得检测固件缺陷变得极其困难。现有的缺陷检测技术主要包括静态分析、符号执行、模糊测试、程序验证以及机器学习,然而现阶段基于上述技术的缺陷检测方法与工具在应用到物联网固件时依旧面临挑战:
(1) 无法获取源码且代码类型复杂。厂商为了保证设备安全通常不会公开固件源码; 且为了完成设备的各项功能, 固件通常混杂有汇编、Java 、 JavaScript 等不同类型代码, 阻碍了反编译的进行;
(2) 不同类型的固件差别较大。现有的固件根据所使用的系统可以分为单片固件、基于Linux的固件和基于RTOS的固件, 不同类型固件代码架构差异较大; 且运行在不同硬件上的固件处理器架构和内存架构差异较大,极大阻碍了固件测试工具的可扩展性;
(3) 测试用例难以构建。固件由于其功能严重依赖外部输入和中断,外设类型极其丰富及内部状态复杂,因此难以构造统一的输入来满足众多外设,也难以构造极端的测试场景去探索更深的路径。
(4) 依赖资源及技术不足。固件运行的硬件资源有限,因此较难在物联网设备中直接运行测试软件; 且物联网设备通常很少向第三方提供完备的测试接口,无法获取足够的固件运行时信息;固件的反汇编技术仍然存在不足,当固件中存在混淆机制时难以获取源码; 模拟器能力有限导致大量固件无法进行模糊测试。
本文针对物联网设备的固件中存在的缺陷进行了研究。通常, 错误指代码中对编程语言规范的违反; 缺陷指固件设计与代码实现上的不足;漏洞指可以被攻击人员利用的缺陷。本文将使用缺陷来指代固件代码实现和设计上的不足,以及可被攻击者利用的漏洞。固件中的缺陷可以分为三个大类, 分别为实现缺陷、配置缺陷和定制缺陷。
实现缺陷指开发人员在开发过程中引入的源码上的不足, 实现缺陷由程序开发人员造成; 配置缺陷指部署人员在部署过程中编写配置文件时引入的缺陷, 配置缺陷由程序部署人员造成; 定制缺陷指用户为使固件满足特定需求或者环境而对固件进行了某些修改, 这一过程中引入的缺陷, 定制缺陷由程序使用人员造成。其中, 实现缺陷又包含内存损坏缺陷、命令注入缺陷、程序逻辑缺陷、并发问题缺陷, 配置缺陷包含功能配置参数缺陷、性能配置参数缺陷、权限配置参数缺陷。
2.1 实现缺陷
2.1.1 内存损坏类缺陷
内存损坏类缺陷指不正确的内存访问导致堆、 栈内存发生错误。大部分固件程序本质上来说就是用 C 语言写成的程序, 只不过底层部分会需要一些汇编指令和硬件直接交互, 因此固件中的内存损坏类缺陷同普通桌面软件中的内存损坏类缺陷没有区别, 而这些缺陷也同样有可能导致被攻击者利用的漏洞。
具体来说可以有以下几类: 1)堆溢出漏洞; 2) 栈溢出漏洞; 3)内存泄漏漏洞; 4)数组越界读写漏洞; 5)use-after-free 漏洞; 6)double-free 漏洞; 7)空指针解引用; 8)格式字符串漏洞。
内存损坏缺陷在缺陷检测中较为常见, 固件中的内存损坏缺陷可能会引起固件程序挂起、崩溃、重启、敏感信息泄露、拒绝服务攻击、缓冲区溢出攻击等行为, 而且内存相关缺陷大多由于外部输入引起,攻击者可以通过构造特定的输入来触发漏洞以达到特定目的。
例如, 在 ASUS 路由器中的栈溢出漏洞会造成远程代码执行(CVE-2017-12754); FreeRTOS 的函数栈中由于不正确的错误处理逻辑导致了double free(CVE-2018-16528) 和 uninitialized pointer free (CVE-2018-16522); Netgear 的无线驱动中包含有一个堆溢出漏洞(CVE-2006-6125), 攻击者可以通过构造一个特定的 802.11 管理片段来触发这个漏洞.
2.1.2 命令注入缺陷
命令注入缺陷指由于缺少对用户输入进行完备 的检查导致恶意用户可以通过构造输入来运行非预期的命令, 与普通桌面软件相比, 固件直接操作 硬件, 拥有更高的权限, 因此命令注入缺陷的危害 也更大。包含系统的固件大都支持运行命令行, 但这也给固件留下了安全隐患, 当固件没有对用户输入的命令行指令进行检查时, 攻击者将可以构造特定的指令来完成某些动作, 达到自己的目的, 如攻击 者可以使用查询来查看嵌入式设备上的数据库或者获取嵌入式设备中的文件, 以造成敏感信息泄露; 可以使用删除指令来删除设备上的重要信息, 使系统无法继续运行。
例如, 在D-Link设备DIR-823G中存在一个命令 注入缺陷(CVE-2019-7298), 当攻击者发送一个定制 的 HNAP1 请求时可以触发这一缺陷, 缺陷的触发形成漏洞, 使攻击者可以运行任意的系统命令; D-Link DCS 网络摄像机中没有对 IP 地址进行检查, 可以通过/common/info.cgi 获取网络摄 像机的配置文件, 无需任何验证就可读取其中的敏感信息(CVE-2018-18441)。
2.1.3 程序逻辑缺陷
程序逻辑缺陷是指程序不严谨的逻辑所留下的缺陷, 使软件无法正常运行或给了不法分子可乘之机。如系统权限等级设计不严谨, 就会使系统的底层置于危险之中; 系统或者传输过程中没有加密或者加密算法过于简单, 就会使系统有被破解的风险; 在代码中硬编码账号、密码等信息, 使系统容易被不法分子侵入, 且大部分厂商为了方便用户使用, 通常会为设备设置相同的出厂用户名和密码, 如果用户未对其进行修改, 则会有遭遇攻击的风险; 防御措施不完善就容易遭受各种攻击如拒绝服务攻击等。
例如, Hikvision 的大量设备在配置文件中硬编码了某些密码, 这使得不法分子可以通过这些密码来获取一定的权限; Netgear FVG318 在 TCP 通信中使用了错误的校验和, 使设备容易受到拒绝服务攻击(CVE-2006-4143); NETGEAR WGT624 无线路由器设备中在配置文件中使用明文记录了敏感信息, 使攻击者可以获取密码并取得权限。
2.1.4 并发问题缺陷
并发问题缺陷指对多线程运行的固件设计不合理导致固件运行时产生数据竞争、死锁等行为。随着硬件的发展, 嵌入式设备不仅仅局限于单个任务的运行, 通常会被设计多个任务同时运行, 便会产生并发问题缺陷, 而这种缺陷无论是工程人员自己编写的调度系统还是使用现成的 RTOS 进行调度都有可能发生。
为嵌入式软件提供多任务调度是 RTOS 最基本的功能, 通过 RTOS 提供的 API 可以将 函数程序分成独立的任务, 并为他们提供了多种调度方式, 此外还提供了任务中断、任务间通信等功能。RTOS 提供的多任务调度简单易懂, 但使用不当也会造成许多问题, 例如死锁、数据竞争等。
2.2 配置缺陷
在大型软件领域常见的配置错误在固件中也经常发生, 随着开发人员对代码的可移植性和可重用性的追求, 产生了大量的配置文件来适配不同的硬 件、架构和系统, 使得厂商在不同平台上的代码无需进行太多修改。广泛使用的 FreeRTOS 便是可移植的一个案例, FreeRTOS 作为一个可移植、可配置的轻量级操作系统, 在提供了大量便利的同时也带来了许多问题, 尤其是其配置问题。
具体的, FreeRTOS 支持 35 种微处理架构, 但针对于每一种架构都需要对 FreeRTOS 进行一系列的配置。用户在使用 FreeRTOS 时也需要根据自己的应 用来进行相应的配置以符合自己的要求。AWS 为 FreeRTOS 编写了许多例如 TCP/IP、UDP、IO 等函 数栈, 这些函数栈的使用需要用户根据需要进行配置; 开发人员在进行开发时通常会复制他人的配置 文件并自己根据需要做一些修改, 但相当一部分开发人员在进行配置时并没有很好的理解这些配置的 真正含义, 往往一个不起眼的不当配置就可能引起致命的缺陷, 这些缺陷有可能会造成系统崩溃、挂起或者其他无法预知的故障。
典型的 , 安全公司辛培力安 (Zimperium) 对 FreeRTOS 系统及其 TCP/IP 相关的函数栈进行分析, 发现了大量同配置相关的缺陷, 并获得了CVE 编号如 CVE-2018-16528 等[17], 这些缺陷可能会造成信息泄露、远程代码执行。
配置缺陷可以分为功能配置参数缺陷、性能配置参数缺陷、权限配置参数缺陷。固件上的配置缺陷目前学术界研究缺失, 但大型软件系统和云系统中都有较多研究, 这些研究对固件配置缺陷检测或许会有启发。
2.2.1 功能配置参数缺陷
功能配置参数缺陷指的是由于部署人员的粗心或对配置项的不了解而产生的诸如配置值不当、类型不匹配、配置项缺失等问题。配置值不当包括不正确的文件路径、配置值错误的拼写等。
D-Link DIR-822 设备中的配置文件中有多个错误的配置且缺乏安全检查(CVE-2018- 19990), 这些错误可能会影响设备的内存管理; 类型不匹配指错误的配置值类型, 如给 int 型的配置项设置了一个字符串类型的值; 配置项的缺失是指没有对某一项配置赋予值, 如CVE-2019-10132。这类错误通常只有当程序运行到需要这一配置项时才会发现, 因此潜藏较深。
2.2.2 性能配置参数缺陷
性能配置参数缺陷指性能相关配置项的值发生错误导致无法提供系统预期的性能, 或者使固件各部分无法很好兼容, 性能配置参数同硬件有较大联系。这类缺陷通常不会直接引起系统挂起、崩溃等异常行为, 但是无法提供系统预期的性能, 无法满足用户的需求。如在配置文件中为固件分配了较小的内存空间, 这样就无法提供预期的性能。
例如, 在CVE-2019-2041中, 由于没有对 NFC 进行合理配置而是使用了默认值, 导致了 NFC 无法区分个人设备。
2.2.3 权限配置参数缺陷
权限配置参数缺陷允许用户做出超越自身权限的行为, 如果该用户被攻击, 则系统会遭受更大的损失。例如, ABB VSN300 WiFi Logger Card中没有正 确限制不同客户的权限, 致使攻击者可以访问到关键信息(CVE-2017-7916);Dasan H660RM 设备上的 BOA 服务器配置将敏感数据放在了错误的位置, 低权限的用户可以随意对这些文件进行查看(CVE-2019-9976)。
2.3 定制缺陷
定制缺陷是指用户根据自己和环境需要对固件进行一定的修改, 但是这种修改使固件产生了不可预期的错误。这一错误的发生可能是由于用户对固件源码的不熟悉、固件对不同环境的适配性不好等, 定制缺陷可造成实现缺陷和配置缺陷, 这一缺陷的检测无需对整个固件进行测试, 可以将测试重点放在被修改及相关部分。
虽然固件中的缺陷分为不同的种类, 但是这些缺陷之间通常会有一定的依赖关系, 一种缺陷的发生有可能会导致其他缺陷的发生。实现缺陷可以视为最基本的缺陷, 其来源有多种, 但主要来源还是开发人员在编写过程中的粗心大意; 配置缺陷主要由部署人员引入, 配置值的本质就是程序中的变量, 变量的输入来自于配置编写人员, 如果配置值编写不当, 而代码中没有对配置值进行检查, 也会引出实现缺陷; 定制缺陷由用户自己引入, 用户在定制过程中可能会对配置或者代码进行一定的修改, 因此定制缺陷会造成实现缺陷和配置缺陷。
原文始发于微信公众号(华克斯):物联网固件安全缺陷检测研究
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论