【AutoCS】卡巴斯基-奔驰MBUX安全研究

文摘   2025-01-23 17:04   上海  


Introduction

本报告涵盖了卡巴斯基团队对梅赛德斯-奔驰主机单元的研究。梅赛德斯-奔驰最新的主机单元(信息娱乐系统)被称为MBUX。我们进行了第一代MBUX的分析。

MBUX之前已被KeenLab分析过。他们的报告是深入了解MBUX内部结构和理解该系统架构的良好起点。

在我们的研究中,我们对第一代MBUX子系统进行了详细分析,这些部分在KeenLab的研究中未被涉及:诊断(如CAN、UDS等)、通过USB连接以及自定义IPC(进程间通信)。


Diagnostic software
要初步了解车辆架构,使用诊断软件(仅限认证用户使用)扫描电子控制单元(ECU),识别其版本,并测试软件的诊断功能是非常有帮助的。有几种诊断工具可以实现与车辆连接,并使用各种类型的通信方式。在我们的研究中,我们使用了一套组合的诊断工具:一个特定的硬件接口和一个对应的软件应用程序,通过该硬件设备与车辆进行通信。这种设置使我们能够通过DoIP建立通信。

Communication between diagnostic software and hardware
诊断工具与诊断硬件设备之间的TCP通信是通过以太网使用自定义协议进行的。在第一阶段,诊断硬件设备使用一种基于ASCII的自定义协议(CSD)。它执行用户认证、版本检查、配置设置,并提供处理上层协议(PDU)所需的初始环境。
上层协议采用二进制格式。它用于发送通用诊断服务(UDS)消息,触发DoIP通信等。为了分析这个协议,我们使用了用LUA编写的脚本:[pduparser.lua]。利用这个脚本,可以轻松地区分UDS命令与诊断软件和硬件之间通信的常规网络流量:
我们检查了诊断工具的接口并解码了流量,这使我们能够找到各种UDS命令,例如用于重置ECU、关闭引擎和锁定车门的命令。

Architecture
MBUX的架构如下:


MBUX的主要组成部分为:

  • MMB——主机单元(HU)的主要部分,包含所有子系统; 

  • BB——具有用于各种网络通信的芯片的部分; 

  • CSB——通过内部以太网与MMB通信的扩展部分; 

  • RH850 —— 设计用于提供低级总线之间通信的模块。 


Test setups

在我们的研究中,我们使用了两种测试设置:

  • 实车 — 梅赛德斯 B180;

  • 测试平台 — 我们自己设计的硬件和软件测试平台,专为此研究目的而创建。


Anti-Theft

在建模测试平台时,我们需要绕过原始的防盗功能,因为在实际车辆启动后,主机单元会通过CAN总线等待认证。正如KeenLab研究报告中提到的,需要通过CAN发送特定命令来唤醒系统。我们在设置中无法模拟这一点,因此主机单元进入了防盗模式,用户无法与其进行通信。通过经验方法,我们发现某些CAN消息可以强制主机单元重置防盗状态。实际上,这些消息触发了防盗检查。例如,当主机单元尝试关闭显示器时,CAN消息会发起防盗检查,使主机单元在几秒钟内仍然可访问。为了实现无缝且稳定的调查,我们创建了一个脚本,该脚本持续循环发送这条消息。

结果是,主机单元长时间处于可访问状态,在已认证状态和防盗模式之间切换。


Firmware
MMB运行在Linux上,其文件系统位于eMMC中。我们需要通过焊锡移除的方法从印刷电路板上提取eMMC。内部包含有若干个分区:

MMB的文件也可以从提供特定硬件件号更新的诊断工具网站下载。


Unpack update

如今,汽车中的多媒体系统通常通过OTA进行更新。然而,汽车经销商是一个例外,因为他们可以使用诊断工具执行离线软件更新。

在网上仍然可以找到一些过时的更新文件。根据文件名,更新文件类型可以分为以下几组:

  • 包含 .CFF、.SMR-F 和 *.bin 文件的 ALL 文件;

  • 仅包含 *.CFF 文件的 CFF 文件;

  • 仅包含 .SMR-F 文件的 SMR-F 文件。

一般来说,.bin 文件是具有自定义文件结构的容器。它们可能使用zlib或其他方法编码。

