4、诊断协议攻击:UDS协议基础、诊断会话劫持、安全访问绕过、DTC注入攻击
大家好,我是老周。今天我们来聊聊诊断协议攻击。说实话,这是车载网络攻击里最「实在」的一块。为什么?因为UDS协议直接控制着ECU的「生杀大权」——刷写、配置、读取故障码,全走这条路。我当年第一次在实车上做渗透测试时,就是通过UDS漏洞拿到了ECU的完全控制权。那感觉,嗯,既兴奋又后怕。
4.1 UDS协议基础:你总得知道对手的规矩
UDS(统一诊断服务)是ISO 14229定义的标准。说白了,它就是ECU的「管理员接口」。你想想看,一辆车上有几十个ECU,每个ECU都需要诊断、刷写、标定。没有统一标准,那不乱套了?
UDS的核心是「请求-响应」模式。诊断仪发一个请求,ECU回一个响应。就这么简单。但关键在于——不是所有请求都允许。ECU有状态机,不同状态下能做的事不一样。
UDS的三种核心会话状态:
- 默认会话(Default Session):上电后的初始状态。只能读读VIN码、版本号这些基本信息。说白了,就是「游客模式」。
- 扩展会话(Extended Session):可以读写一些参数,但还不能刷写。相当于「高级用户」。
- 编程会话(Programming Session):最高权限。可以刷写固件、修改配置。这就是「管理员模式」。
我在项目中遇到过一件事:某Tier1的ECU,默认会话下居然允许执行0x2E(写入数据)服务。你猜怎么着?攻击者根本不需要进入扩展会话,直接就能篡改关键参数。这就是典型的会话状态管理不当。
4.2 诊断会话劫持:抢在合法诊断仪前面
诊断会话劫持,说白了就是「抢方向盘」。攻击者冒充诊断仪,强行切换ECU的会话状态。
为什么会这样?因为UDS协议本身没有强认证机制。ECU只认「谁先发请求」,不认「谁有资格发请求」。攻击者只要在总线上发送一个0x10(诊断会话控制)请求,就能把ECU从默认会话切换到编程会话。
注意:会话劫持的关键在于「时序」。攻击者必须在合法诊断仪发送请求之前,或者在其响应间隙中插入恶意请求。我曾经在测试中,用CANoe模拟了一个高优先级报文,成功在合法诊断仪之前抢占了会话控制权。
防御思路其实不复杂:
- 会话状态锁定:ECU在进入编程会话后,锁定当前会话,拒绝其他节点的会话切换请求。
- 基于挑战-响应的会话建立:不要只靠0x10指令切换,加入一个握手过程。
- 会话超时机制:长时间无活动自动回退到默认会话。
嗯,这里要注意:很多ECU的会话超时时间设置得太长,有的甚至不设超时。这就给了攻击者充足的时间慢慢搞。
4.3 安全访问绕过:破解那把「锁」
安全访问(Security Access,服务ID 0x27)是UDS里最重要的安全机制。它要求诊断仪先发送一个「种子」(Seed),ECU返回一个随机数,然后诊断仪必须用正确的「密钥」(Key)来解锁。
听起来很安全对吧?但实际实现中,漏洞多得让人头疼。
常见的安全访问绕过方式:
| 攻击方式 | 原理 | 我见过的真实案例 |
|---|---|---|
| 种子固定 | ECU每次返回相同的种子 | 某国产ECU,种子永远是0x12345678 |
| 密钥算法逆向 | 通过多次抓包分析出密钥生成算法 | 用CANoe抓了10组Seed-Key对,反推出算法 |
| 暴力破解 | 种子空间太小,直接枚举 | 某ECU种子只有16位,几分钟就破解了 |
| 重放攻击 | 记录合法的Seed-Key对,直接重放 | ECU没有做时间戳或计数器校验 |
我个人习惯,在测试安全访问时,第一件事就是抓10组Seed-Key对。如果发现种子有规律(比如递增、固定、或者跟时间相关),那基本就破了一半。
我曾经遇到一个ECU,它的密钥算法居然是:Key = Seed XOR 0xA5A5A5A5。你想想看,这跟没加密有什么区别?
避坑指南:我曾经在测试某款T-Box时,发现它的安全访问居然没有失败次数限制。我连续发了1000次错误密钥,ECU照样给我返回种子。这种设计,说白了就是形同虚设。
4.4 DTC注入攻击:让ECU「生病」
DTC(诊断故障码)注入攻击,听起来好像没什么危害?其实不然。你想想看,如果攻击者能随意设置故障码,会发生什么?
- 误导维修:让4S店误判故障,更换不必要的零件。
- 掩盖真实攻击:先注入一堆假故障码,把真正的攻击痕迹淹没掉。
- 触发安全机制:某些ECU检测到特定DTC后会进入跛行模式(Limp Home),甚至切断动力。
DTC注入通常通过0x2E(写入数据)服务实现。攻击者直接写入DTC状态字节,把故障码的「确认」位设为1。ECU就认为这个故障真的发生了。
// 攻击示例:注入一个P0A00(电机控制器故障)
// 请求:2E F1 90 [DTC数据]
// 其中F190是DTC状态标识符
// 正常DTC状态字节:
// bit0: 测试失败
// bit1: 当前故障
// bit2: 历史故障
// bit3: 确认故障
// 攻击者直接写入0x0F,把所有位都置1
请求: 02 2E F1 90 0F
响应: 06 6E F1 90 0F // 写入成功
防御DTC注入,核心在于权限控制:
- DTC写入必须经过安全访问:不能允许默认会话下修改DTC。
- DTC状态机校验:ECU内部应该有自己的故障检测逻辑,不能完全相信外部写入的状态。
- 日志审计:记录所有DTC状态变更操作,包括时间戳和源地址。
注意:有些ECU的DTC写入接口,居然连安全访问都不需要。我在某款BCM(车身控制模块)上就遇到过,直接发0x2E就能改DTC。这种漏洞,说白了就是设计时根本没考虑安全。
4.5 实战建议:如何防御诊断协议攻击
说了这么多攻击手法,最后给几条防御建议。这些都是我在项目里踩过坑后总结出来的:
- 会话状态机必须严格:每个服务都要检查当前会话是否允许执行。不要偷懒。
- 安全访问算法要够复杂:别用简单的XOR、加法。至少用AES或者国密算法。种子长度至少32位。
- 加失败次数限制:安全访问失败5次后,锁定30分钟。这是基本操作。
- DTC写入权限收紧:只有编程会话且通过安全访问后,才能修改DTC状态。
- 总线防火墙:在网关上做过滤,只允许特定诊断仪(比如VIN码匹配)访问诊断服务。
我记得有一次,帮某主机厂做安全审计。他们的ECU几乎把所有诊断服务都暴露在默认会话下。我花了不到10分钟,就成功刷写了非法固件。那场面,嗯,挺尴尬的。
好了,这一章就到这里。诊断协议攻击是车载网络安全的「基本功」,也是攻击者最喜欢下手的地方。下一章我们聊聊CAN ID注入攻击,那又是另一番天地了。