isecwire/canbus-sniffer
GitHub: isecwire/canbus-sniffer
这是一个基于 Linux SocketCAN 的汽车与工业总线安全审计工具,集成了多协议解码、流量统计及实时异常检测功能。
Stars: 0 | Forks: 0
# canbus-sniffer
[](https://github.com/isecwire/canbus-sniffer/actions/workflows/ci.yml)
[](LICENSE)
[](https://isocpp.org/)
[](https://www.kernel.org/doc/html/latest/networking/can.html)
用于汽车和工业安全评估的 CAN 总线流量捕获、多协议解码器和异常检测器。
`canbus-sniffer` 是一个基于 Linux SocketCAN 构建的命令行工具,用于捕获原始 CAN 帧,使用 DBC 信号数据库或内置协议解码器(J1939、OBD-II、UDS)对其进行解码,重新组装 ISO-TP 多帧消息,并应用实时异常检测(包括统计时序分析和熵监控)来识别对 CAN 网络的潜在攻击。它专为在汽车 ECU 网络、工业 SCADA 总线以及任何使用 CAN 2.0A/B 的系统中进行渗透测试、安全审计和事件调查而设计。
### CLI 输出

### 终端界面 (`--tui`)

## 功能特性
### 捕获与接口
- 在任何 SocketCAN 接口(`can0`、`vcan0`、PEAK、Kvaser 等)上进行 **实时捕获**
- 通过仲裁 ID 进行 **硬件级过滤**,以减少繁忙总线上的噪声
- 带有微型表达式解析器的 **软件过滤表达式**(`id=0x100-0x1FF,dlc>4`)
- **重放模式** —— 离线分析之前捕获的 candump 日志文件
- **持续时间受限的捕获**,用于自动化测试脚本
### 协议解码
- **DBC 信号解码** —— 解析标准 DBC 文件并实时显示物理信号值
- **J1939 协议支持** —— 从 29 位 ID 解码 PGN、源/目的地址、优先级;内置 PGN 数据库,支持 EEC1、CCVS、ET1、LFE、DM1、TSC1、AMB 等的 SPN 解码
- **OBD-II PID 解码器** —— 从 ID 为 0x7DF/0x7E0-0x7E7 的 CAN 帧中解码标准 OBD-II PID(发动机转速、车速、冷却液温度、节气门、燃油液位等)
- **UDS(统一诊断服务)解码器** —— 解析诊断请求/响应,包括 DiagnosticSessionControl、SecurityAccess、ReadDataByIdentifier(带 DID 名称查找)、RoutineControl,以及带有 NRC 解码的否定响应
- **ISO-TP (ISO 15765-2) 重组** —— 处理多帧消息(单帧、首帧、连续帧、流控制),具有序列验证和超时处理
### 异常检测
- **学习/检测两阶段模型**,可配置学习持续时间
- 基线期间未见过的未知仲裁 ID
- 总线泛洪检测(每个 ID 可配置的消息速率阈值)
- 重放攻击检测(重复的有效载荷序列)
- DLC(帧长度)异常
- **统计时序异常检测** —— 跟踪每个 ID 的消息间时序分布,标记超出 3 sigma 的消息
- **Shannon 熵分析** —— 计算每个仲裁 ID 的有效载荷熵,标记异常的高/低熵有效载荷
- **序列号跟踪** —— 检测递增字节模式并标记间隙
- **伪装检测** —— 基于时序检测多个源声明相同的仲裁 ID
### 输出与导出
- 带有 ANSI 代码的 **彩色终端输出** —— 异常为红色,解码为绿色,警告为黄色
- **实时统计模式**(`--stats`)—— 刷新显示每个 ID 的帧计数、消息速率、总线负载百分比、熵
- **PCAP 导出**(`--pcap FILE`)—— 以 PCAP 格式写入捕获的帧(LINKTYPE_SOCKETCAN = 227),以便用 Wireshark 进行分析
- **多种导出格式**(`--export json|csv|candump`),可选输出文件
- 以 candump 兼容格式和结构化 JSON 进行 **日志记录**
### 终端界面(可选)
- 使用 FTXUI 构建的 **交互式 TUI**(`--tui`)—— 可选择使用 `-DENABLE_TUI=ON` 进行编译
- 顶部面板:实时帧源(滚动,按类型着色)
- 左侧边栏:仲裁 ID 列表,包含帧计数和速率
- 右侧面板:选定 ID 的详细信息,包含解码信号、熵、时序
- 底部栏:总帧数、总线负载 %、异常计数、运行时间
- 状态行:过滤表达式、接口名称、录制状态
- 键盘:`q` 退出,`p` 暂停/继续,`r` 重置统计,Up/Down 选择 ID
## 环境要求
- 支持 SocketCAN 的 Linux(内核 2.6.25+)
- C++17 编译器(GCC 8+,Clang 7+)
- CMake 3.14+
- `can-utils`(可选,用于使用 `cansend`/`candump`/`cangen` 进行测试)
- FTXUI(可选,当使用 `-DENABLE_TUI=ON` 时自动获取)
## 构建说明
### 不带 TUI(默认)
```
mkdir build && cd build
cmake ..
make -j$(nproc)
```
### 带 TUI
```
mkdir build && cd build
cmake .. -DENABLE_TUI=ON
make -j$(nproc)
```
FTXUI 会通过 CMake FetchContent 自动下载。该工具在没有 FTXUI 的情况下也能完全编译和运行。
生成的二进制文件位于 `build/canbus-sniffer`。
### 运行测试
```
cd build
ctest --output-on-failure
```
## SocketCAN 设置
### 物理 CAN 适配器
大多数 USB-CAN 适配器(PEAK PCAN-USB、Kvaser Leaf、CANable)会自动注册为 SocketCAN 接口:
```
sudo ip link set can0 up type can bitrate 500000
```
### 用于测试的虚拟 CAN (vcan)
创建一个虚拟 CAN 接口,以便在没有硬件的情况下进行本地开发:
```
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
```
## 使用方法
```
canbus-sniffer v2.1.0 [OPTIONS]
Interface & capture:
-i, --interface CAN interface (default: can0)
-D, --duration Capture duration (0 = infinite, default: 0)
-q, --quiet Suppress frame output to stdout
-C, --no-color Disable ANSI colored output
Protocol decoding:
-d, --dbc Load DBC file for signal decoding
-P, --protocol Protocol mode: raw (default), j1939, obd2, uds
Filtering:
-f, --filter Hardware filter by arbitration ID
-F, --filter-expr Software filter expression
e.g. "id=0x100-0x1FF,dlc>4"
Anomaly detection:
-a, --detect-anomalies Enable anomaly detection
--learn Learning phase duration (default: 30)
--flood-threshold Messages/sec per ID to flag as flood (default: 500)
Logging & export:
-l, --log Log frames to file (candump format)
-j, --json Log frames to file (JSON format)
--pcap Write captured frames in PCAP format
--export Export format: json, csv, candump
--export-file Export output file (default: stdout)
Statistics & replay:
-s, --stats Live statistics mode (refreshing display)
--replay Replay a candump log file through the analyzer
Terminal UI:
--tui Launch interactive terminal UI
-h, --help Show this help
```
### 示例
在虚拟 CAN 接口上进行基本捕获:
```
./canbus-sniffer -i vcan0
```
J1939 重型车辆总线解码:
```
./canbus-sniffer -i can0 -P j1939 -a --learn 10
```
带过滤的 OBD-II 诊断捕获:
```
./canbus-sniffer -i can0 -P obd2 -F "id=0x7E0-0x7EF"
```
UDS 诊断会话监控:
```
./canbus-sniffer -i can0 -P uds -j diag_session.json
```
带 DBC 解码和 PCAP 导出的捕获:
```
./canbus-sniffer -i can0 -d vehicle.dbc --pcap capture.pcap -l capture.log
```
带实时统计的异常检测:
```
./canbus-sniffer -i vcan0 -a --learn 10 -s
```
通过 J1939 解码器重放捕获的日志:
```
./canbus-sniffer --replay capture.log -P j1939 --export csv --export-file out.csv
```
带异常检测的交互式终端界面:
```
./canbus-sniffer -i vcan0 --tui -a --learn 5
```
用于 CI 流水线的限时捕获:
```
./canbus-sniffer -i vcan0 -D 60 -l test_capture.log -q
```
### 过滤表达式语法
```
filter = condition { ',' condition }
condition = field op value
| 'id' '=' value '-' value (range)
field = 'id' | 'dlc' | 'data[N]'
op = '=' | '!=' | '<' | '<=' | '>' | '>='
value = hex (0x...) or decimal number
```
示例:
```
id=0x100-0x1FF # ID range filter
id=0x7DF,dlc>4 # Combined conditions
id=0x100,data[0]=0xFF # Data byte filter
dlc<=4,id!=0x000 # Multiple conditions
```
### 使用 vcan 进行测试
在一个终端中,以 J1939 模式启动嗅探器:
```
./canbus-sniffer -i vcan0 -P j1939 -a --learn 5 -s
```
在另一个终端中,发送 J1939 流量:
```
# EEC1 (engine speed)
cansend vcan0 18F00400#00000080003E0000
# CCVS (vehicle speed)
cansend vcan0 18FEF100#0000500000000000
```
对于 OBD-II 测试:
```
# Request engine RPM
cansend vcan0 7DF#0201010000000000
# Simulate RPM response (1726 rpm)
cansend vcan0 7E8#04410C1AF8000000
```
## 架构
```
src/
main.cpp Main entry point, CLI parsing, capture loop
can_interface.h/cpp RAII SocketCAN wrapper
frame_decoder.h/cpp DBC parser and signal extraction
anomaly_detector.h/cpp Learning/detection anomaly engine
logger.h/cpp Candump and JSON file logging
j1939.h/cpp J1939 PGN decoder with SPN database
obd2.h/cpp OBD-II Service 01 PID decoder
uds.h/cpp UDS service/DID/NRC decoder
isotp.h/cpp ISO-TP multi-frame reassembly engine
statistics.h/cpp Statistical analysis, entropy, timing, bus load
pcap_writer.h/cpp PCAP file writer (LINKTYPE_SOCKETCAN)
filter_expr.h/cpp Filter expression parser and evaluator
tui.h TUI controller interface (always available)
tui.cpp FTXUI implementation (compiled with -DENABLE_TUI=ON)
tui_stub.cpp Stub when FTXUI not available
tests/
main_test.cpp Hand-rolled test framework (no external deps)
test_*.cpp Unit tests for each module
```
## DBC 文件格式
该工具解析标准的 Vector DBC 文件。最小示例:
```
BO_ 291 EngineData: 8 ECU
SG_ EngineSpeed : 24|16@1+ (0.25,0) [0|16383.75] "rpm" Vector__XXX
SG_ EngineTemp : 40|8@1+ (1,-40) [-40|215] "degC" Vector__XXX
BO_ 1024 BrakeStatus: 2 ABS
SG_ BrakePedal : 0|8@1+ (0.392157,0) [0|100] "%" Vector__XXX
```
## 安全背景
车辆和工业系统中的 CAN 总线网络通常缺乏身份验证和加密。常见的攻击向量包括:
- **欺骗** —— 注入带有伪造仲裁 ID 的帧,以冒充 ECU
- **重放攻击** —— 记录并重新发送有效的帧序列
- **总线泛洪** —— 通过高优先级饱和总线来进行拒绝服务
- **模糊测试** —— 发送格式错误的帧,以触发 ECU 中的未定义行为
- **伪装攻击** —— 基于时序的冒充,攻击者替换合法的 ECU
- **Bus-off 攻击** —— 强制错误状态以断开合法节点
- **诊断滥用** —— 未经授权的 UDS 会话,用于固件提取或 ECU 重编程
`canbus-sniffer` 帮助安全评估人员在实时评估期间建立流量基线并检测这些模式。它还可以作为轻量级 IDS 部署在嵌入式 Linux 网关上。
## 常见问题
### “解码 CAN 帧”是什么意思?
CAN 总线是车辆、机器人和工业机器内部的通信网络。电子控制单元(ECU)发送包含原始字节的帧 —— 例如,ID 为 0x0C0、数据为 `0B B8` 的帧。如果不进行解码,你只能看到十六进制。经过解码(使用 DBC 文件或协议知识)后,你会看到:“Engine Speed: 3000 RPM”。
canbus-sniffer 捕获这些原始帧,并使用 J1939(卡车/重型设备)、OBD-II(汽车)或 UDS(诊断)协议解码器将其转换为人类可读的值。
### 什么是 CAN 总线上的重放攻击?
攻击者记录合法的 CAN 帧(例如,“解锁车门”),并在稍后重放它们。车辆/机器会执行该命令,因为 CAN 没有身份验证 —— 它无法区分重放的帧和真实的帧。canbus-sniffer 通过跟踪帧序列并标记重复模式来检测重放攻击。
### 实际中如何使用?
```
# Set up virtual CAN for testing
sudo modprobe vcan && sudo ip link add dev vcan0 type vcan && sudo ip link set up vcan0
# Capture and decode J1939 traffic
canbus-sniffer --interface can0 --protocol j1939 --detect-anomalies --log capture.json
```
## 许可证
MIT -- 详见 [LICENSE](LICENSE)。
版权所有 (c) 2026 isecwire GmbH
标签:Bash脚本, C++, CAN总线, DBC文件, ECU, ISO-TP, J1939, OBD-II, SCADA, SocketCAN, UDS, 二进制发布, 协议解码, 哈希传递, 工业控制安全, 开源工具, 异常检测, 数据擦除, 汽车安全, 车载网络