*.SMR-F 文件是压缩过的,并且也具有自定义文件结构。除了纯文本元数据外,它们还包含加密的数据,诊断工具使用其共享库来解密这些数据。解密后,生成的文件包含元数据和一个容器,就像 *.bin 文件一样。

*.CFF 文件与 *.SMR-F 文件包含相同的未压缩有效载荷内容。这种格式用于较早一代的主机单元。


Custom IPC

在主机单元内部,固件服务使用自定义的进程间通信(Inter-Process Communication, IPC)协议,在自身的线程、其他服务以及其他ECU之间进行通信。有三种主要广泛使用的协议:

  • thriftme; 

  • MoCCA; 

  • GCF。 

这些协议可以同时使用;此外,每个服务也可以同时使用所有这些协议。了解这些协议的内部工作原理和API,有助于更好地理解服务的工作流程。


thriftme

此RPC(Remote Procedure Call) 协议基于开源协议Apache Thrift。它的主要特点之一是thriftme允许订阅者接收到特定事件的通知。UNIX套接字、TCP、UDP、SSL等可以作为此协议的传输层。此协议的核心功能实现在库libthriftme.so.2.7.2中。

在thriftme RPC中,基类为“thrift::TServiceBroker”,它负责隔离服务与客户端之间的通信以及服务调用接口。在thriftme中,服务代理版本是“thrift::lisa::CTLisaServiceBroker”的实例,它继承自“thrift::TServiceBroker”。

Thriftme中的服务类继承自thrift::lisa::TLisaServerBase,而thrift::lisa::TLisaServerBase又继承自thrift::TServiceProcessor。服务通过thrift::TServiceProcessor::registerService方法在服务代理中进行注册。客户端使用的传输协议通过thrift::lisa::CTLisaServiceBroker::addServers方法注册,该方法封装了thrift::TServiceBroker::addServer。服务接口函数则通过thrift::TServiceProcessor::tmRegisterCallback方法注册。在处理客户端请求时,会调用传递给该方法的处理器(handler)。因此,内存中的服务实例结构如下:

interface1”字段包含用于处理服务API及其先前通thrift::TServiceProcessor::tmRegisterCallback注册的包装函数。而“interface2”字段包含用于通知该服务订阅者的回调函数。

在Thriftme中,客户端继承自thrift::lisa::TLisaClientBase,而thrift::lisa::TLisaClientBase又继承自thrift::TClient。实际上,客户端实例是由服务代理在传输成功创建时生成的。在我们的案例中,服务代理使用了一个客户端工厂,该工厂通过thrift::TServiceBroker::tmRegCli注册到服务代理中。该工厂帮助客户端通过thrift::TClient::tmRegisterCallback注册事件通知的处理器。Thriftme客户端的实例布局如下:

“interface1”字段包含的处理器是在传输连接建立后被调用的。通常这个处理器用于触发订阅操作以接收事件通知。“interface2”字段包含发送请求到服务API的函数。“interface3”字段包含在发起该服务的“通知订阅者”操作之前的调用函数。这些函数的包装器是通过“thrift::TClient::tmRegisterCallback”预先注册的。


MoCCA

这个RPC框架由Harman开发,基于开源的DSI框架。核心功能实现在“/opt/sys/lib/libSysMoCCAFrameworkSharedSo.so.11”库中。这个框架广泛用于线程间通信。

在启动期间,服务通过工厂函数创建组件实例,例如“CHBApplicationBuilder::theCDiagnosisComponentCreator”。这个实例继承自“CHBComponent”类。全局变量“CHBComponentInfo::spMap”包含了组件附加信息与它们名称之间的映射。框架允许组件拥有自己的别名,以便通过“CHBComponentInfo::addComponentMapping”访问其他组件:“CHBComponentInfo::addComponentMapping(&unk_581498, “FsActionHandler”, “FilesystemMainActionHandler”)”。组件可以包含多个服务和客户端,并且可以与自身服务或其他组件的服务进行通信。以下是组件的架构:

为了通信,以下事件被使用:
一个客户端对象的例子是“CTraceServiceClientBase”,它继承自“CHBClientBase”并使用代理对象“CTraceServiceProxy”进行传输。代理对象继承自“CHBProxyBase”,并通过工厂方法“CTraceServiceProxy::findOrCreateInstance”创建。它尝试在这个组件内重用已经创建的代理对象。客户端对象的一般布局如下:

