Multiple vulnerabilities have been discovered in the Mazda Connect Connectivity Master Unit (CMU) system installed in multiple car models, such as the Mazda 3 model year 2014-2021. Like in so many cases, these vulnerabilities are caused by insufficient sanitization when handling attacker-supplied input. A physically present attacker could exploit these vulnerabilities by connecting a specially crafted USB device – such as an iPod or mass storage device – to the target system. Successful exploitation of some of these vulnerabilities results in arbitrary code execution with root privileges.
在安装在多款车型(例如 2014-2021 年款 Mazda 3)中的 Mazda Connect 连接主站 (CMU) 系统中发现了多个漏洞。与许多情况一样,这些漏洞是由于在处理攻击者提供的输入时清理不充分造成的。实际存在的攻击者可以通过将特制的 USB 设备(如 iPod 或大容量存储设备)连接到目标系统来利用这些漏洞。成功利用其中一些漏洞会导致以 root 权限执行任意代码。
The Target 目标
The specific CMU unit that was the target of the research was manufactured by Visteon, while the software was initially developed by Johnson Controls Inc (JCI). The research was performed against the latest available software version (74.00.324A). Earlier software versions down to at least 70.x may also be affected by these vulnerabilities.
作为研究目标的特定 CMU 单元由伟世通制造,而软件最初由江森自控公司 (JCI) 开发。该研究是针对最新的可用软件版本 (74.00.324A) 进行的。低至 70.x 的早期软件版本也可能受到这些漏洞的影响。
Notably, the CMU has a very active “modding scene” with the community releasing multiple software “tweaks” to alter the operation of the unit. The installation of these tweaks typically relied on software vulnerabilities. At the time of publication, we are unaware of any publicly known vulnerabilities in the latest firmware version.
值得注意的是,CMU 有一个非常活跃的“改装场景”,社区发布了多个软件“调整”来改变该装置的运行。这些调整的安装通常依赖于软件漏洞。在发布时,我们尚未发现最新固件版本中有任何公开已知的漏洞。
Hardware Design 硬件设计
The unit exterior looks like this:
单元外观如下所示:
There is a sticker on the bottom with some technical information about the unit. The sticker notes the specific CMU model being MAZDA_GEN_65_CMU
.
底部有一个贴纸,上面有一些关于该装置的技术信息。贴纸上注明了正在MAZDA_GEN_65_CMU
的特定 CMU 型号。
On the back, the unit provides multiple connectors that carry power, audio input/output, USB and CAN signals, and a serial console.
在背面,该装置提供多个连接器,用于传输电源、音频输入/输出、USB 和 CAN 信号以及串行控制台。
Inside, the unit is built on a single PCB which carries an application SoC (Freescale part number SCIMX06DAVT10AC), an assortment of memory ICs (a serial Flash on the back of the board, a NAND Flash, and an eMMC), an auxiliary MCU (Renesas part number R5F35MCEJFF), and a Bluetooth module (Murata part number LBEE6Z2U0C-584).
在内部,该单元构建在单个 PCB 上,该 PCB 带有一个应用 SoC(飞思卡尔零件编号 SCIMX06DAVT10AC)、各种存储器 IC(电路板背面的串行闪存、NAND 闪存和 eMMC)、一个辅助 MCU(瑞萨电子零件编号 R5F35MCEJFF)和一个蓝牙模块(村田零件编号 LBEE6Z2U0C-584)。
The functionality available on the edge connectors was not explored in this research.
本研究未探讨边缘连接器上可用的功能。
Typically, in designs where there is more than one processing unit present, some degree of separation is implemented. User-facing applications handled by a rich OS (i.e., QNX, Linux, Android, etc.) run on the application SoC, while CAN connectivity is handled by an MCU usually running an RTOS. This appears to be the case for this unit as well.
通常,在存在多个 processing unit 的设计中,会实现一定程度的分离。面向用户的应用程序由丰富的操作系统(即 QNX、Linux、Android 等)在应用程序 SoC 上运行,而 CAN 连接由通常运行 RTOS 的 MCU 处理。这个单位似乎也是这种情况。
Software design 软件设计
On the software side of things, the unit’s main SoC is running a Linux-based OS image, as evidenced by the following output (abbreviated here) captured via the serial console:
在软件方面,该单元的主 SoC 正在运行基于 Linux 的操作系统映像,通过串行控制台捕获的以下输出(此处缩写)证明了这一点:
IBC embedded bootloader 1.68.21 | |
(c) 2012 XS Embedded GmbH | |
Uncompressing Linux… done, booting the kernel. | |
00:00:01.226 LVDS[61] contrast : 54 -> 54 | |
00:00:01.227 LVDS[61] (Defaulting) Speed Restriction: Enabled | |
00:00:01.227 LVDS[61] (Defaulting) Visteon Display. | |
… | |
00:00:01.428 LVDS[61] ChangeBrightness_Id: | |
00:00:01.433 LVDS[61] brightness : 5000 -> 5000 | |
00:00:01.433 LVDS[61] BrightNessLevel = 5000. | |
FGSN: VPGJ3Fxxxxxxxxyy | |
cmu login: |
While there is a login prompt, authentication credentials for the latest software version are not publicly known. The console proceeds to serve a vast amount of logging output, which could be useful for testing exploits.
虽然存在登录提示,但最新软件版本的身份验证凭证并不公开。控制台继续提供大量的日志记录输出,这可能对测试漏洞很有用。
When fully booted, the system has the following file systems mounted:
完全引导后,系统挂载了以下文件系统:
rootfs on / type rootfs (rw) | |
none on /sys type sysfs (rw,relatime) | |
none on /proc type proc (rw,relatime) | |
none on /dev type devtmpfs (rw,relatime,size=8192k,nr_inodes=95316,mode=755) | |
/dev/ffx01p1 on / type relfs (ro,noatime) | |
none on /sys type sysfs (rw,relatime) | |
none on /proc type proc (rw,relatime) | |
none on /dev type devtmpfs (rw,relatime,size=8192k,nr_inodes=95316,mode=755) | |
none on /tmp type tmpfs (rw,relatime,size=95232k) | |
/dev/ffx01p4 on /tmp/mnt/data type relfs (rw,noatime) | |
/dev/mmcblk0p2 on /tmp/mnt/data_persist type relfs (rw,noatime) | |
/dev/mtdblock5 on /config-mfg type squashfs (ro,relatime) | |
none on /dev/pts type devpts (rw,relatime,mode=600) | |
none on /dev/mqueue type mqueue (rw,relatime) | |
none on /tmp/mnt/tmp/race/database type tmpfs (rw,relatime,size=30720k) | |
/dev/mmcblk0p1 on /tmp/mnt/resources type relfs (ro,noatime) |
All the persistent memory storage is accessible from the OS. The serial Flash is present as the mtdblock
partitions, the NAND is present as the ffx01
partitions, and the eMMC as the mmcblk
partitions. Notably, several file systems are mounted read-write as signified by the rw
string included in parentheses.
所有持久内存存储都可以从操作系统访问。串行闪存作为 mtdblock
分区存在,NAND 作为 ffx01
分区存在,eMMC 作为 mmcblk
分区存在。值得注意的是,多个文件系统是读写挂载的,如括号中的 rw
字符串所示。
The Software Update Process
软件更新过程
The software on the unit can be updated from the diagnostic menu:
可以从诊断菜单更新设备上的软件:
The update process expects a file with the .up
extension to be located on a mass storage device connected via USB. The dealer could then enter this diagnostic menu and start the update process.
更新过程需要扩展名为 .up
的文件位于通过 USB 连接的大容量存储设备上。然后,经销商可以进入此诊断菜单并开始更新过程。
Software update files are password-protected ZIP archives containing multiple directories for various steps in the update process, as well as an “instruction” file describing how to perform the update. There are 21 steps in the latest update file. Of special interest is the contents of the following directories:
软件更新文件是受密码保护的 ZIP 存档文件,其中包含用于更新过程中各个步骤的多个目录,以及描述如何执行更新的“说明”文件。最新更新文件包含 21 个步骤。特别值得关注的是以下目录的内容:
• rootfs1upd
containing a .tar.gz
archive of the entire root file system,
• rootfs1upd
包含整个根文件系统的 .tar.gz
存档,
• linux1
containing the Linux kernel 3.0.35,
• linux1
包含 Linux 内核 3.0.35,
• ibc1
and ibc2
containing a bootloader,
• 包含引导加载程序的 ibc1
和 ibc2
,
• bootstrap
containing yet another bootloader,
• 包含
另一个引导加载程序的 bootstrap,
• passwdupdate
containing the replacement passwd
file,
• passwdupdate
包含替换 passwd
文件,
• vip
containing the update image for the auxiliary MCU.
• vip
包含辅助 MCU 的更新映像。
The majority of the update process is implemented in several shared objects. All business logic is located in svcjciupdatea.so
and svcjciupdates.so
, which use supporting code in libjcireflashua.so
and libjcisecurity.so
. The update process was investigated only up to the point of signature verification. Further investigation would assume the ability to produce either properly signed updates or a signature verification bypass. Unfortunately, the former was not available at the time of this research, and the latter was not discovered during this effort.
大部分更新过程都是在多个共享目标文件中实现的。所有业务逻辑都位于 svcjciupdatea.so
和 svcjciupdates.so
中,它们使用 libjcireflashua.so
和 libjcisecurity.so
中的支持代码。更新过程仅在签名验证之前进行调查。进一步的调查将假设能够生成正确签名的更新或绕过签名验证。不幸的是,前者在这项研究时不可用,后者在这项研究中也没有被发现。
On a high level, the update verification process is contained in the svcjciupdates.so:updates_sys_srv_ValidatePackageOperationThread()
function, which calls other functions to perform verification steps in the given order:
概括地说,更新验证过程包含在 svcjciupdates.so:updates_sys_srv_ValidatePackageOperationThread()
函数中,该函数调用其他函数以按给定顺序执行验证步骤:
• updates_sys_srv_LoadUP()
parses the specified update file, extracts the main_instructions.ini
and versions.ini
files, and stores them in memory for later use.
• updates_sys_srv_LoadUP()
解析指定的更新文件,提取 main_instructions.ini
和 versions.ini
文件,并将其存储在内存中以供以后使用。
• updates_sys_srv_ValidateUPStructure()
validates whether the internal structure of the update file matches the expected layout. This was not an issue when the format of proper update files was followed to create an exploit.
• updates_sys_srv_ValidateUPStructure()
验证更新文件的内部结构是否与预期布局匹配。当遵循正确的更新文件格式来创建漏洞时,这不是问题。
• updates_sys_srv_ExtractCertificates()
extracts the signing certificate chain from the update file to be used for update verification. The chain contains the publisher certificate used to sign the update and an intermediate CA certificate that issued the publisher certificate. The intermediate CA certificate is issued by the JCI root CA.
• updates_sys_srv_ExtractCertificates()
从更新文件中提取签名证书链以用于更新验证。该链包含用于对更新进行签名的发布者证书和颁发发布者证书的中间 CA 证书。中间 CA 证书由 JCI 根 CA 颁发。
• updates_sys_sec_VerifyUPCertificates()
verifies the extracted certificate chain to ensure the chain properly terminates in the expected root CA stored on the device.
• updates_sys_sec_VerifyUPCertificates()
验证提取的证书链,以确保该链正确终止于设备上存储的预期根 CA。
• updates_sys_sec_VerifyUPSignature()
verifies the signature of a specified update file against the publisher certificate. The signature in this case is located at the end of the update file and is 256 bytes long.
• updates_sys_sec_VerifyUPSignature()
根据发布者证书验证指定更新文件的签名。在本例中,签名位于更新文件的末尾,长度为 256 字节。
• updates_sys_srv_RemoveExtractedCertificates()
cleans up after the verification process.
• updates_sys_srv_RemoveExtractedCertificates()
验证过程后进行清理。
Of particular note is the fact that multiple operations are performed on the supplied update file by the updates_sys_srv_LoadUP()
function and its callees before any integrity checks occur against the user-supplied file.
特别值得注意的是,在对用户提供的文件进行任何完整性检查之前,updates_sys_srv_LoadUP()
函数及其被调用方会对提供的更新文件执行多个操作。
The Vulnerabilities 漏洞
Multiple vulnerabilities were discovered during our research effort, which can be used in conjunction to achieve a complete and persistent compromise of the infotainment system.
在我们的研究工作中发现了多个漏洞,这些漏洞可以结合使用,以实现对信息娱乐系统的全面和持续入侵。
CVE-2024-8355/ZDI-24-1208: DeviceManager iAP Serial Number SQL Injection
CVE-2024-8355/ZDI-24-1208:DeviceManager iAP 序列号 SQL 注入
This vulnerability was the first bug discovered during research, spurring a deeper look into this unit.
这个漏洞是研究过程中发现的第一个错误,促使人们更深入地了解这个单元。
The specific vulnerability exists in the eInsertDeviceEntry()
function of the /jci/devicemanager/libdevicemanager.so
library. When attempting to insert a new Apple device into the DeviceDatabase.db
SQLite database, several values are taken from the device and used in an SQL statement without sanitization. See the following pseudocode implementation of the eInsertDeviceEntry()
function:
具体漏洞存在于 /jci/devicemanager/libdevicemanager.so
该库的 eInsertDeviceEntry()
函数中。尝试将新的 Apple 设备插入 DeviceDatabase.db
SQLite 数据库时,将从设备中获取多个值并在 SQL 语句中使用,而无需进行清理。请参阅以下 eInsertDeviceEntry()
函数的伪代码实现:
int eInsertDeviceEntry(undefined4 param_1,int param_2) | |
{ | |
int iVar1; | |
undefined auStack1052 [1024]; | |
int local_1c; | |
local_1c = 0; | |
sqlite3_snprintf(0x400,auStack1052, | |
“INSERT INTO DeviceInfo (USBSERIAL,MACADDRESS, IAPSERIAL, UIDVALID) VALUES(\’%s\’,%Q,\’%s\’,%d)” | |
,param_2,param_2 + 100,param_2 + 200,*(undefined4 *)(param_2 + 300)); | |
race_print_log(4,0x11,“eInsertDeviceEntry”,0x4c0,“DEVMGR_DATABASE”,“Query is : %s\n”,auStack1052); | |
iVar1 = sqlite3_exec(param_1,auStack1052,0,0,&local_1c); | |
if (iVar1 != 0) { | |
race_print_log(1,0x11,“eInsertDeviceEntry”,0x4c5,“DEVMGR_DATABASE”,“SQL error: %s %d\n”,local_1c | |
,iVar1); | |
if (local_1c != 0) { | |
sqlite3_free(); | |
} | |
} | |
if (iVar1 != 0) { | |
iVar1 = 1; | |
} | |
return iVar1; | |
} |
Because of this, when the infotainment system detects an Apple device has been connected and requests, for example, its iAP serial number, a spoofed iPod or other Apple device can instead reply with a string along the lines of:
因此,当信息娱乐系统检测到已连接 Apple 设备并请求(例如)其 iAP 序列号时,欺骗性的 iPod 或其他 Apple 设备可以改为使用以下字符串进行回复:
‘ , 0); [ANY SQL STATEMENT];– |
This leads to the DeviceManager executing the injected SQL statement on the infotainment system with root privileges. This could be used to manipulate the database itself, disclose information, create arbitrary files on the file system, and possibly execute code. Exploitation of this vulnerability is somewhat limited due to an apparent length limitation of 0x36 bytes on the input, but this could potentially be worked around by having several spoofed iPods connect one after the other, each with its own injected SQL statements in place of a serial number.
这会导致 DeviceManager 以 root 权限在信息娱乐系统上执行注入的 SQL 语句。这可用于操纵数据库本身、泄露信息、在文件系统上创建任意文件以及可能执行代码。由于输入上 0x36 字节的明显长度限制,因此此漏洞的利用在一定程度上受到限制,但可以通过让多个欺骗性 iPod 一个接一个地连接来解决,每个 iPod 都使用自己的注入 SQL 语句代替序列号。
CVE-2024-8359/ZDI-24-1191: REFLASH_DDU_FindFile Command Injection RCE
CVE-2024-8359/ZDI-24-1191:REFLASH_DDU_FindFile命令注入 RCE
One of the multitude of functions supporting the update process is the REFLASH_DDU_FindFile()
function found in the libjcireflashua.so
shared object. The pseudocode for this function is reproduced below for clarity:
支持更新过程的众多函数之一是 libjcireflashua.so
共享目标文件中的 REFLASH_DDU_FindFile()
函数。为清楚起见,此函数的伪代码复制如下:
undefined4 REFLASH_DDU_FindFile(char *_up_path,char *_file_name,int _is_gzipped) | |
{ | |
int iVar1; | |
undefined4 uVar2; | |
char acStack_408 [1023]; | |
undefined local_9; | |
memset(acStack_408,0,0x400); | |
if ((_up_path == (char *)0x0) || (_file_name == (char *)0x0)) { | |
REFLASH_UL_WriteLog(“Core Reflash”,0,0,“reflash_ddu.c”,“REFLASH_DDU_FindFile”,0x181, | |
“Some of the input parameters are wrong!”); | |
uVar2 = 0xffffd8f0; | |
} | |
else { | |
if (_is_gzipped == 1) { | |
if (reflash_ddu_password == 0) { | |
snprintf(acStack_408,0x400,“%s \”%s\” \”%s.gz\” > /dev/null”,“unzip -t”,_up_path,_file_name) | |
; | |
} | |
else { | |
snprintf(acStack_408,0x400,“%s %s \”%s\” \”%s.gz\” > /dev/null”,“unzip -t -P”, | |
reflash_ddu_password,_up_path,_file_name); | |
} | |
} | |
else if (reflash_ddu_password == 0) { | |
snprintf(acStack_408,0x400,“%s \”%s\” \”%s\” > /dev/null”,“unzip -t”,_up_path,_file_name); | |
} | |
else { | |
snprintf(acStack_408,0x400,“%s %s \”%s\” \”%s\” > /dev/null”,“unzip -t -P”, | |
reflash_ddu_password,_up_path,_file_name); | |
} | |
local_9 = 0; | |
iVar1 = system(acStack_408); | |
if (iVar1 == 0) { | |
uVar2 = 0; | |
} | |
else { | |
uVar2 = 0xffffd8fb; | |
} | |
} | |
return uVar2; | |
} |
The function attempts to find a specific file within the update package specified via the provided file path. This is performed by interpolating the provided path into a command line for the unzip
program. Unfortunately, no sanitization is performed before that occurs, and attacker-controlled input (e.g., /dev/sda1/path/file.up
) is passed to the system()
function. This allows the attacker to inject arbitrary OS commands that will be executed by the head unit OS shell, allowing for a full compromise of the system. The attacker can control both the path
and file
elements of the overall path.
该函数尝试在通过提供的文件路径指定的更新包中查找特定文件。这是通过将提供的路径插入到 unzip
程序的命令行中来执行的。遗憾的是,在此之前没有执行清理,攻击者控制的输入(例如,/dev/sda1/path/file.up
)被传递给 system()
函数。这允许攻击者注入任意 OS 命令,这些命令将由主机 OS shell 执行,从而允许完全破坏系统。攻击者可以控制整个路径的 path
和 file
元素。
The affected function can be reached via the following call graph:
可以通过以下调用图访问受影响的函数:
• UPDATES_SYS_IPC_INTERFACE_GetPackageInfo_svc in svcjciupdates.so
• svcjciupdates.so UPDATES_SYS_IPC_INTERFACE_GetPackageInfo_svc
• UPDATES_SYS_SRV_GetPackageInfo
• UPDATES_SYS_SRV_GetPackageInfo
• updates_sys_srv_GetPackageInfoOperationThread
• updates_sys_srv_GetPackageInfoOperationThread
• updates_sys_srv_LoadUP • updates_sys_srv_LoadUP
• REFLASH_UA_LoadUP in libjcireflashua.so
• libjcireflashua.so REFLASH_UA_LoadUP
• REFLASH_DDU_FindFile • REFLASH_DDU_FindFile
CVE-2024-8360/ZDI-24-1192: REFLASH_DDU_ExtractFile Command Injection RCE
CVE-2024-8360/ZDI-24-1192:REFLASH_DDU_ExtractFile命令注入 RCE
One of the multitude of functions supporting the update process is the REFLASH_DDU_ExtractFile()
function found in the libjcireflashua.so
shared object. The pseudocode for this function is reproduced below for clarity:
支持更新过程的众多函数之一是 libjcireflashua.so
共享目标文件中的 REFLASH_DDU_ExtractFile()
函数。为清楚起见,此函数的伪代码复制如下:
undefined4 REFLASH_DDU_ExtractFile(char *_up_path,char *_file_name,char *_dest_path,int _is_gzipped) | |
{ | |
undefined4 uVar1; | |
char acStack_808 [1023]; | |
undefined local_409; | |
char acStack_408 [1023]; | |
undefined local_9; | |
memset(acStack_408,0,0x400); | |
memset(acStack_808,0,0x400); | |
if (((_up_path == (char *)0x0) || (_file_name == (char *)0x0)) || (_dest_path == (char *)0x0)) { | |
REFLASH_UL_WriteLog(“Core Reflash”,0,0,“reflash_ddu.c”,“REFLASH_DDU_ExtractFile”,0xd4, | |
“Some of the input parameters are wrong!”); | |
uVar1 = 0xffffd8f0; | |
} | |
else { | |
if (_is_gzipped == 1) { | |
if (reflash_ddu_password == 0) { | |
snprintf(acStack_408,0x400,“%s \”%s\” \”%s.gz\” | %s > \”%s\””,“unzip -p”,_up_path, | |
_file_name,“gzip -d -c”,_dest_path); | |
} | |
else { | |
snprintf(acStack_408,0x400,“%s %s \”%s\” \”%s.gz\” | %s > \”%s\””,“unzip -p -P”, | |
reflash_ddu_password,_up_path,_file_name,“gzip -d -c”,_dest_path); | |
snprintf(acStack_808,0x400,“%s %s \”%s\” \”%s.gz\” | %s > \”%s\””,“unzip -p -P”,“<***>”, | |
_up_path,_file_name,“gzip -d -c”,_dest_path); | |
} | |
} | |
else if (reflash_ddu_password == 0) { | |
snprintf(acStack_408,0x400,“%s \”%s\” \”%s\” > \”%s\””,“unzip -p”,_up_path,_file_name, | |
_dest_path); | |
} | |
else { | |
snprintf(acStack_408,0x400,“%s %s \”%s\” \”%s\” > \”%s\””,“unzip -p -P”,reflash_ddu_password, | |
_up_path,_file_name,_dest_path); | |
snprintf(acStack_808,0x400,“%s %s \”%s\” \”%s\” > \”%s\””,“unzip -p -P”,“<***>”,_up_path, | |
_file_name,_dest_path); | |
} | |
local_9 = 0; | |
if (reflash_ddu_password == 0) { | |
uVar1 = REFLASH_ExecuteCommand(acStack_408,0); | |
} | |
else { | |
local_409 = 0; | |
uVar1 = REFLASH_ExecuteCommand(acStack_408,acStack_808); | |
} | |
} | |
return uVar1; | |
} |
The function attempts to extract a specific file from the update package specified by the path supplied through the up_path
argument. This interpolates the provided path into a command line for the unzip
program. Unfortunately, no sanitization is performed before that occurs, and attacker-controlled input (e.g., /dev/sda1/path/file.up
) is passed to the system()
function. The attacker can control both path
and file
elements of the overall path. This allows the attacker to inject arbitrary OS commands that will be executed by the head unit OS shell, allowing for a full compromise of the system.
该函数尝试从更新包中提取特定文件,该更新包由通过 up_path
参数提供的路径指定。这会将提供的路径插入到 unzip
程序的命令行中。遗憾的是,在此之前没有执行清理,攻击者控制的输入(例如,/dev/sda1/path/file.up
)被传递给 system()
函数。攻击者可以控制整个路径的 path
和 file
元素。这允许攻击者注入任意 OS 命令,这些命令将由主机 OS shell 执行,从而允许完全破坏系统。
The affected function can be reached via the following call graph:
可以通过以下调用图访问受影响的函数:
• UPDATES_SYS_IPC_INTERFACE_GetPackageInfo_svc in svcjciupdates.so
• svcjciupdates.so UPDATES_SYS_IPC_INTERFACE_GetPackageInfo_svc
• UPDATES_SYS_SRV_GetPackageInfo
• UPDATES_SYS_SRV_GetPackageInfo
• updates_sys_srv_GetPackageInfoOperationThread
• updates_sys_srv_GetPackageInfoOperationThread
• updates_sys_srv_LoadUP • updates_sys_srv_LoadUP
• REFLASH_UA_LoadUP in libjcireflashua.so
• libjcireflashua.so REFLASH_UA_LoadUP
• REFLASH_DDU_ExtractFile
• REFLASH_DDU_ExtractFile
CVE-2024-8358/ZDI-24-1190: UPDATES_ExtractFile Command Injection RCE
CVE-2024-8358/ZDI-24-1190:UPDATES_ExtractFile 命令注入 RCE
One of the various functions supporting the update process is the UPDATES_ExtractFile()
function found in the svcjciupdates.so
shared object. The pseudocode for this function is partially reproduced below for clarity:
支持更新过程的各种函数之一是 svcjciupdates.so
共享目标文件中的 UPDATES_ExtractFile()
函数。为清楚起见,此函数的伪代码部分复制如下:
int UPDATES_ExtractFile(char *up_path,char *file_path,char *destFile,int gzipped,char *password) | |
{ | |
int iVar1; | |
size_t sVar2; | |
size_t sVar3; | |
int iVar4; | |
char *pcVar5; | |
char *local_2060 [4]; | |
int gzipped$1; | |
char *destFile$1; | |
char *file_path$1; | |
char *up_path$1; | |
char acStack_203c [4100]; | |
char *pcStack_1038; | |
char cmd [4100]; | |
char *local_30; | |
int local_2c; | |
size_t local_28; | |
int local_24; | |
local_24 = 100; | |
gzipped$1 = gzipped; | |
destFile$1 = destFile; | |
file_path$1 = file_path; | |
up_path$1 = up_path; | |
// … | |
if (local_24 == 100) { | |
snprintf(acStack_203c,0x1001,“%s”,“unzip -p”); | |
} | |
if ((local_24 == 100) && (password != (char *)0x0)) { | |
// append the unzip option and the password itself | |
} | |
if (local_24 == 100) { | |
if (gzipped$1 == 1) { | |
local_2060[0] = up_path$1; | |
local_2060[1] = file_path$1; | |
local_2060[2] = “gzip -d -c”; | |
local_2060[3] = destFile$1; | |
snprintf(cmd,0x1001,“%s \”%s\” \”%s.gz\” | %s > \”%s\””,acStack_203c); | |
} | |
else { | |
local_2060[0] = up_path$1; | |
local_2060[1] = file_path$1; | |
local_2060[2] = destFile$1; | |
snprintf(cmd,0x1001,“%s \”%s\” \”%s\” > \”%s\””,acStack_203c); | |
} | |
local_24 = UPDATES_ExecuteCommand(cmd,&pcStack_1038); | |
// … |
The function attempts to extract a specific file from the update package specified by the path supplied through the up_path
argument. This interpolates the provided path into a command line for the unzip
program. As with the other bugs, no sanitization is performed before that occurs, and attacker-controlled input (e.g., /dev/sda1/path/file.up
) is passed to the system()
function. The attacker can control both path
and file
elements of the overall path. This allows the attacker to inject arbitrary OS commands that will be executed by the head unit OS shell, allowing for a full compromise of the system.
该函数尝试从更新包中提取特定文件,该更新包由通过 up_path
参数提供的路径指定。这会将提供的路径插入到 unzip
程序的命令行中。与其他错误一样,在此之前不会执行清理,攻击者控制的输入(例如 /dev/sda1/path/file.up
)会传递给 system()
函数。攻击者可以控制整个路径的 path
和 file
元素。这允许攻击者注入任意 OS 命令,这些命令将由主机 OS shell 执行,从而允许完全破坏系统。
The affected function can be reached via the following call graph:
可以通过以下调用图访问受影响的函数:
• UPDATES_SYS_IPC_INTERFACE_GetPackageInfo_svc in svcjciupdates.so
• svcjciupdates.so UPDATES_SYS_IPC_INTERFACE_GetPackageInfo_svc
• UPDATES_SYS_SRV_GetPackageInfo
• UPDATES_SYS_SRV_GetPackageInfo
• updates_sys_srv_GetPackageInfoOperationThread
• updates_sys_srv_GetPackageInfoOperationThread
• updates_sys_srv_LoadUP • updates_sys_srv_LoadUP
• updates_sys_srv_ExtractCertificates
• updates_sys_srv_ExtractCertificates
• updates_sys_srv_ExtractPubCert
• updates_sys_srv_ExtractPubCert
• UPDATES_ExtractFile(“publisher_cert.pem”, “/tmp/reflash/publisher_cert.pem”)
• UPDATES_ExtractFile(“publisher_cert.pem”, “/tmp/reflash/publisher_cert.pem”)
CVE-2024-8357/ZDI-24-1189: App SoC Missing Root of Trust in Hardware
CVE-2024-8357/ZDI-24-1189:App SoC 在硬件中缺少信任根
As previously mentioned, the head unit is partitioned into two relatively independent systems: the application SoC running Linux and the VIP MCU running an unspecified OS. The application SoC uses an onboard SPI Flash chip to boot. The chip is partitioned as follows:
如前所述,车机被划分为两个相对独立的系统:运行 Linux 的应用程序 SoC 和运行未指定操作系统的 VIP MCU。应用程序 SoC 使用板载 SPI Flash 芯片启动。芯片的分区如下:
/tmp/root # cat /proc/mtd | |
dev: size erasesize name | |
mtd0: 00010000 00010000 “bootstrap” | |
mtd1: 00010000 00010000 “boot-select” | |
mtd2: 00020000 00010000 “ibc1” | |
mtd3: 00020000 00010000 “ibc2” | |
mtd4: 00010000 00010000 “nv-config” | |
mtd5: 00060000 00010000 “config” | |
mtd6: 00010000 00010000 “jci-boot-diag” | |
mtd7: 00700000 00010000 “fail-safe” | |
mtd8: 00020000 00010000 “update” |
Here, the mtd0 partition stores the bootstrap code, which appears to be the first piece of code to be executed on the system. The application SoC was found to be missing any authentication of this bootstrap code. Additionally, none of the subsequent OS boot steps perform any authentication of the next boot stage before passing control to it. This results in the following opportunities for an attacker who has gained code execution on the Linux system:
在这里,mtd0 分区存储引导代码,它似乎是在系统上执行的第一段代码。发现应用程序 SoC 缺少此引导代码的任何身份验证。此外,在将控制权传递给下一个引导阶段之前,任何后续 OS 引导步骤都不会对下一个引导阶段执行任何身份验证。这会导致在 Linux 系统上获得代码执行的攻击者获得以下机会:
• Manipulate the root filesystem, changing arbitrary files and e.g. gaining persistence on the system,
• 操作根文件系统,更改任意文件,例如在系统上获得持久性,
• Manipulate configuration data residing in the mtd5 partition, e.g. installing arbitrary SSH keys, and
• 操纵驻留在 mtd5 分区中的配置数据,例如安装任意 SSH 密钥,以及
• Manipulate the bootstrap code, gaining the ability to execute arbitrary code prior to OS boot.
• 操纵引导代码,获得在操作系统启动之前执行任意代码的能力。
CVE-2024-8356/ZDI-24-1188: VIP MCU Unsigned Code
CVE-2024-8356/ZDI-24-1188:VIP MCU 未签名代码
As previously mentioned, the head unit is partitioned into two relatively independent systems; the application SoC running Linux and the VIP MCU running an unspecified OS. The MCU appears to support several CMU functions, including CAN/LIN connectivity to the rest of the vehicle. The partitioning is also assumed to represent a security boundary in that the compromise of the application SoC is expected to be contained and not affect the rest of the vehicle in a way that may compromise safety.
如前所述,车机被划分为两个相对独立的系统;运行 Linux 的应用程序 SoC 和运行未指定操作系统的 VIP MCU。MCU 似乎支持多种 CMU 功能,包括与车辆其余部分的 CAN/LIN 连接。分区还假定代表安全边界,因为应用程序 SoC 的泄露应得到遏制,并且不会以可能危及安全的方式影响车辆的其余部分。
The MCU in question is identified as VIP in the strings found in the CMU software. Through the analysis of software update packages, it was discovered the VIP is also updated during the software update process. The tools to do so, as well as the update image, are found in the vip
subdirectory of the update package.
有问题的 MCU 在 CMU 软件中的字符串中被标识为 VIP。通过对软件更新包的分析,发现 VIP 也会在软件更新过程中进行更新。执行此操作的工具以及更新映像位于更新包的 vip
子目录中。
The vcm
tool allows performing the following operations against the VIP:
vcm
工具允许对 VIP 执行以下操作:
/tmp/mnt/sdb1 # ./vcm –help | |
***** VCM supports the following options: ***** | |
*** Command –write-image argument Required | |
*** Command –get-version argument None | |
*** Command –write-conf argument Required | |
*** Command –reboot argument None | |
*** Command –watchdog-enable argument None | |
*** Command –watchdog-disable argument None | |
*** Command –heartbeat-enable argument None | |
*** Command –heartbeat-disable argument None | |
*** Command –get-all-version argument None | |
*** Command –help argument None | |
*** Command –vipmonitor-enable argument None | |
*** Command –vipmonitor-disable argument None |
Specifically, the --write-image
command allows writing an update image to the VIP. This command is normally used by the update script and takes an input file formatted as Motorola S-records. Of particular interest is also querying the versions of VIP software components. The following is reported on the unit running software cmu150_NA_74.00.324A
:
具体来说,--write-image
命令允许将更新映像写入 VIP。此命令通常由更新脚本使用,并采用格式为 Motorola S 记录的输入文件。特别有趣的是查询 VIP 软件组件的版本。在运行软件 cmu150_NA_74.00.324A
的设备上报告以下内容:
/tmp/mnt/sda1 # ./vcm –get-all-version | |
[VIP VersionInfo] | |
================= | |
OEM P/N: YYYYYYY | |
SW P/N: XXXXXXX | |
CMU_LIN_CAN_DUAL | |
VIP_APP-MAZ150_10.13.012 | |
VIP_CAN-MAZ140_07.09.020 | |
VIP_DIAG-MAZ140_02.77.502 | |
VIP_VBM-MAZ140_15.33.634 | |
VIP_VFBL-MAZ140_02.00.500 | |
CPP_VIPALOGMON_08.08.500 | |
CPP_VIPBTL_05.07.500 | |
CPP_VIPCFG_06.01.500 | |
CPP_VIPEEMGR_05.06.501 | |
CPP_VIPGPIOMON_04.05.502 | |
CPP_VIPHBMON_04.05.500 | |
CPP_VIPIUC_08.09.506 | |
CPP_VIPLINDRVR_05.05.501 | |
CPP_VIPPWRMON_10.01.507 | |
CPP_VIPSPIDRVR_02.21.502 | |
CPP_VIPVOLMGR_06.12.602 |
These strings can be located in the update file image-vip_appvfbl.mot
and are destined to be programmed at memory address 0xC000A in the VIP MCU memory space and appear to be part of the application image spanning addresses 0xC0000 through 0xFFFFF. By modifying these strings, it is possible to determine whether the image is validated before being programmed into the internal memory.
这些字符串可以位于更新文件 image-vip_appvfbl.mot
中,并且注定要在 VIP MCU 内存空间的内存地址0xC000A进行编程,并且似乎是跨地址 0xC0000 到 0xFFFFF 的应用程序映像的一部分。通过修改这些字符串,可以确定图像在编程到内部存储器之前是否经过验证。
The original S-record file was manipulated to change one string to produce a visible indication of different firmware, and the resulting image was programmed back to the VIP MCU:
原始 S 记录文件纵以更改一个字符串以产生不同固件的可见指示,并将生成的图像编程回 VIP MCU:
% diff ./image-original.mot ./image-haxd-fixd.mot | |
457c457 | |
< S2240C00200000000000000000535720502F4E3A202058585858585858000000000000000036 | |
— | |
> S2240C00200000000000000000535720502F4E3A202048415844204259205A444900000000B7 |
/tmp/mnt/sda1 # ./vcm –write-image image-haxd-fixd.mot | |
Data Flashed: 589168 of 589168 bytes | |
VIP Rebooted |
Using the same command for version check, it is possible to confirm the tampered image was accepted:
使用相同的命令进行版本检查,可以确认被篡改的镜像已被接受:
/tmp/mnt/sda1 # ./vcm –get-all-version | |
[VIP VersionInfo] | |
================= | |
OEM P/N: YYYYYYY | |
SW P/N: HAXD BY ZDI | |
CMU_LIN_CAN_DUAL | |
VIP_APP-MAZ150_10.13.012 | |
VIP_CAN-MAZ140_07.09.020 | |
VIP_DIAG-MAZ140_02.77.502 | |
VIP_VBM-MAZ140_15.33.634 | |
VIP_VFBL-MAZ140_02.00.500 | |
CPP_VIPALOGMON_08.08.500 | |
CPP_VIPBTL_05.07.500 | |
CPP_VIPCFG_06.01.500 | |
CPP_VIPEEMGR_05.06.501 | |
CPP_VIPGPIOMON_04.05.502 | |
CPP_VIPHBMON_04.05.500 | |
CPP_VIPIUC_08.09.506 | |
CPP_VIPLINDRVR_05.05.501 | |
CPP_VIPPWRMON_10.01.507 | |
CPP_VIPSPIDRVR_02.21.502 | |
CPP_VIPVOLMGR_06.12.602 |
In a more global sense, this allows an attacker to pivot from a compromised application SoC running Linux to the VIP MCU by installing a crafted firmware version and subsequently gaining direct access to the connected CAN busses of the vehicle.
从更全球化的意义上讲,这允许攻击者通过安装精心设计的固件版本,然后直接访问车辆连接的 CAN 总线,从运行 Linux 的受感染应用程序 SoC 转向 VIP MCU。
Exploitation 开发
Exploitation of the OS command injection vulnerabilities is relatively straightforward. All the attacker needs to do is create a file on a FAT32-formatted USB mass storage device where the name will contain the OS commands to be executed. The filename must end with .up
for it to be recognized by the software update handling code. While all three command injection vulnerabilities are exploited via the file name, the easiest one to exploit is by far the ZDI-CAN-23420 as there are no specific exploitation requirements such as validity of the crafted update file.
利用 OS 命令注入漏洞相对简单。攻击者需要做的就是在 FAT32 格式的 USB 大容量存储设备上创建一个文件,该文件的名称将包含要执行的操作系统命令。文件名必须以 .up
结尾,以便软件更新处理代码能够识别它。虽然所有三个命令注入漏洞都是通过文件名利用的,但到目前为止最容易利用的是 ZDI-CAN-23420,因为没有特定的利用要求,例如构建的更新文件的有效性。
Exploitation of the described command injection vulnerabilities can be further facilitated by the fact that software update installation can be triggered automatically upon connecting a USB mass storage device; this is a “known feature” which is activated by simply placing an empty file named jci-autoupdate
on the storage device.
通过在连接 USB 大容量存储设备时可以自动触发软件更新安装,可以进一步促进对所述命令注入漏洞的利用;这是一个“已知功能”,只需在存储设备上放置一个名为 jci-autoupdate
的空文件即可激活。
Once the initial compromise is achieved, the attacker can gain persistence through manipulation of the root file system, such as installing backdoored system components which will persist across system restarts.
一旦实现最初的入侵,攻击者就可以通过操纵根文件系统来获得持久性,例如安装后门系统组件,这些组件将在系统重启后仍然存在。
Furthermore, the attacker can move laterally and install a specially crafted VIP microcontroller software allowing unfettered access to vehicle networks, potentially impacting vehicle operation and safety. Specific impacts (what could be controlled and how) were not investigated during this research effort.
此外,攻击者可以横向移动并安装特制的 VIP 微控制器软件,从而允许不受限制地访问车辆网络,从而可能影响车辆运行和安全。在这项研究工作中,没有调查具体影响(可以控制什么以及如何控制)。
Associated Risks for Users/Owners
用户/所有者的相关风险
In the lab environment, the entire attack chain – from plugging in a USB drive to installing a crafted update on the VIP – takes only a few minutes. Currently, there is no reason to believe a similar attack will take significantly more time against a unit installed in a car. This means that the vehicle can be compromised while, for example, it is being handled by a valet, during a ride share, or via USB malware. Naturally, the same can be done in a shop environment where there are no significant time pressures.
在实验室环境中,整个攻击链 – 从插入 USB 驱动器到在 VIP 上安装精心设计的更新 – 只需几分钟。目前,没有理由相信针对安装在汽车中的装置进行类似的攻击会花费更多时间。这意味着车辆可能会受到损害,例如,当它由代客泊车、拼车期间或通过 USB 恶意软件处理时。当然,在没有重大时间压力的车间环境中也可以这样做。
The CMU can then be compromised and “enhanced” to, for example, attempt to compromise any connected device in targeted attacks that can result in DoS, bricking, ransomware, safety compromise, etc.
然后,CMU 可以被入侵和“增强”,例如,尝试在有针对性的攻击中入侵任何连接的设备,从而导致 DoS、变砖、勒索软件、安全危害等。
Conclusions 结论
This research effort and its output highlighted the fact that high-impact vulnerabilities can be found even in a very mature automotive product that has been on the market for a number of years and with a long history of security fixes. To date, these vulnerabilities remain unpatched by the vendor.
这项研究工作及其成果突出了这样一个事实,即即使在已经上市多年且具有悠久安全修复历史的非常成熟的汽车产品中,也可以发现高影响的漏洞。迄今为止,供应商仍未修补这些漏洞。
There has been a lot of focus and discussion recently in the security community about the importance of language security and “memory safe” languages. This set of real-world vulnerabilities is a good reminder that focusing on only one bug class or employing one set of security tools (static code analysis, for instance) does not result in deployed systems being secure. In this case, C was used to develop the firmware, but it is an irrelevant fact considering the nature of the discovered vulnerabilities. Any ‘memory-safe’ firmware would have also been compromised in this instance.
最近,安全社区中有很多关于语言安全和“内存安全”语言重要性的关注和讨论。这组真实的漏洞很好地提醒我们,只关注一个错误类别或使用一组安全工具(例如静态代码分析)并不能确保部署的系统是安全的。在这种情况下,C 用于开发固件,但考虑到发现的漏洞的性质,这是一个无关紧要的事实。在这种情况下,任何“内存安全”固件也会受到损害。
While the SQL and OS command injection issues represent programming errors, the remaining vulnerabilities are security design flaws. It is paramount that system integrity is ensured at all runtime stages and for all components. Only then is it possible to guarantee the downstream security properties of languages and their compilers.
虽然 SQL 和 OS 命令注入问题代表编程错误,但其余漏洞是安全设计缺陷。确保所有运行时阶段和所有组件的系统完整性至关重要。只有这样,才能保证语言及其编译器的下游安全属性。
In summary, it is important to consider the whole system security and security-test complete production systems in all their operational modes.
总之,重要的是要考虑整个系统的安全性,并在所有操作模式下对整个生产系统进行安全测试。
原文始发于Dmitry Janushkevich:Multiple Vulnerabilities in the Mazda In-Vehicle Infotainment (IVI) System
转载请注明:Multiple Vulnerabilities in the Mazda In-Vehicle Infotainment (IVI) System | CTF导航