Skip to content

Latest commit

 

History

43 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

canbus-sniffer

CI License: MIT C++ Platform

CAN bus traffic capture, multi-protocol decoder, and anomaly detector for automotive and industrial security assessments.

canbus-sniffer is a command-line tool built on Linux SocketCAN that captures raw CAN frames, decodes them using DBC signal databases or built-in protocol decoders (J1939, OBD-II, UDS), reassembles ISO-TP multi-frame messages, and applies real-time anomaly detection (including statistical timing analysis and entropy monitoring) to identify potential attacks on CAN networks. It is designed for use in penetration testing, security audits, and incident investigation on automotive ECU networks, industrial SCADA buses, and any system using CAN 2.0A/B.

CLI output

CLI screenshot

Terminal UI (--tui)

TUI screenshot

Features

Capture and interface

  • Live capture on any SocketCAN interface (can0, vcan0, PEAK, Kvaser, etc.)
  • Hardware-level filtering by arbitration ID to reduce noise on busy buses
  • Software filter expressions with mini expression parser (id=0x100-0x1FF,dlc>4)
  • Replay mode -- analyze previously captured candump log files offline
  • Duration-limited captures for automated test scripts

Protocol decoding

  • DBC signal decoding -- parse standard DBC files and display physical signal values in real time
  • J1939 protocol support -- decode PGN, source/destination addresses, priority from 29-bit IDs; built-in PGN database with SPN decoding for EEC1, CCVS, ET1, LFE, DM1, TSC1, AMB, and more
  • OBD-II PID decoder -- decode standard OBD-II PIDs (engine RPM, speed, coolant temp, throttle, fuel level, etc.) from CAN frames with IDs 0x7DF/0x7E0-0x7E7
  • UDS (Unified Diagnostic Services) decoder -- parse diagnostic requests/responses including DiagnosticSessionControl, SecurityAccess, ReadDataByIdentifier (with DID name lookup), RoutineControl, negative responses with NRC decoding
  • ISO-TP (ISO 15765-2) reassembly -- handle multi-frame messages (Single Frame, First Frame, Consecutive Frame, Flow Control) with sequence validation and timeout handling

Anomaly detection

  • Learning/detection two-phase model with configurable learning duration
  • Unknown arbitration IDs not seen during baseline
  • Bus flood detection (configurable message-rate threshold per ID)
  • Replay attack detection (duplicate payload sequences)
  • DLC (frame length) anomalies
  • Statistical timing anomaly detection -- tracks per-ID inter-message timing distribution, flags messages outside 3 sigma
  • Shannon entropy analysis -- calculates payload entropy per arbitration ID, flags anomalous high/low entropy payloads
  • Sequence number tracking -- detects incrementing byte patterns and flags gaps
  • Masquerade detection -- timing-based detection of multiple sources claiming the same arbitration ID

Output and export

  • Colored terminal output with ANSI codes -- red for anomalies, green for decoded, yellow for warnings
  • Live statistics mode (--stats) -- refreshing display of frame counts per ID, message rates, bus load percentage, entropy
  • PCAP export (--pcap FILE) -- write captured frames in PCAP format (LINKTYPE_SOCKETCAN = 227) for Wireshark analysis
  • Multiple export formats (--export json|csv|candump) with optional output file
  • Logging in candump-compatible format and structured JSON

Terminal UI (optional)

  • Interactive TUI (--tui) built with FTXUI -- compiled optionally with -DENABLE_TUI=ON
  • Top panel: live frame feed (scrolling, color-coded by type)
  • Left sidebar: arbitration ID list with frame counts and rates
  • Right panel: selected ID detail with decoded signals, entropy, timing
  • Bottom bar: total frames, bus load %, anomaly count, uptime
  • Status line: filter expression, interface name, recording status
  • Keyboard: q quit, p pause/resume, r reset stats, Up/Down select ID

Requirements

  • Linux with SocketCAN support (kernel 2.6.25+)
  • C++17 compiler (GCC 8+, Clang 7+)
  • CMake 3.14+
  • can-utils (optional, for testing with cansend/candump/cangen)
  • FTXUI (optional, fetched automatically when -DENABLE_TUI=ON)