“IHBEventConsumer”接口用于在“CTraceServiceClientBase”中处理响应事件。处理的入口点是“processEvent”方法。它使用两个值来查找处理器,调用方式如下:

使用“status”字段识别响应:服务的标准响应、失败或无效响应; 使用“internalID”字段识别API函数。 在我们的示例中,服务端使用了“CTraceServiceStub”类。以下是它的布局:

请求事件在“processEvent”方法中被处理。它通过“internalID”字段识别API函数处理器,并调用已识别的处理器。

GCF

GCF是一种自定义协议,用于远程过程调用(RPC)。它允许服务在路由中注册。路由处理来自服务和客户端的消息如下:

控制消息(“CTRL”):

  •  “REGS” – 用于注册服务;

  •  “REGF” – 用于注册服务的RPC函数; 

  • “EVNT” – 由服务用来通知客户端有关事件;

  •  “CALL” – 由客户端用来调用服务的功能; 

因此,在初始化期间,服务在路由中注册。内部路由表处理消息流的处理。最后,客户端可以向路由发送调用请求,这会触发已注册服务的预定义功能。调用请求的格式如下:

CALL <ServiceName>:<Number> <ServiceCallName> <Params>

Internal network
正如KeenLab的研究报告中提到的,主机单元上有一些测试点,这些测试点被CSB用于连接到MMB。我们移除了默认连接,并连接RJ45以访问主机单元的内部网络。这个连接标记为eth0,根据“firewall_prd.policy”中的相应防火墙规则,它有一定的限制:
-A INPUT -s [IP]/32 -d [IP]/32 -i eth0 -m state –state NEW -j ACCEPT-A OUTPUT -s [IP]/32 -d [IP]/32 -o eth0 -j ACCEPT-A OUTPUT -s [IP]/32 -d [IP]/32 -o eth0 -m state –state NEW -j ACCEPT
对MMB上的服务的访问是通过一个IP地址建立的,这是CSB连接到MMB的默认地址。对MMB上的TCP端口扫描结果如下:

连接到测试点后,我们获得了一个庞大的攻击面以及对诊断日志和跟踪(Diagnostic Log and Trace, DLT)子系统的访问权限,这在测试和调试时非常有帮助:

DLT支持回调注入功能,使得可以在服务内部调用特定的处理器。在主机单元中,这一特性被广泛用于产品测试。


Identified vulnerabilities

以下发现被用来攻破测试平台。这对于调试环境以及搜索可能在真实车辆中被利用的子系统漏洞是必要的。

CVE-2024-37600 (MoCCA) 

“servicebroker”服务是DSI框架的一部分,该框架被用于MoCCA中。此服务用于监控其他服务和客户端。

它通过TCP端口设置HTTP服务器。有几个POST命令可以被处理,其中一个命令是disconnect,它以字符串作为参数。

setup()函数中的代码尝试使用提供不必要的内存访问权限的函数来解析这个命令。根据反汇编代码,它使用sscanf在一个栈缓冲区上执行读取操作。结果可能导致栈缓冲区溢出:

在DLT日志中,我们可以识别出崩溃信息:


CVE-2023-34404 (GCF)

 “MonitorService”是一个可以通过GCF协议访问的服务。这个服务在“scp”服务中初始化并启动。“scp”服务本身是一个systemd服务,它使用以下配置启动:

...[Service]ExecStart=/opt/comm/swmp/wicome/bin/scp -f /var/opt/swmp/pss_config.cfg -s wicome_config -r /opt/comm/swmp/wicome/bin -k VerboseLevel=5ExecStop=/bin/kill $MAINPIDEnvironment=LD_LIBRARY_PATH=/opt/sys/lib:/opt/comm/swmp/wicome/libEnvironment=LOGNAME=rootEnvironmentFile=/opt/etc/lisa_envType=simpleRestart=on-failureRestartSec=2WatchdogSec=240...

“MonitorService” 使用以下配置文件 “/var/opt/swmp/pss_config.cfg” 来微调其操作:

MonitorService.TimestampEnable = 1MonitorService.ReceiveEnable = 1MonitorService.MonitoringEnable = 1MonitorService.MessageBufferSize = 1000MonitorService.MessageBufferMemory = 512000#1-file, 2-dlt, 3-bothMonitorService.LogMode = 2#MonitorService.LogMode = 0MonitorService.LogFileSize = -1MonitorService.LogFileName = /tmp/wicom.logMonitorService.LinefeedEnable = 1MonitorService.HeaderEnable = 1MonitorService.FileHeaderEnable = 1#RHMonitorService.Port                = 2021

