导语:上一讲把 SocketCAN + can-utils 这套 Linux 原生栈讲透了,今天切到 Python 工具链。Python 在车安全领域已经形成清晰的三层栈——底层是 python-can 做硬件抽象,中层是 Scapy 做协议构造,上层是 Caring Caribou 做安全测试。三件套组合起来能一站打 UDS 服务发现、DoIP 扫描、模糊测试,比单纯用 can-utils 命令行工具灵活得多。
一、为什么 Python 在车安全里必学
车安全的攻击面太多——CAN、CAN-FD、LIN、FlexRay、汽车以太网(DoIP、Some/IP)、UDS、XCP、TPMS(胎压监测系统)、IVN(车内联网)协议栈都不一样。用 C 写每个协议的解析器不现实,Python 的优势就在这里:动态语言 + 协议包生态成熟 + 跨平台,三件事凑齐就成了首选。
另外,所有红队 PoC 都倾向于 Python——它能快速验证假设,错了改一行就行,不用编译重链接。这一讲把 Phase 2 工具链最后一讲的三件套讲完,后面 Phase 3 的 Jeep Cherokee、Tesla 等经典案例会直接引用今天这套工具做实战。

二、python-can:CAN 总线的硬件抽象层
python-can 由 hardbyte 维护,是 Python 生态里事实标准的 CAN 库。它的核心价值是把”硬件差异”藏到 backend(后端)层——同一份代码可以跑在 SocketCAN、PCAN(PEAK)、Vector、Kvaser、CANalyst-II、CANtact 等任意硬件上。
Bus 是这条类的核心抽象:
import can
# 通过 SocketCAN 后端连 vcan0 虚拟接口
bus = can.Bus(interface="socketcan", channel="vcan0", bitrate=500000)
# 发一帧
msg = can.Message(arbitration_id=0x123, data=[0xDE, 0xAD, 0xBE, 0xEF], is_extended_id=False)
bus.send(msg)
# 收一帧(超时 1 秒)
recv = bus.recv(timeout=1.0)
print(f"ID=0x{recv.arbitration_id:X}, DLC={recv.dlc}, DATA={recv.data.hex()}")
支持的 backend(部分):
socketcan— Linux 原生pcan— PEAK PCAN 硬件kvaser— Kvaser 硬件vector— Vector CANalyzer/CANoevirtual— 完全虚拟,不需硬件udp_multicast/udp_socket— 把 CAN 流量走 UDP,跨机器调试用ixxat/neovi— IXXAT 和 neoVI 硬件
常用功能:
- Listener(监听器)——把
recv()包成回调,异步处理不丢帧 - Logger(记录器)——ASC(CANalyzer)、BLF(Vector)、MF4(ASAM)、TRC、CSV、SQLite 七种格式直接写盘
- Notifier(通知器)——多 listener 订阅同一条总线
- 周期发送——
can.send_periodic()设间隔自动发,用于模拟 ECU 节拍
版本要求是 Python 3.7+(4.0+)、3.8+(4.3+)、3.9+(4.6+),目前 4.x 主线跑得很稳。
三、Scapy:协议构造的瑞士军刀
Scapy 由 secdev 团队维护,是网络协议栈的事实标准 DSL(领域特定语言)。它在车安全领域的价值是用统一的 Python 语法描述任意协议包——从 Ethernet(以太网)到 CAN,从 TCP 到 UDS,语法完全一致。
CAN 协议包构造:
from scapy.all import *
from scapy.contrib.automotive import Ecu_State, UDS
load_contrib("automotive") # 加载汽车贡献包
# 构造一帧 CAN 包
pkt = CAN(arbitration_id=0x7DF) / bytes([0x02, 0x01, 0x00]) # OBD-II 请求
# 0x7DF 是广播 ID,0x01 0x00 是 Service 01 PID 00 请求
# 发送并等待响应(默认 socketcan 接口 vcan0)
ans, unans = sr(pkt, timeout=2, iface="vcan0")
for s, r in ans:
print(f"Recv: ID=0x{r.arbitration_id:X}, DATA={bytes(r).hex()}")
Scapy 的关键能力:
- load_contrib(“automotive”)——加载汽车贡献包,提供 CAN、CAN-FD、UDS、OBD-II、Ecu_State 等高层协议对象
- sr() / srp()——send & receive 模式,自动匹配请求和响应
- sniff()——抓包并回调,等价于 tcpdump
- hexdump() / raw()——包和字节流互转
- 与 python-can 协同——Scapy 默认走 socketcan 后端,硬件切换靠 python-can
最大优势是协议无关性——同一个 sr() 函数既能发 TCP SYN 也能发 UDS 0x27 Seed-Key,对红队而言,写攻击脚本的认知负担最小。
四、Caring Caribou:车安全测试的 nmap
Caring Caribou(GitHub: CaringCaribou/caringcaribou)的定位直接——”a friendly automotive security exploration tool”,它把车安全测试做成类似 nmap 的模块化工具集:
| 模块 | 功能 |
|---|---|
dump | 抓 CAN 流量到终端或文件 |
send | 命令行发原始帧,或 replay(重放)dump 文件 |
listener | 枚举总线上所有出现过的 arbitration ID(仲裁 ID) |
fuzzer random | 随机 ID + 随机数据发包 |
fuzzer brute | 按位掩码(bit mask)暴力遍历某个 ID 下的可能值 |
uds | UDS 服务发现(0x10 诊断会话控制、0x22 读 DID、0x27 安全访问等) |
uds_fuzz | UDS 模糊测试(基于 uds 模块的 fuzz(模糊测试)封装) |
doip | DoIP 扫描(UDP 发现 + TCP 连接握手) |
xcp | XCP 标定协议连接 |
dcm | 已弃用,旧版 DCM 接口 |
test | 跑内置测试套件 |
典型 UDS 扫描:
# 枚举所有仲裁 ID
caringcaribou listener
# 扫描 0x7DF(OBD-II 广播)下的 UDS 服务
caringcaribou uds services -arbuds 0x7DF
# 测试 ECU 是否支持 0x27 安全访问
caringcaribou uds security_access -arbuds 0x7E0
# 暴力遍历 0x100-0x1FF 范围 ID
caringcaribou fuzzer brute -bitmask 0x700 -start 0x100 -end 0x1FF
Caring Caribou 起源于瑞典 KTH 皇家理工学院的 HEAVENS(HEAling Vulnerabilities to ENhance Software Security and Safety)研究项目,本来是学术工具,但模块设计很工程化,已经被多家 OEM(整车厂)和 Tier 1(一级供应商)安全团队日常使用。
顺手做个三件套职责对比——红队拿到工具经常一脸蒙,这张表能让选型秒定:
| 关注点 | python-can | scapy | caring caribou |
|---|---|---|---|
| 定位 | CAN 硬件抽象库 | 多协议包构造器 | 车安全测试 CLI(命令行工具) |
| 后端硬件切换 | 30+ 接口可配 | 仅 socketcan | 仅 socketcan |
| 协议对象抽象 | 无 | CAN/UDS/Ecu_State | UDS/XCP/DoIP |
| 学习曲线 | 陡(API 多) | 平(DSL 友好) | 最平(开箱即用) |
| 适合场景 | 自研工具底座 | 写自定义 PoC | 快速摸底目标 |
五、实战三连:UDS 发现 + DoIP 扫描 + 模糊测试
红队拿到 CAN 接口后,标准打法三步走:
第一步:listener 摸底——caringcaribou listener 启动一段时间,看哪些 ID 出现频率高、哪些 ID 只在上电时出现。出现频率高的 ID 优先分析。
第二步:UDS 服务发现——caringcaribou uds services -arbuds 0x7E0(0x7E0 是动力总成常见 ID)扫 ECU 支持哪些 UDS 子服务,重点看:
- 0x27 安全访问是否启用
- 0x2E 写 DID(Data Identifier,数据标识符)是否无鉴权
- 0x31 例程控制能否调用未公开例程
第三步:模糊测试——caringcaribou fuzzer random 在工程车上永远不要跑,先在 HIL(Hardware-in-the-Loop,硬件在环)测试台架或车辆断开传动系统的状态下跑。模糊测试一定要有 watchdog(看门狗),发现异常立即停。
六、红队 4 大攻击场景
这三件套组合起来能做的事:
- 服务发现——扫出整车 ECU 的诊断服务矩阵,画出攻击面地图
- 凭证爆破——0x27 Seed-Key 算法的 Python 实现,结合 Scapy 跑字典
- 协议模糊——自定义 UDS 数据包模板 + 变异策略,喂给 CanCat/UDSim 做离线 fuzz(模糊测试)
- 持久化 PoC——Scapy 写一次攻击脚本,所有 ModBus 传测试用例都用同一套框架,便于工程化交付
真实攻防推荐链条:python-can 做收发底座(多硬件切换),Scapy 做协议层表达(高层协议对象),Caring Caribou 做工具层捷径(现成模块)。三层各管各的,不要混着用。
七、防御建议
- 诊断端口接入——OBD-II 接口加身份认证或物理开关,非授权场景禁止调试协议访问
- UDS 安全访问——0x27 强制 Seed-Key 算法,禁止默认 0x00/0x01 等弱种子
- 日志审计——ECU 记录所有诊断会话,鉴权失败的请求要能回溯 IP/工具指纹
- 模糊测试左移——OEM 在量产前用 Scapy + UDSim 做协议 fuzz(模糊测试),CI(持续集成)跑回归,发现问题比红队找到早
八、思考题
- python-can 的
Bus()接口同时支持 socketcan 和 virtual 两种后端。如果你在开发 PoC 时用 vcan0 调试,部署到实车要改哪个参数?硬件切换要不要动业务代码? - Scapy 的
sr()自动匹配请求和响应,但 UDS 多帧传输(ISO-TP 协议)会把一个大包拆成多帧,sr()还能正确匹配吗?需要用哪个 contrib 模块? - Caring Caribou 的
fuzzer brute按位掩码遍历 ID 范围。如果攻击面是 11-bit 标准帧的全 ID 空间(0x000-0x7FF),暴力遍历跑完要多久?为什么生产环境禁止直接跑?
下一篇 08 讲进入 Phase 3 的经典案例——Jeep Cherokee 2015 年 Miller/Valasek 那次著名远程攻击复盘。
九、素材出处
- python-can:
https://github.com/hardbyte/python-can - Scapy(secdev):
https://github.com/secdev/scapy - Scapy 汽车贡献包文档:
https://scapy.readthedocs.io/en/latest/layers/automotive.html - Caring Caribou:
https://github.com/CaringCaribou/caringcaribou - HEAVENS 项目:
https://research.kth.se/ics/heavens - awesome-vehicle-security 列表 #170、#172、#174














暂无评论内容