Move command registry from components/command/ into components/core/. New modules: mod_canbus, mod_honeypot, mod_fallback, mod_redteam, mod_ota. Replace mod_proxy with tun_core (multiplexed SOCKS5 tunnel). Kconfig extended with per-module settings and async worker config.
12 KiB
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
- Wiring
- Configuration
- Architecture
- Commands Reference
- Frame Format
- C3PO Integration
- Usage Examples
- 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 <id_hex> <data_hex> |
2 | No | Send a single frame. Ex: can_send 0x7DF 0201000000000000 |
can_filter_add <id_hex> |
1 | No | Add software filter (pass only matching IDs) |
can_filter_del <id_hex> |
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 <tx_id> <service_hex> [data_hex] |
2-3 | Yes | Raw UDS request |
can_uds_session <tx_id> <type> |
2 | No | DiagnosticSessionControl (1=default, 2=prog, 3=extended) |
can_uds_read <tx_id> <did_hex> |
2 | Yes | ReadDataByIdentifier |
can_uds_dump <tx_id> <addr_hex> <size> |
3 | Yes | ReadMemoryByAddress (streamed) |
can_uds_auth <tx_id> [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 <pid_hex> |
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 <pids> [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 <id_hex> [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|<timestamp_ms>|<id_hex>|<dlc>|<data_hex>
Example:
CAN|1708000123456|0x123|8|DEADBEEF01020304
Special Markers
| Marker | Meaning |
|---|---|
SNIFF_END |
End of sniff session |
DUMP_START|<count> |
Beginning of frame dump |
DUMP_END |
End of frame dump |
UDS_RSP|<rx_id>|<hex> |
UDS response |
MEM_DUMP|<addr>|<size> |
Start of memory dump |
MEM|<addr>|<hex_data> |
Memory block |
MEM_DUMP_END |
End of memory dump |
ECU|<tx_id>|<rx_id> |
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_MHZmatches 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
listenmode first:can_start 500000 listen - Check CAN_H / CAN_L connections and termination (120 ohm)
- Use
can_statusto check error counters — high RX errors indicate speed mismatch
Bus-off state
- TEC exceeded 255 — the MCP2515 disconnected from the bus
can_stopthencan_startto 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 <id> - Increase
CANBUS_RECORD_BUFFERin 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