CAN Bus Module¶
Automotive CAN bus offensive module 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. Never fuzz on a live vehicle — use isolated test benches only.
Configuration
Enable in idf.py menuconfig → Espilon Bot Configuration → Modules → CAN Bus Module (MCP2515)
Config flag: CONFIG_MODULE_CANBUS
Overview¶
The CAN Bus module provides a full automotive attack stack from low-level SPI communication to application-layer diagnostics. Each layer is independently configurable via Kconfig.
┌──────────────────────────────────────────────────────┐
│ cmd_canbus.c — C2 command handlers (27 cmds)│
│ ↕ │
│ canbus_uds.c — UDS (ISO 14229) diagnostics │
│ 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 │
└──────────────────────────────────────────────────────┘
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 include the TJA1050 CAN transceiver. Check the oscillator crystal (8 MHz or 16 MHz — must match Kconfig CANBUS_OSC_MHZ).
Wiring¶
Default GPIO mapping (configurable in 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 to the target bus. For OBD-II: pin 6 (CAN_H) and pin 14 (CAN_L).
Configuration¶
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 |
CANBUS_OSC_MHZ |
8 | Oscillator frequency (8 or 16 MHz) |
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 (64-2048) |
CANBUS_ISO_TP |
y | ISO-TP transport layer |
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 |
Core Commands¶
can_start¶
Initialize the MCP2515 and start the CAN bus.
Syntax:
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
bitrate |
int | No | Bus speed in bps (default: 500000) |
mode |
string | No | normal (default), listen, loopback |
Modes:
- normal: Full TX/RX participation on bus
- listen: RX only, no ACK sent (stealth sniff)
- loopback: Self-test mode, TX frames loop back to RX
can_stop¶
Stop the CAN bus and put MCP2515 in config mode.
can_send¶
Send a single CAN frame.
Example:
can_filter_add / can_filter_del / can_filter_list / can_filter_clear¶
Manage software filters. When filters are active, only matching CAN IDs are processed.
c2:> send <device_id> can_filter_add <id_hex>
c2:> send <device_id> can_filter_del <id_hex>
c2:> send <device_id> can_filter_list
c2:> send <device_id> can_filter_clear
can_status¶
Show bus state, configuration, and error counters.
Response:
state=running mode=normal bitrate=500000 osc=8MHz
rx=1234 tx=56 rx_err=0 tx_err=0 bus_err=0 overflow=0
filters: 0x7E0 0x7E8
can_sniff¶
Stream CAN frames to C2 for a specified duration. Async.
Default duration: 10 seconds. Frames arrive in format: CAN|<ts>|<id>|<dlc>|<data>.
can_record / can_dump / can_replay¶
Record frames to local ring buffer, dump to C2, or replay on bus.
c2:> send <device_id> can_record [duration_s] # Record to buffer (async)
c2:> send <device_id> can_dump # Send buffer to C2 (async)
c2:> send <device_id> can_replay [speed_pct] # Replay: 100=realtime, 0=max (async)
UDS Diagnostic Commands¶
Requires CONFIG_CANBUS_UDS=y
can_scan_ecu¶
Discover ECUs on the bus by sending TesterPresent to standard ID ranges. Async.
Scans 0x7E0-0x7E7 and 0x700-0x7DF. Reports discovered ECUs as ECU|<tx_id>|<rx_id>.
can_uds¶
Send a raw UDS request. Async.
Example:
can_uds_session¶
Open a UDS diagnostic session.
| Type | Session |
|---|---|
| 1 | Default |
| 2 | Programming |
| 3 | Extended diagnostic |
can_uds_read¶
Read a Data Identifier (DID) from an ECU. Async.
Common DIDs: F190 (VIN), F191 (hardware version), F187 (part number).
can_uds_dump¶
Read memory from an ECU by address. Streams data to C2. Async.
can_uds_auth¶
Request SecurityAccess seed from an ECU. Async.
Default level: 1. Reports the seed bytes for offline key computation.
OBD-II Commands¶
Requires CONFIG_CANBUS_OBD=y
can_obd¶
Query a single OBD-II PID and return the decoded value. Async.
Example:
c2:> send esp001 can_obd 0C
# Response: Engine RPM = 2450.25 rpm
c2:> send esp001 can_obd 0D
# Response: Vehicle Speed = 60 km/h
Common PIDs: 05 (coolant temp), 0C (RPM), 0D (speed), 11 (throttle), 2F (fuel level).
can_obd_vin¶
Read the Vehicle Identification Number (Mode 09, PID 02). Async.
can_obd_dtc¶
Read Diagnostic Trouble Codes (Mode 03). Async.
Reports DTC codes like P0300, C0035, B0100, U0001.
can_obd_supported¶
List which PIDs the vehicle supports. Async.
can_obd_monitor / can_obd_monitor_stop¶
Continuously stream PID values to C2. Async.
c2:> send <device_id> can_obd_monitor <pid_hex,...> [interval_ms]
c2:> send <device_id> can_obd_monitor_stop
Example:
Fuzzing Commands¶
Requires CONFIG_CANBUS_FUZZ=y
Warning
Never fuzz on a live vehicle or production CAN bus. Use isolated test benches only. Fuzzing can cause unpredictable behavior including loss of vehicle control.
can_fuzz_id¶
Iterate through CAN IDs with a fixed payload. Async.
Default: 0x000 to 0x7FF, 10ms delay.
can_fuzz_data¶
Mutate data bytes for a fixed CAN ID. Async.
can_fuzz_random¶
Send random CAN IDs with random data. Async.
can_fuzz_stop¶
Stop any active fuzzing operation.
Frame Format¶
Frames streamed to C2 use the format:
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 |
ECU\|<tx_id>\|<rx_id> |
Discovered ECU |
C3PO Integration¶
REST API¶
CAN frames are automatically stored server-side (ring buffer, 10,000 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¶
can stats [device_id] # Frame count, unique CAN IDs
can frames [device_id] [limit] # Display last N frames
can clear # Clear frame store
Usage Examples¶
Basic Sniffing¶
c2:> send esp001 can_start 500000 listen # Stealth mode
c2:> send esp001 can_sniff 30 # Stream 30 seconds
c2:> send esp001 can_stop
Record and Replay¶
c2:> send esp001 can_start 500000 listen
c2:> send esp001 can_record 60 # Record 60 seconds
c2:> send esp001 can_stop
c2:> send esp001 can_start 500000 normal # Switch to TX mode
c2:> send esp001 can_replay 100 # Replay at real-time speed
Vehicle Diagnostics¶
c2:> send esp001 can_start 500000
c2:> send esp001 can_obd_supported # What does the car support?
c2:> send esp001 can_obd 0C # Engine RPM
c2:> send esp001 can_obd 0D # Speed
c2:> send esp001 can_obd_vin # VIN number
c2:> send esp001 can_obd_dtc # Trouble codes
c2:> send esp001 can_obd_monitor 0C,0D 500 # Stream RPM + speed
ECU Exploration¶
c2:> send esp001 can_start 500000
c2:> send esp001 can_scan_ecu # Find ECUs
c2:> send esp001 can_uds_session 0x7E0 3 # Extended session
c2:> send esp001 can_uds_read 0x7E0 F190 # Read VIN via DID
c2:> send esp001 can_uds_auth 0x7E0 1 # Security seed
c2:> send esp001 can_uds_dump 0x7E0 0x00000000 4096 # Dump 4KB
Troubleshooting¶
MCP2515 not detected¶
- Verify wiring (CS, MOSI, MISO, SCK)
- Check
CANBUS_OSC_MHZmatches crystal (8 vs 16 MHz) - Try loopback:
can_start 500000 loopback— if it works, bus wiring is the issue
No frames received¶
- Confirm bus speed matches target (500k for cars, 250k for trucks)
- Use
listenmode:can_start 500000 listen - Check CAN_H / CAN_L connections and 120 ohm termination
can_status— high RX errors indicate speed mismatch
Bus-off state¶
- TEC exceeded 255 — MCP2515 disconnected from bus
can_stopthencan_startto reset- Fix wiring or speed mismatch
RX overflow¶
- Bus traffic exceeds processing speed
- Add filters:
can_filter_add <id> - Increase
CANBUS_RECORD_BUFFERin menuconfig
Previous: Honeypot | Next: OTA Updates