# CAN Bus Module (mod_canbus) Automotive CAN bus offensive module for Espilon, built on the **MCP2515** SPI controller. Supports passive sniffing, frame injection, ISO-TP transport, UDS diagnostics, OBD-II decoding, fuzzing, and replay. > **Authorization required**: CAN bus interaction with vehicles must be performed only on owned hardware or with explicit written authorization. Unauthorized access to vehicle networks is illegal. --- ## Table of Contents - [Hardware Requirements](#hardware-requirements) - [Wiring](#wiring) - [Configuration](#configuration) - [Architecture](#architecture) - [Commands Reference](#commands-reference) - [Core Commands](#core-commands) - [UDS Diagnostic Commands](#uds-diagnostic-commands) - [OBD-II Commands](#obd-ii-commands) - [Fuzzing Commands](#fuzzing-commands) - [Frame Format](#frame-format) - [C3PO Integration](#c3po-integration) - [Usage Examples](#usage-examples) - [Troubleshooting](#troubleshooting) --- ## Hardware Requirements | Component | Role | Cost | |-----------|------|------| | **MCP2515 module** | CAN 2.0B controller + TJA1050 transceiver | ~3 EUR | | **ESP32** | Main MCU (any variant with SPI) | ~5 EUR | Most MCP2515 modules sold online already integrate the TJA1050 CAN transceiver. Check the oscillator crystal on your module — common values are **8 MHz** and **16 MHz** (must match Kconfig `CANBUS_OSC_MHZ`). --- ## Wiring Default GPIO mapping (configurable via `idf.py menuconfig`): ``` MCP2515 Module ESP32 (VSPI) ────────────── ──────────── VCC → 3.3V GND → GND CS → GPIO 5 MOSI (SI) → GPIO 23 MISO (SO) → GPIO 19 SCK → GPIO 18 INT → GPIO 4 (active low) ``` Connect **CAN_H** and **CAN_L** on the MCP2515 module to the target CAN bus. For OBD-II: pin 6 (CAN_H) and pin 14 (CAN_L). --- ## Configuration Enable the module in `idf.py menuconfig` under **Modules > CAN Bus Module (MCP2515)**. ### Kconfig Options | Option | Default | Description | |--------|---------|-------------| | `CONFIG_MODULE_CANBUS` | n | Enable the CAN bus module | | `CANBUS_SPI_HOST` | 3 (VSPI) | SPI host: 2=HSPI, 3=VSPI | | `CANBUS_PIN_MOSI` | 23 | SPI MOSI GPIO | | `CANBUS_PIN_MISO` | 19 | SPI MISO GPIO | | `CANBUS_PIN_SCK` | 18 | SPI SCK GPIO | | `CANBUS_PIN_CS` | 5 | SPI Chip Select GPIO | | `CANBUS_PIN_INT` | 4 | MCP2515 interrupt GPIO (active low) | | `CANBUS_OSC_MHZ` | 8 | Oscillator frequency on MCP2515 module | | `CANBUS_DEFAULT_BITRATE` | 500000 | Default bus speed (bps) | | `CANBUS_SPI_CLOCK_HZ` | 10000000 | SPI clock (max 10 MHz) | | `CANBUS_RECORD_BUFFER` | 512 | Frame ring buffer size (64-2048) | | `CANBUS_ISO_TP` | y | ISO-TP transport layer (required for UDS/OBD) | | `CANBUS_UDS` | y | UDS diagnostic services (requires ISO-TP) | | `CANBUS_OBD` | y | OBD-II PID decoder (requires ISO-TP) | | `CANBUS_FUZZ` | y | CAN fuzzing engine | ### Supported Bitrates | Bitrate | Use Case | 8 MHz | 16 MHz | |---------|----------|-------|--------| | 1 Mbps | High-speed CAN | - | Yes | | 500 kbps | Standard automotive | Yes | Yes | | 250 kbps | J1939 (trucks) | Yes | Yes | | 125 kbps | Low-speed CAN | Yes | Yes | | 100 kbps | Diagnostic | Yes | Yes | --- ## Architecture ``` ┌─────────────────────────────────────────────────────┐ │ cmd_canbus.c — C2 command handlers (27 cmds)│ │ ↕ │ │ canbus_uds.c — UDS (ISO 14229) services │ │ canbus_obd.c — OBD-II PID decoder │ │ canbus_fuzz.c — Fuzzing engine │ │ ↕ │ │ canbus_isotp.c — ISO-TP (ISO 15765-2) │ │ ↕ │ │ canbus_driver.c — MCP2515 SPI driver + RX task │ │ ↕ │ │ canbus_config.c — NVS persistence │ │ ↕ │ │ ESP-IDF SPI Master — Hardware SPI bus │ └─────────────────────────────────────────────────────┘ ``` ### File Manifest | File | Lines | Layer | |------|-------|-------| | `canbus_driver.c/.h` | ~920 | MCP2515 SPI + RX/TX + ISR | | `canbus_isotp.c/.h` | ~480 | Multi-frame CAN transport | | `canbus_uds.c/.h` | ~440 | Automotive diagnostics | | `canbus_obd.c/.h` | ~390 | OBD-II PID decode | | `canbus_fuzz.c/.h` | ~390 | Fuzz testing engine | | `canbus_config.c/.h` | ~360 | NVS persistence | | `cmd_canbus.c/.h` | ~1360 | Command handlers + registration | | **Total** | **~4350** | | ### NVS Persistence Namespace: `"can_cfg"` | Key | Type | Content | |-----|------|---------| | `bitrate` | i32 | Saved CAN speed | | `osc_mhz` | u8 | Oscillator frequency | | `sw_filters` | blob | Up to 16 software filter IDs | | `ecus` | blob | Discovered UDS ECU IDs | --- ## Commands Reference ### Core Commands | Command | Args | Async | Description | |---------|------|-------|-------------| | `can_start [bitrate] [mode]` | 0-2 | No | Init MCP2515, start bus. Mode: `normal` (default), `listen`, `loopback` | | `can_stop` | 0 | No | Stop bus, set MCP2515 to config mode | | `can_send ` | 2 | No | Send a single frame. Ex: `can_send 0x7DF 0201000000000000` | | `can_filter_add ` | 1 | No | Add software filter (pass only matching IDs) | | `can_filter_del ` | 1 | No | Remove a software filter | | `can_filter_list` | 0 | No | List active software filters | | `can_filter_clear` | 0 | No | Clear all filters (accept everything) | | `can_status` | 0 | No | Show bus state, config, RX/TX counters, error counters | | `can_sniff [duration_s]` | 0-1 | **Yes** | Stream frames to C2 for N seconds (default: 10) | | `can_record [duration_s]` | 0-1 | **Yes** | Record to local ring buffer for N seconds (default: 10) | | `can_dump` | 0 | **Yes** | Send recorded buffer to C2 | | `can_replay [speed_pct]` | 0-1 | **Yes** | Replay recorded buffer. 100=real-time, 0=max speed | ### UDS Diagnostic Commands *Requires `CONFIG_CANBUS_UDS=y` (depends on ISO-TP)* | Command | Args | Async | Description | |---------|------|-------|-------------| | `can_scan_ecu` | 0 | **Yes** | Discover ECUs: scans 0x7E0-0x7E7, 0x700-0x7DF | | `can_uds [data_hex]` | 2-3 | **Yes** | Raw UDS request | | `can_uds_session ` | 2 | No | DiagnosticSessionControl (1=default, 2=prog, 3=extended) | | `can_uds_read ` | 2 | **Yes** | ReadDataByIdentifier | | `can_uds_dump ` | 3 | **Yes** | ReadMemoryByAddress (streamed) | | `can_uds_auth [level]` | 1-2 | **Yes** | SecurityAccess seed request | ### OBD-II Commands *Requires `CONFIG_CANBUS_OBD=y` (depends on ISO-TP)* | Command | Args | Async | Description | |---------|------|-------|-------------| | `can_obd ` | 1 | **Yes** | Query single PID, returns decoded value | | `can_obd_vin` | 0 | **Yes** | Read Vehicle Identification Number | | `can_obd_dtc` | 0 | **Yes** | Read Diagnostic Trouble Codes | | `can_obd_supported` | 0 | **Yes** | List supported PIDs | | `can_obd_monitor [interval_ms]` | 1-2 | **Yes** | Stream PIDs to C2 continuously | | `can_obd_monitor_stop` | 0 | No | Stop monitoring | ### Fuzzing Commands *Requires `CONFIG_CANBUS_FUZZ=y`* | Command | Args | Async | Description | |---------|------|-------|-------------| | `can_fuzz_id [start] [end] [delay_ms]` | 0-3 | **Yes** | Iterate all CAN IDs with fixed payload | | `can_fuzz_data [seed_hex] [delay_ms]` | 1-3 | **Yes** | Mutate data bytes for fixed ID | | `can_fuzz_random [delay_ms] [count]` | 0-2 | **Yes** | Random ID + random data | | `can_fuzz_stop` | 0 | No | Stop fuzzing | --- ## Frame Format Frames streamed to C2 use the format: ``` CAN|||| ``` **Example:** ``` CAN|1708000123456|0x123|8|DEADBEEF01020304 ``` ### Special Markers | Marker | Meaning | |--------|---------| | `SNIFF_END` | End of sniff session | | `DUMP_START\|` | Beginning of frame dump | | `DUMP_END` | End of frame dump | | `UDS_RSP\|\|` | UDS response | | `MEM_DUMP\|\|` | Start of memory dump | | `MEM\|\|` | Memory block | | `MEM_DUMP_END` | End of memory dump | | `ECU\|\|` | Discovered ECU | --- ## C3PO Integration ### REST API CAN frames received from agents are stored in a server-side ring buffer (10,000 frames max). | Endpoint | Method | Description | |----------|--------|-------------| | `/api/can/frames` | GET | List frames. Params: `device_id`, `can_id`, `limit`, `offset` | | `/api/can/stats` | GET | Frame stats. Params: `device_id` | | `/api/can/frames/export` | GET | Download CSV. Params: `device_id` | ### TUI Commands From the C3PO interactive TUI: ``` can stats [device_id] — Frame count, unique CAN IDs can frames [device_id] [limit] — Display last N frames can clear — Clear frame store ``` ### Transport Integration CAN frames arrive via `AGENT_DATA` messages with the `CAN|` prefix. The transport layer automatically parses and stores them in `CanStore`. --- ## Usage Examples ### Basic Sniffing (Listen-Only) ``` > can_start 500000 listen # Start in stealth mode (no ACK on bus) > can_sniff 30 # Stream frames for 30 seconds > can_stop ``` ### Record and Replay ``` > can_start 500000 listen > can_record 60 # Record for 60 seconds > can_stop > can_start 500000 normal # Switch to normal mode for TX > can_replay 100 # Replay at real-time speed ``` ### OBD-II Vehicle Diagnostics ``` > can_start 500000 # Standard automotive bitrate > can_obd_supported # List what the car supports > can_obd 0C # Engine RPM > can_obd 0D # Vehicle speed (km/h) > can_obd_vin # VIN number > can_obd_dtc # Read trouble codes > can_obd_monitor 0C,0D 500 # Stream RPM + speed every 500ms ``` ### UDS ECU Exploration ``` > can_start 500000 > can_scan_ecu # Find ECUs on bus > can_uds_session 0x7E0 3 # Extended session on ECU 0x7E0 > can_uds_read 0x7E0 F190 # Read VIN via DID > can_uds_read 0x7E0 F191 # Hardware version > can_uds_auth 0x7E0 1 # SecurityAccess level 1 > can_uds_dump 0x7E0 0x00000000 4096 # Dump 4KB from address 0 ``` ### Fuzzing (Isolated Bus Only!) ``` > can_start 500000 > can_fuzz_id 0x000 0x7FF 10 # Scan all standard IDs, 10ms delay > can_fuzz_data 0x7E0 0000000000000000 5 # Mutate bytes on ECU ID > can_fuzz_stop ``` --- ## Troubleshooting ### MCP2515 not detected - Verify wiring (CS, MOSI, MISO, SCK) - Check `CANBUS_OSC_MHZ` matches the crystal on your module (8 vs 16 MHz) - Try `can_start 500000 loopback` — if loopback works, wiring to the bus is the issue ### No frames received - Confirm bus speed matches the target (500k for cars, 250k for trucks) - Try `listen` mode first: `can_start 500000 listen` - Check CAN_H / CAN_L connections and termination (120 ohm) - Use `can_status` to check error counters — high RX errors indicate speed mismatch ### Bus-off state - TEC exceeded 255 — the MCP2515 disconnected from the bus - `can_stop` then `can_start` to reset - Check for wiring issues or speed mismatch ### RX overflow - Bus traffic exceeds processing speed - Reduce bus load or add hardware filters: `can_filter_add ` - Increase `CANBUS_RECORD_BUFFER` in menuconfig ### SPI communication errors - Reduce `CANBUS_SPI_CLOCK_HZ` (try 8000000 or 4000000) - Check for long wires or loose connections - Ensure no other device shares the SPI bus