“MonitorService.Port” 变量处理服务器将使用的TCP端口号。“MonitorService.ReceiveEnable” 变量定义了服务器是否能够处理来自客户端的请求。因此,“MonitorService”,包含主机单元配置,可以接收来自客户端的GCF消息,并通过GCF路由器传输这些消息。

在GCF路由中注册的服务列表包括 “NetworkingService”。它具有以下已注册的处理程序:

“NWS_PF_setMacAddrExceptionIP” 处理程序向防火墙策略中添加规则。它使用以下参数:

  • macAddress – 用于规则的MAC地址;
  • direction – 定义规则的方向:入站或出站;
  • fate – 定义规则的类型:允许或拒绝;
  • command – 要执行的动作:将规则添加到策略中或从策略中移除。

处理此请求的控制流位于以下二进制文件中:“MonitorService”,“libwicome_monitorservice.so” 和 “libwicode_gcf_core.so”。调用栈如下:

sub_EE6E8 (NWS_PF_setMacAddrExceptionIP)  sub_E9D0C (sNWS_PF_setMacAddrExceptionIP)    sub_F275C (CGCFStub_PF::setMacAddrExceptionIP)      sub_F7AF4 (CGCFStub_PF::_int_setMacAddrExceptionIP)        snprintf        sub_F7EB4 (systemExec)          system
sub_F7AF4 函数使用参数执行对 iptables 二进制文件的 system() 调用:
/* ... */  if ( v10 )  {    v11 = (const char *)PAL::CString::raw(direction);    v12 = (const char *)PAL::CString::raw(mac);    if ( snprintf(v22, 0xFFuLL, "iptables -%s  %s -m mac --mac-source %s -j %s ", (const char *)&v21, v11, v12, v20) < 0 )     {      /* ... */      v18 = 0;    }    if ( v18 )    {      if ( (unsigned __int8)systemExec(a1, v22) != 1 )      {        /* ... */        return 0;      }    }  }  /* ... */

在处理请求时,MAC地址既没有被检查也没有受到限制。这意味着攻击者可以在执行iptables命令期间进行命令注入。


Privilege escalation

主机单元使用的是过时的Polkit系统,该系统存在CVE-2021-4034漏洞。这是一个本地权限提升漏洞,可能导致非特权用户在目标机器上获得管理员权限。有很多公开可用的利用此漏洞的方法,可以以“phone”用户和“comm”组的身份执行任意命令。

成功利用这个漏洞后,攻击者可以运行命令来修改网络接口、挂载文件系统并执行其他特权活动。尽管施加了一些限制,潜在的攻击者仍可以访问systemd命令以进一步提升其权限。

根文件系统的分区是以只读文件系统挂载的。正如KeenLab的研究中提到的,主机单元没有任何启用的磁盘完整性保护功能。这意味着文件系统可以用读写权限重新挂载,并且可以在启动期间运行的bash脚本可以被修改。


USB
在物理访问方面,USB是最流行的攻击向量。主机单元建立在一个微服务架构之上,每个服务相对隔离,并通过API进行通信。主机单元的每个微服务提供一些内部功能和一个或多个thriftme服务,通过这些服务其他微服务可以与之通信。这一事实使得可以使用QEMU用户模式版本来模拟USB子系统。

Preparation

“DeviceManager”服务负责处理USB事件:添加、移除、挂载或更新。其他服务可以订阅“DeviceManager”,并在USB事件发生时使用通知回调来执行动作。例如,当USB文件系统挂载时,这样的服务可以开始搜索特定文件。

“GDVariantCodingService”服务是变体编码的前端。其他服务使用它来识别主机单元和汽车的参数。

为了运行自托管的USB子系统,这两个服务都应被模拟。这项任务可以通过模拟相应的thriftme服务来完成。因此,为了成功的模拟,我们应该执行以下操作:

  1. 准备用于服务的IP地址网络。

  2. “DeviceManager”和“GDVariantCodingService”服务使用UNIX套接字作为传输方式。为了模拟它们,使用TCP套接字会更简单,这样我们就不会依赖于文件系统。使用socat进行转发。

  3. 运行模拟的thriftme服务。在我们的案例中,我们创建了devicemgr.py、vehicle.py和varcoding.py。在devicemgr.py中,模拟了USB文件系统的挂载路径为“/opt/sys/bin/aaaaa”。

  4. 以“transparent”的方式使用QEMU用户模拟。

  5. 在chroot环境中准备文件夹和设备。