Building

Without TUI (default)

mkdir build && cd build
cmake ..
make -j$(nproc)

With TUI

mkdir build && cd build
cmake .. -DENABLE_TUI=ON
make -j$(nproc)

FTXUI is downloaded automatically via CMake FetchContent. The tool compiles and works fully without FTXUI.

The binary is produced at build/canbus-sniffer.

Running tests

cd build
ctest --output-on-failure

SocketCAN setup

Physical CAN adapter

Most USB-CAN adapters (PEAK PCAN-USB, Kvaser Leaf, CANable) register as SocketCAN interfaces automatically:

sudo ip link set can0 up type can bitrate 500000

Virtual CAN (vcan) for testing

Create a virtual CAN interface for local development without hardware:

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

Usage

canbus-sniffer v2.1.0 [OPTIONS]

Interface & capture:
  -i, --interface <iface>      CAN interface (default: can0)
  -D, --duration <seconds>     Capture duration (0 = infinite, default: 0)
  -q, --quiet                  Suppress frame output to stdout
  -C, --no-color               Disable ANSI colored output

Protocol decoding:
  -d, --dbc <file>             Load DBC file for signal decoding
  -P, --protocol <mode>        Protocol mode: raw (default), j1939, obd2, uds

Filtering:
  -f, --filter <id[,id,...]>   Hardware filter by arbitration ID
  -F, --filter-expr <expr>     Software filter expression
                               e.g. "id=0x100-0x1FF,dlc>4"

Anomaly detection:
  -a, --detect-anomalies       Enable anomaly detection
      --learn <seconds>        Learning phase duration (default: 30)
      --flood-threshold <n>    Messages/sec per ID to flag as flood (default: 500)

Logging & export:
  -l, --log <file>             Log frames to file (candump format)
  -j, --json <file>            Log frames to file (JSON format)
      --pcap <file>            Write captured frames in PCAP format
      --export <format>        Export format: json, csv, candump
      --export-file <file>     Export output file (default: stdout)

Statistics & replay:
  -s, --stats                  Live statistics mode (refreshing display)
      --replay <file>          Replay a candump log file through the analyzer

Terminal UI:
      --tui                    Launch interactive terminal UI

  -h, --help                   Show this help

Examples

Basic capture on a virtual CAN interface:

./canbus-sniffer -i vcan0

J1939 heavy-duty vehicle bus decoding:

./canbus-sniffer -i can0 -P j1939 -a --learn 10

OBD-II diagnostic capture with filtering:

./canbus-sniffer -i can0 -P obd2 -F "id=0x7E0-0x7EF"

UDS diagnostic session monitoring:

./canbus-sniffer -i can0 -P uds -j diag_session.json

Capture with DBC decoding and PCAP export:

./canbus-sniffer -i can0 -d vehicle.dbc --pcap capture.pcap -l capture.log

Anomaly detection with live statistics:

./canbus-sniffer -i vcan0 -a --learn 10 -s

Replay a captured log through the J1939 decoder:

./canbus-sniffer --replay capture.log -P j1939 --export csv --export-file out.csv

Interactive terminal UI with anomaly detection:

./canbus-sniffer -i vcan0 --tui -a --learn 5

Time-limited capture for CI pipelines:

./canbus-sniffer -i vcan0 -D 60 -l test_capture.log -q

Filter expression syntax

filter = condition { ',' condition }
condition = field op value
          | 'id' '=' value '-' value     (range)

field = 'id' | 'dlc' | 'data[N]'
op    = '=' | '!=' | '<' | '<=' | '>' | '>='
value = hex (0x...) or decimal number

Examples:

id=0x100-0x1FF              # ID range filter
id=0x7DF,dlc>4              # Combined conditions
id=0x100,data[0]=0xFF       # Data byte filter
dlc<=4,id!=0x000            # Multiple conditions

Testing with vcan

In one terminal, start the sniffer in J1939 mode:

./canbus-sniffer -i vcan0 -P j1939 -a --learn 5 -s

In another terminal, send J1939 traffic:

# EEC1 (engine speed)
cansend vcan0 18F00400#00000080003E0000

