espilon-source/espilon_bot/components/mod_canbus/README.md
Eun0us 6d45770d98 epsilon: merge command system into core + add 5 new modules
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.
2026-02-28 20:07:59 +01:00

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

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_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 <id>
  • 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