对USB子系统进行了仿真。


Emulation of data export, import and tracing

主机单元具有将用户配置文件(座椅位置、喜爱的广播电台等)导入或导出到USB存储的功能。这项任务由“UserData”服务处理——更确切地说,是由thriftme服务“CSystemProfileServiceImpl”处理的。

用户配置文件备份看起来像是一个具有以下目录结构的文件夹:

.└── MyMercedesBackup    ├── shared    ├── system    │   ├── rse.ud2    │   └── system.ud2    └── udxprofiles        ├── profile0        │   ├── commuterroute.ud2        │   ├── emotions.ud2        │   ├── navidata.ud2        │   ├── pud.ud2        │   ├── uapreds.ud2        │   ├── vt_ab.ud2        │   └── vt_tuner.ud2        └── profileindex.xml

一些文件是由“UserData”自身生成的,但大多数文件是由其他服务如“CAPServer”生成和处理的。“UserData”中的thriftme服务“UserDataExchangeService”是数据导入和导出过程中的最重要组件。其他服务订阅“UserDataExchangeService”以接收有关数据导入和导出的通知。

当通过“CSystemProfileServiceImpl”导出配置文件备份时,执行以下工作流程:

  • 启动一个100秒的计时器。
  • 通过“UserDataExchangeService”使用事件通知客户端服务请求数据导出。这些事件包含了关于被导出数据的信息。
  • 服务调用API函数来验证数据导出的成功与否。其参数包括数据键和文件路径。
  • “UserData”收集所有接收到的文件,对其进行编码,并将它们存储在已挂载的USB文件系统中。

对于配置文件备份的导入,流程类似:

  • “UserData”从USB复制文件到本地系统并解码它们。
  • 它通过事件通知客户端服务请求数据导入。
  • 如果客户端服务正在处理该数据键,则它会导入数据。
  • 服务调用API函数来验证数据导入的成功与否。

备份包含XML文件和二进制文件。对于漏洞挖掘而言,二进制文件被认为更有用:

Data keyFilename in backupContent
PUD_COMMUTER
commuterroute.ud2
ISO-8859 text, with no line terminators
PUD_UAPREDICTIONSDATA
uapreds.ud2
SQLite 3.x database
PUD_VT_TUNER
vt_ab.ud2
Proprietary binary data
PUD_VT_ADDRESSBOOK
vt_tuner.ud2
Proprietary binary data

触发备份导入(恢复)和导出(备份)时,创建了以下脚本:triggerRestore.py 和 triggerBackup.py。

主机单元的几乎所有服务都支持追踪系统HBTracePersistence,这允许为特定模块或功能开启或关闭追踪。

“hbtc”文件包含追踪系统的配置,并确定函数追踪的方法。下面提供了一个“hbtc”文件的例子:

HBTracePersistence 1.0.0imp 00 08imp_userdata_private_CSystemProfileManager ff 08imp_userdata_private_CUserDataVehicleInformationAdapter ff 08imp_userdata_private_CUserDataIF2Impl ff 08imp_common_streamhelper_StreamHelper ff 08imp_userdata_private_CUDXStructure ff 08

如前所述,备份中的文件是经过编码的——所使用的算法是私有的。“CPUserDataEncodingHandler”类处理这些编码和解码操作。为了能够对文件进行编码和解码,准备了一个名为 ud2codec.py 的脚本。


Identified vulnerabilities

已识别的漏洞 以下漏洞已在真实车辆上进行了测试。

CVE-2024-37601

解码具有 *.ud2 扩展名的文件的过程包含堆缓冲区溢出漏洞。