# CCVS (vehicle speed)
cansend vcan0 18FEF100#0000500000000000

For OBD-II testing:

# Request engine RPM
cansend vcan0 7DF#0201010000000000

# Simulate RPM response (1726 rpm)
cansend vcan0 7E8#04410C1AF8000000

Architecture

src/
  main.cpp            Main entry point, CLI parsing, capture loop
  can_interface.h/cpp RAII SocketCAN wrapper
  frame_decoder.h/cpp DBC parser and signal extraction
  anomaly_detector.h/cpp  Learning/detection anomaly engine
  logger.h/cpp        Candump and JSON file logging
  j1939.h/cpp         J1939 PGN decoder with SPN database
  obd2.h/cpp          OBD-II Service 01 PID decoder
  uds.h/cpp           UDS service/DID/NRC decoder
  isotp.h/cpp         ISO-TP multi-frame reassembly engine
  statistics.h/cpp    Statistical analysis, entropy, timing, bus load
  pcap_writer.h/cpp   PCAP file writer (LINKTYPE_SOCKETCAN)
  filter_expr.h/cpp   Filter expression parser and evaluator
  tui.h               TUI controller interface (always available)
  tui.cpp             FTXUI implementation (compiled with -DENABLE_TUI=ON)
  tui_stub.cpp        Stub when FTXUI not available

tests/
  main_test.cpp       Hand-rolled test framework (no external deps)
  test_*.cpp          Unit tests for each module

DBC file format

The tool parses standard Vector DBC files. Minimal example:

BO_ 291 EngineData: 8 ECU
 SG_ EngineSpeed : 24|16@1+ (0.25,0) [0|16383.75] "rpm" Vector__XXX
 SG_ EngineTemp : 40|8@1+ (1,-40) [-40|215] "degC" Vector__XXX

BO_ 1024 BrakeStatus: 2 ABS
 SG_ BrakePedal : 0|8@1+ (0.392157,0) [0|100] "%" Vector__XXX

Security context

CAN bus networks in vehicles and industrial systems typically lack authentication and encryption. Common attack vectors include:

  • Spoofing -- injecting frames with forged arbitration IDs to impersonate ECUs
  • Replay attacks -- recording and retransmitting valid frame sequences
  • Bus flooding -- denial-of-service by saturating the bus at high priority
  • Fuzzing -- sending malformed frames to trigger undefined behavior in ECUs
  • Masquerade attacks -- timing-based impersonation where an attacker replaces a legitimate ECU
  • Bus-off attacks -- forcing error states to disconnect legitimate nodes
  • Diagnostic abuse -- unauthorized UDS sessions for firmware extraction or ECU reprogramming

canbus-sniffer helps security assessors establish a traffic baseline and detect these patterns during live assessments. It can also be deployed as a lightweight IDS on embedded Linux gateways.

FAQ

What does "decoding CAN frames" mean?

CAN bus is the internal communication network inside vehicles, robots, and industrial machines. Electronic Control Units (ECUs) send frames containing raw bytes — e.g., frame ID 0x0C0 with data 0B B8. Without decoding, you just see hex. With decoding (using a DBC file or protocol knowledge), you see: "Engine Speed: 3000 RPM".

canbus-sniffer captures these raw frames and translates them into human-readable values using J1939 (trucks/heavy equipment), OBD-II (cars), or UDS (diagnostics) protocol decoders.

What is a replay attack on CAN bus?

An attacker records legitimate CAN frames (e.g., "unlock doors") and replays them later. The vehicle/machine executes the command because CAN has no authentication — it cannot tell a replayed frame from a real one. canbus-sniffer detects replay attacks by tracking frame sequences and flagging duplicate patterns.

How is this used in practice?

# Set up virtual CAN for testing
sudo modprobe vcan && sudo ip link add dev vcan0 type vcan && sudo ip link set up vcan0

# Capture and decode J1939 traffic
canbus-sniffer --interface can0 --protocol j1939 --detect-anomalies --log capture.json

License

MIT -- see LICENSE.

Copyright (c) 2026 isecwire GmbH

About

CAN bus capture, multi-protocol decoder (J1939/OBD-II/UDS), and anomaly detector for automotive & industrial security audits.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages