sunandithabs/CANary

GitHub: sunandithabs/CANary

CANARY 是一套面向 CAN 总线网络的实时可观测性与入侵检测系统,通过模拟多 ECU 流量并基于行为规则识别伪装、重放、泛洪等注入攻击,为车载和工业控制网络提供早期安全预警。

Stars: 0 | Forks: 0

# CANARY 针对 CAN 总线网络的实时可观测性和入侵检测系统。 CAN,加上“煤矿里的金丝雀”(早期预警的象征)。它是为网络上运行的几乎地球上所有的汽车、拖拉机和工业机器提供的早期预警系统。 ## 问题 现代车辆运行着 50-100 多个 ECU(发动机、刹车、转向、信息娱乐系统等),它们全部通过共享的 CAN 总线进行通信。CAN 在 20 世纪 80 年代被设计用于封闭、可信的网络。它没有身份验证,也没有加密。总线上的任何节点都可以发送帧,并声称自己是任何其他节点。 一旦汽车配备了蓝牙、蜂窝调制解调器和 USB 接口,这种假设就不再安全了。攻击者无论是通过信息娱乐系统漏洞、OBD-II 接口设备,还是被入侵的远程信息处理控制单元抵达总线,都可以注入对网络上其他所有 ECU 看起来完全合法的帧。 ## 为什么 CAN 攻击很重要 Miller 和 Valasek 在 2015 年对 Jeep Cherokee 的远程接管事件表明,CAN 注入可以控制转向、制动和加速。从那时起,随着车辆不断增加互联功能,攻击面只增不减,而 CAN 网络本身对伪装身份的节点依然几乎没有内置的防御机制。 要发现这一点,意味着必须监控行为,而不仅仅是检查协议的正确性。一个恶意帧通常是一个格式完全良好的 CAN 帧。这才是 CANARY 旨在解决的实际工程问题。 ## 架构 ``` ┌──────────────────────────────┐ │ ECU Nodes │ │ (Engine, Brake, Door, or an │ │ attacker injecting frames) │ └───────────────┬────────────────┘ │ CANFrame ▼ ┌──────────────────────────────┐ │ BusInterface │ │ SimulatedBus (today) │ │ SocketCANBus (future) │ └───────────────┬────────────────┘ ┌────────┼────────┐ ▼ ▼ ▼ ┌─────────┐ ┌────────┐ ┌───────┐ │ Logger │ │Detector│ │ Stats │ │ (CSV + │ │(rules) │ │Engine │ │ replay) │ │ │ │ │ └─────────┘ └───┬────┘ └───┬───┘ │ Alerts │ Telemetry ▼ ▼ ┌──────────────────────────┐ │ Dashboard (TUI) │ └──────────────────────────┘ ``` 总线下游的所有组件仅通过 `BusInterface.subscribe()` 和 `.offer()` 与其进行通信。logger、detector 和 stats engine 根本不知道也不关心数据帧是来自模拟环境还是真实的 `vcan0` 接口。 ## 功能 - 多 ECU 模拟,具备真实的时序、抖动和基于优先级的仲裁 - CSV 流量记录,以及从日志文件中进行时序精确的回放 - 基于规则的异常检测:ID 欺骗、畸形帧、不可能的消息频率、泛洪/DoS、重放攻击 - 标记严重程度的警报,从 LOW 到 CRITICAL - 实时终端仪表盘,显示总线利用率、仲裁延迟、最活跃发送者和最近的警报 - 原生 C 语言组件(CRC-15 校验和)通过 `ctypes` 桥接,与真实的 CAN 控制器在位级别计算帧完整性的方式一致 - `SocketCANBus`:通过原始 `AF_CAN` 套接字提供真正的 Linux SocketCAN 支持,无需外部库。针对真实接口(`vcan0` 或物理硬件)运行时,无需对 detector、logger 或 dashboard 进行任何修改 - 45 个单元测试和集成测试(2 个 SocketCAN 测试在不具备 CAN 功能的内核上会自动跳过,已验证在 CI 中针对 `vcan0` 通过) - 预先生成的样本数据集:干净的流量和多攻击混合场景 ## 演示 ``` pip install -r requirements.txt bash canary/native/build.sh # build the C CRC-15 component PYTHONPATH=. python -m canary.simulator.generate_samples ``` 这会重新生成 `data/sample_logs/normal_traffic.csv`(0 警报)和 `data/attack_scenarios/mixed_attacks.csv`(欺骗、畸形帧、泛洪和重放攻击全被捕获),并在每个警报触发时将其打印出来。 要针对正在运行的模拟启动实时仪表盘: ``` from canary.simulator import Simulator from canary.dashboard import run_dashboard sim = Simulator("live_demo.csv") # 实践中:在 timer thread 上运行 sim.step(),然后: run_dashboard(sim.stats, sim.detector) ``` ## 工作原理 1. ECU 按照带有真实抖动的时间表发送帧(`canary/ecu/`)。 2. SimulatedBus 通过基于仲裁 ID 的最小堆来解决优先级问题,ID 越低优先级越高,这与真实的 CAN 仲裁工作方式相同(`canary/bus/`)。 3. Logger、Detector 和 StatsEngine 各自独立订阅。它们互不关心对方的存在。 4. Detector 跟踪每个 ID 的基线(预期的源、大小、周期),并对每个帧运行六条独立的规则,从而生成标记了严重程度的警报。 5. StatsEngine 纯粹根据其观察到的内容聚合遥测数据、速率、延迟和最活跃发送者。它从不接触总线内部结构。 6. Dashboard 负责渲染这两者,并且不负责其他任何事情。 ## 设计决策 仲裁被建模为优先级调度,而不是位级别的竞争。这捕获了真实的效果(负载下的延迟和确定性的优先级),而无需模拟下游任何组件都不需要的电信号。 C 语言仅仅出现了一次,用于 CRC-15 校验和,因为这确实是位级别、与硬件紧密相关的工作。它不是为了用而用的。 许多协议特性被有意省略了:位填充、ACK 槽、错误帧、远程帧、过载帧、总线关闭状态机以及精确的位级别仲裁。它们都不会改变 detector 能观察到的内容,因此实现它们只是为了追求 CAN 规范的完整性,而不是为了构建检测工具。 `BusInterface` 是在 Module 4 之后提取出来的,而不是一开始就设计好的,并且它要求对 detector、logger 或 ECU 代码进行零修改。这就是从第一天起就采用订阅者模式解耦所带来的好处。 在集成阶段(Module 7)仅出现了两个真实的 bug:ECU 帧默认使用挂钟时间戳而不是模拟时间,以及 stats engine 将挂钟延迟与模拟时间帧混淆了。这两个问题都是通过显式、有文档记录的时钟传递来修复的,而不是简单地掩盖过去。参见 `Simulator.__init__` 和 `StatsEngine.observe()`。 ## 后续工作 - CAN-FD 支持(更大的 payload,灵活的数据速率) - UDS (Unified Diagnostic Services) 模拟 - J1939(重型车辆协议层) - ISO-TP(多帧传输协议) - 基于 ML 的异常检测(作为极具挑战性的扩展目标) ## 运行测试 ``` PYTHONPATH=. python -m pytest tests/ -v ``` 45 个测试涵盖了帧验证、总线仲裁、ECU 调度、日志记录/回放往返、原生 CRC-15(与纯 Python 参考实现进行核对)、所有六条检测规则、stats engine、dashboard 渲染、跨每个攻击场景的完整模拟器集成,以及 SocketCAN 帧编解码。 其中两个测试会演练实时 `vcan0` 接口,如果内核不支持 CAN,则会自动跳过。要在 Linux 上本地运行它们: ``` sudo modprobe vcan sudo ip link add dev vcan0 type vcan sudo ip link set up vcan0 PYTHONPATH=. python -m pytest tests/test_socketcan.py -v ``` CI 会在每次推送时针对 `vcan0` 真实地运行这些测试。 ## 许可证 MIT。请参阅 LICENSE。
标签:CAN总线, Google搜索, SocketCAN, 安全规则引擎, 模拟器, 车联网, 车载网络安全, 逆向工具, 遥测, 配置错误