“UserData” 通过 “CHBString” 对象表示编码的数据,该对象将数据作为 UTF 字符串处理。然后应删除特定于 UD2 的解码字符,并保持其索引不变。为此任务我们使用了 “CHBString::const_iterator::incrementSteps” 函数来获取指向所需字符的指针,并使用 “CHBString::remove” 函数从字符串中移除字符。“CHBString::const_iterator::incrementSteps” 错误地处理了代码为 0xe7 的字符:它将被解码为 1 个字节。但根据 “UTF8LookUpTable”,这个表在 “CHBString::remove” 和 “CHBString::CHBString” 中使用,代码为 0xe7 的字符是用 3 个字节编码的。 因此,在使用 “UTF8LookUpTable” 进行 UTF 解码后,“CHBString::remove” 函数执行时计算出的指针可能会超出分配的缓冲区范围。此时会调用带有第三个参数(缓冲区大小)等于 -1 的 memmove 函数。

即使没有攻击者的进一步利用,这个漏洞也会导致“UserData”服务在数据导入期间崩溃。这会使系统进入冻结状态,只有通过 ECU 硬复位才能修复。

CVE-2023-34402

如前所述,在配置文件备份导出期间,vt_ab.ud2 文件被解码为 vt_ab.xml 以用于漏洞搜索。这个文件的内容看起来像二进制文件,并由文本到语音服务处理。

vt_ab.xml 文件中包含了另一个文件,描述了在处理过程中将丢弃的服务。为此,它包含了要丢弃的文件的名称。这一动作是在 “UserDataExchangeServiceClient::unpackVoiceTagArchiveOptimized” 函数中完成的:

  • 获取描述要丢弃内容的文件的内容;
  • 获取要丢弃的文件名并执行丢弃操作。

由于缺乏检查,攻击者可以控制用于写入可控内容的路径。结果是,攻击者可以获得与服务相同权限的任意文件写入访问权。

CVE-2023-34399

解码后,“MyMercedesBackup/udxprofiles/profile0” 配置文件夹中的 uapreds.ud2 文件以 uapreds.db 的形式存在。系统将其识别为 SQLite 数据库,该数据库在使用机器学习创建高效路线的服务中解析。解码后的文件在 “capthrift::CapServer::requestImportBinaryData” 中处理,然后调用 “capthrift::CapServer::setProfile” 来加载数据库。

SQLite 数据库表中的所有值都被序列化为一个档案,以匹配 boost 库。这个档案的格式可以是 XML 或纯文本。我们使用的是纯文本模式。以下是 kvpair_table 表中 learning_kernel 行的一个档案示例:

22 serialization::archive 11 0 2 0 1 0 0 1 0 1 0 0 0 0 1 0.00000000000000000e+00 0 0 0 0 0 0 0 0 1.00000000000000000e+00...

截至研究时,boost库的最后一个公开版本为1.81,其中包含整数溢出漏洞。当处理实体指针时,可以利用此漏洞:

在(1)处,值cid从攻击者可控的数据中获得。然后,在(2)处,该值被用作数组索引来获取cobject_id对象。(3.1)和(3.2)引入了对cid的限制:

  • cid的值是否等于-1;
  • cid的值是否大于cobject_id_vector数组的大小。

这些限制可以通过分配给cid的值来绕过。这是可能的,因为class_id_type被定义为一个整数:

所以如果我们给cid赋值“-3”,那么指针co.bpis_ptr (2)将会被破坏。

最后,在调试器中触发的漏洞如下所示:

在(1)处,值cid从攻击者可控的数据中获得。然后,在(2)处,该值被用作数组索引来获取cobject_id对象。(3.1)和(3.2)引入了对cid的限制:

  • cid的值是否等于-1;
  • cid的值是否大于cobject_id_vector数组的大小。

这些限制可以通过分配给cid的值来绕过。这是可能的,因为class_id_type被定义为一个整数:

所以如果我们给cid赋值“-3”,那么指针co.bpis_ptr (2)将会被破坏。

最后,在调试器中触发的漏洞如下所示:

Thread 63 hit Breakpoint 20x0000004002f3cea4 in ?? ()# cid value(gdb) i r x2x2             0xfffffffffffffffd  -3# cobject_id_vector size(gdb) x/1hx $x20 + 0x580x405c01b278:  0x000e# cobject_id_vector pointer(gdb) x/1gx $x20 + 0x600x405c01b280:  0x000000405c017f001 element in the cobject_id_vector(gdb) x/3gx *(void **)($x20 + 0x60) + 0 * 0x180x405c017f00:  0x000000400147f1c8  0x00000000000000000x405c017f10:  0x0000010000000002# refferenced element(gdb) x/3gx *(void **)($x20 + 0x60) + -3 * 0x180x405c017eb8:  0x5f72696170766b5f  0x00315f656c6261740x405c017ec8:  0x0000000000000035(gdb) cContinuing. Thread 63 received signal SIGSEGVSegmentation fault.

