AUTOSAR是一个普遍采用的软件框架,用于各种汽车零部件,如ABS, ECU,自动照明、环境控制、充电控制器、信息娱乐系统等。AUTOSAR的创建目的是促进汽车零部件之间形成标准接口,可以在不同制造商之间互通。
因此,任何配备微控制器(MCU)的汽车零部件都应符合AUTOSAR的规定。
AUTOSAR标准不仅管理用于模块间通信的数据格式,还规定了这些模块的标准API。在汽车行业内使用的AUTOSAR平台有两个版本:Classic和Adaptive。
Adaptive平台是为高性能设备量身定制的,例如信息娱乐系统或高级驾驶辅助系统(ADAS),这些设备通常在Linux或QNX等资源丰富的操作系统上运行。另一方面,Classic平台部署于运行在微控制器单元裸板(MCU)上的低性能设备中,包括ABS, EBD, 安全气囊控制单元、车身控制模块、传输控制模块等系统。
虽然AUTOSAR是一个稳健而可靠的开发框架,但它并非没有潜在的错误和漏洞。在对AUTOSAR文件进行内部分析时,我们偶然发现了一个特别有趣的漏洞,这个漏洞可能会带来很大的安全风险。代码中的缺陷并不是由于AUTOSAR本身造成的,而是对AUTOSAR使用不当的结果。
在本文中,我们打算深入研究和剖析这个具体的案例。
AUTOSAR Classic固件开发
在大多数情况下,固件是利用两家领先的AUTOSAR软件提供商(Vector和Elektrobit)提供的工具链开发的。
Vector和Elektrobit都提供了配置工具和SDK,其中包括标准AUTOSAR模块的预构建实现,如MicroSAR OS运行时、CAN接口、NVM API、诊断模块、加密和内存接口等。这种被称为基本软件(Basic Software,简称BSW)的SDK是以中间件方式执行,因此不能在目标硬件上独立运行。
除了BSW之外,还有一套被称为微控制器抽象层(Microcontroller Abstraction Layer,简称MCAL)的驱动程序和库,用于对硬件的访问。每个打算将其MCU用于汽车行业的硬件制造商都提供了适用于其MCU的AUTOSAR MCAL。例如,有来自博世、恩智浦、瑞萨和英飞凌的MCAL。MCAL驱动程序和库也需要遵循AUTOSAR标准,以确保BSW可以与任何硬件制造商的MCAL一起使用。
新固件的开发通常从配置工具开始。在这里,开发人员构建要使用的硬件平台,为他们的项目选择所需的MCAL和BSW模块,然后在所有模块之间建立连接。例如,开发人员可以指定BSW中的CanIf模块应该使用哪个MCAL的CAN接口。一旦配置阶段完成,配置工具就会生成源代码,这些源代码本质上是MCAL和BSW的一个子集。
生成源代码之后,可以使用任何编译器或集成开发环境(IDE)对其进行编译,然后再将其安装到目标设备上。由配置工具输出的源代码已经包含了设备以默认行为操作所必需的一切。因此,开发人员可能不需要对所生成的代码进行任何修改。在BSW层之上的任何自定义代码往往都是最小化了的,通常占固件总大小的10%以下。
基于AUTOSAR的固件漏洞
在我们进行红队渗透测试的过程中,我们获得了基于AUTOSAR的固件进行安全评估。从攻击者和渗透测试者的角度来看,基于AUTOSAR的文件的潜在攻击点非常有限。该模块的源代码非常可靠,始终经过代码审查和漏洞分析。
关于常规漏洞和通用缺陷枚举(CWE),发现它们的可能性相当小。没有动态内存分配,所有变量要么是全局的,要么是堆栈上的,从而消除了发现double-free或use-after-free等漏洞的机会。汽车代码不执行字符串操作,而只关注二进制解析。因此,通过sprintf, sscanf, strcpy等操作遇到堆栈溢出的可能性在这里是不存在的。
当涉及到潜在的竞态条件漏洞时,AUTOSAR Classic不允许动态任务初始化或动态创建的同步原语。任务和同步事件列表是在配置阶段预先确定的。因此,考虑到静态的、预先配置的任务资源和事件集,自动生成的代码不太可能包含死锁或竞态条件。
因此,我们必须深入研究AUTOSAR框架,了解它的用法和对API的潜在使用不当,特别关注用户如何以可能导致漏洞的方式调用它。
我们在NvM模块中遇到了一组函数:NvM_ReadBlock, NvM_WriteBlock和NvM_RestoreBlockDefaults,这组函数通常用于在NVM中加载和存储设备设置(如EEPROM, NAND, NOR内存等)。
通过对NVRAM管理器规范中的函数原型进行研究:
很明显,这些函数缺少缓冲区大小检查,仅使用块ID来确定在配置阶段配置的特殊块表中的数据大小。换句话说,用户有责任包含在写入时验证保存在NvM块中的数据大小是否合适的代码。同样,当从NvM块中读取数据时,用户有责任提供足够大的缓冲区,因为NvM_ReadBlock只是根据NvM块的大小简单地覆盖缓冲区。
因此,这样的API调用可能会导致越界(Out of Bounds, 简称OOB)读取或写入。根据作为NvM_DstPtr/NvM_SrcPtr传递的缓冲区类型,可能会出现各种问题:
- 如果用户提供了一个小的堆栈变量,但读取了一个大的NvM块,NvM_ReadBlock将在堆栈变量之外写入数据,这会导致堆栈损坏,并可能为远程代码执行(Remote Code Execution,简称RCE)打开大门。
- 如果提供的变量是全局变量,NvM_ReadBlock将覆盖邻近的全局变量。这可能会导致代码中出现未定义的行为。
- 如果用户为NvM_WriteBlock提供了一个小的堆栈或全局变量,将导致NvM_WriteBlock读取变量外的数据,并将随机数据存储到NVM中。
利用这种方法,我们发现了一个有趣的由于AUTOSAR API使用不当导致缓冲区溢出漏洞的案例。
发现基于AUTOSAR的漏洞
让我们看一下我们遇到的漏洞的简化版本:
NvM_ReadBlock将从NVM读取0x110字节,然后将其写入myVar的位置。虽然NvM_ReadBlock会准确地写入myVar的值,但之后它仍将继续用不可预测的值覆盖邻近的全局变量。
在我们发现的案例中,NvM_ReadBlock被设置为在堆栈上执行越界写入操作,这可能会覆盖函数的返回地址。
在这个具体案例中,对易受攻击函数的调用被MCU复杂的自定义工作流程所掩盖。然而,它仍然是可触发的,并且确实导致了执行崩溃。
缓解威胁
代码生成之后,管理源代码中与NvM API一起使用的变量大小就完全是开发人员的责任了。因此,AUTOSAR开发人员应当尽一切努力在配置器中对齐变量和NVM块的大小。AUTOSAR开发人员还应当避免修改生成的代码,除非他们完全理解有关NVM块大小的约束。
此外,没有NVM函数可以提供NVM块的大小来执行如下检查:assert(sizeof(myVar) == NvM_BlockSize(Block_ID));这是因为块大小被硬编码到NvM模块配置中,并被视为内部数据。
即使在使用AUTOSAR这样的标准化框架时,在某些情况下,也可能无意中引入重大的内存漏洞。为了减少这种情况,强烈建议采用持续的质量保证措施和定期的渗透测试。
总结
虽然AUTOSAR为汽车软件开发提供了一个稳健而标准的框架,但由于使用不当,特别是在NvM API的变量管理中,仍然可能出现潜在的漏洞。随着汽车技术越来越复杂,有必要通过持续的质量保证和定期的渗透测试来加强软件安全性。这些实践,加上对正在使用的框架的深刻理解,可以帮助开发人员降低潜在的安全风险,并提高汽车系统的整体安全性。
“原创内容,转载请标明出处”