Exploitation notes

在第一阶段,假设图像基地址是固定的,并且漏洞代码被加载到内存中的特定地址。我们分析了漏洞代码并检查了所有指针是如何解引用的以及虚拟调用是在哪里执行的。以下是步骤:

通过控制id,我们可以移动指针(通过将其移动到堆中数组起始位置的负偏移);

通过移动指针,我们将到达一个地址,该地址包含指向bis_ptr对象的另一个地址;

bis_ptr的地址应该包含虚拟调用表的地址。

 仅控制到相应对象的偏移量,我们需要到达堆中包含指向关联虚拟表的指针的地址。

我们可以使用在SQLite数据库内可控的DDL条目喷射来实现这样的场景。对于这种喷射,我们需要创建许多带有长名称的表。结果,格式正确的结构将出现在堆中,而负索引将允许我们访问这些结构。

以下是一个基于SQLite的文件示例(sqlite_schema中的条目是表创建请求):
因此,我们可以创建许多带有长名称的表,这给了我们一个堆喷射的原始方法。

利用堆喷射技术,攻击者可以完全控制执行流:

为了将uapreds.db数据库导入“CAPServer”服务,我们需要将其复制到服务的工作目录。然后“CAPServer”尝试从其自己的工作目录加载数据库。结果是,如果攻击者成功导入了一个触发主机单元漏洞的数据库,那么每次“CAPServer”的启动都会尝试加载它并导致崩溃。“CAPServer”服务由“systemd”启动,并配置如下:

[Service]ExecStart=/opt/prediction/bin/CAPServer /var/opt/prediction/ExecStop=/bin/kill $MAINPIDEnvironment=LD_LIBRARY_PATH=/opt/sys/libEnvironmentFile=/opt/etc/lisa_envType=notifyWatchdogSec=30Restart=on-failureRestartSec=2

这意味着在崩溃之后,“systemd”将会尝试重启“CAPServer”。这会触发服务崩溃的无限循环,这在试图暴力破解图像基地址时可能是有用的。

在SQLite数据库中,有一个pragma部分,它包含了用于创建表的SQL命令。此特性可以基于当前时间用来创建数据库表外的可控数据。以下脚本可以用来自动化创建SQLite数据库的过程,根据当前时间可能会触发这个漏洞:

#!/bin/bashDBPATH=test.dbSTOP_TIME=$(date --date='-2 hours +10 seconds' +"%H:%M:%S") echo "Trigger until < $STOP_TIME, clean after >= $STOP_TIME"; poc_value="CRASH the system"clean_value="system work" check() {	sqlite3 $DBPATH << EOFSELECT strftime ('Time of database: %H:%M:%S''now');select * from target_table;.exitEOF} rm $DBPATH sqlite3 $DBPATH << EOFCREATE VIEW target_table AS SELECT "key" AS varkey, "$poc_value" AS varval WHERE TIME() < "$STOP_TIME" UNION SELECT "key" AS varkey, "$clean_value" AS varval WHERE TIME() >= "$STOP_TIME";.exitEOF check sleep 10 check

因此,攻击者可以在一段时间内运行图像基地址的暴力破解。


Attack vectors

在我们的研究过程中,我们成功攻破了主机单元的测试平台,并通过物理访问找到了几个适用于真实汽车的漏洞。

测试平台被攻破有三种潜在的使用场景:

  • 一名罪犯想要禁用被盗主机单元中的防盗保护;
  • 一位车主调整和解锁车辆上的预付费服务;
  • 一名渗透测试员进行研究以发现新的漏洞。

对于真实汽车而言,所识别的漏洞可以通过暴露给普通用户的USB服务来触发。

CVE详情将在以下链接公布:https://github.com/klsecservices/Advisories



ArtiAuto 匠歆汽车
匠歆会展是一家全球性的活动公司,通过会议和培训向汽车制造、出行、教育、生命科学等行业的领先商业、学术、政府和研究机构提供前沿信息。旗下品牌包括匠歆汽车(ArtiAuto)、匠歆出行(ArtiMobi)、匠歆教育(ArtiEdu)等。
 最新文章