Skip to content

circle-rd/vandal-ctf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vandal CTF β€” Firmware

Vulnerable-by-design multi-protocol security testing platform built on two stacked ESP32-C6 boards.

The master board transmits intentionally weak payloads across 8 communication protocols. The slave board receives, decodes, and reports everything back to a web dashboard served by the master.


✨ Features

Protocol Transport Vulnerability by Design
UART GPIO16 ↔ GPIO17, 115 200 baud Plain-text serial, no framing
IΒ²C SDA GPIO22 / SCL GPIO23, 100 kHz Unencrypted bus, fixed slave address 0x28
SPI MOSI 18 / MISO 20 / SCLK 19 / CS 21, 1 MHz No authentication on the bus
ESP-NOW WiFi broadcast, channel 1 Broadcast MAC, no encryption
BLE Open GATT service 0000aa00-… Characteristic readable without pairing
BLE Auth GATT service 0000bb00-… Static 6-digit PIN (001234), Legacy Pairing
Thread IEEE 802.15.4, channel 15, PAN 0xFACE Well-known network key, UDP multicast
HTTP WiFi TCP port 80 Payload in plaintext over open SoftAP

System Monitoring

The master exposes a GET /system endpoint returning real-time telemetry:

  • Heap usage (total / free / min-free)
  • Internal temperature (Β°C)
  • Uptime, FreeRTOS task count
  • ESP-IDF version
  • Per-protocol running state & custom payload

On-Demand Protocol Control

The master boots with WiFi AP + HTTP server only. Each protocol is started or stopped at runtime through the web dashboard (POST /control). Heavy initializations (OpenThread, NimBLE) run in dedicated FreeRTOS tasks so the HTTP server stays responsive.

Custom Payloads

Each protocol's payload can be overridden from the dashboard (POST /payload). Clear the value to revert to the auto-generated default.


🎯 Vandal Capabilities

Each CTF service maps to a specific capability in the Vandal security analysis platform. The table below shows which Vandal command or module targets each service.

CTF Service Vandal Module / Command What to Demonstrate
UART Passive serial capture / protocol analysis Plain-text payload recovery
IΒ²C IΒ²C bus monitor / logic analyser Unencrypted sensor data capture
SPI SPI bus capture No-auth bus snooping
ESP-NOW esp_now sniffer (WiFi monitor mode) Broadcast frame capture, no encryption
BLE Open bt_scanner (GATT enumeration) Discover open characteristic, read flag without pairing
BLE Auth bt_probe_start (PIN dictionary attack) Identify PASSKEY_REQUIRED class, crack PIN 001234 via dictionary, read protected characteristic
Thread Roadmap β€” OpenThread network analysis Capture 802.15.4 frames, known network key extraction
HTTP wifi_sniffer (probe capture) + HTTP sniff Intercept HTTP payload on open WiFi

BLE Auth β€” Vandal workflow

bt_probe_start targets=[<slave_mac>] pins=["0000","1234","001234"]
  β†’ preflight: BT_AUTH_CLASS_PASSKEY_REQUIRED
  β†’ dictionary attempt "001234" β†’ pairing_success: true
  β†’ post-pairing: bt_write or GATT read on service 0000bb00-…

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ MASTER ────────────────────────┐
β”‚  WiFi AP ("Vandal CTF")                           β”‚
β”‚  HTTP Server (port 80)                            β”‚
β”‚    β”œβ”€ GET  /            β†’ React SPA (FATFS)       β”‚
β”‚    β”œβ”€ GET  /status      β†’ merged payload report   β”‚
β”‚    β”œβ”€ GET  /system      β†’ system telemetry        β”‚
β”‚    β”œβ”€ POST /control     β†’ start/stop protocol     β”‚
β”‚    β”œβ”€ POST /payload     β†’ custom payload          β”‚
β”‚    β”œβ”€ POST /messages    β†’ slave JSON report       β”‚
β”‚    └─ POST /http-payloadβ†’ HTTP service endpoint   β”‚
β”‚                                                   β”‚
β”‚  Protocol TX (on demand, 8 services)              β”‚
β”‚  UART Β· IΒ²C Β· SPI Β· ESP-NOW Β· BLE Β· Thread Β· HTTP β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        wired + wireless
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   SLAVE                           β”‚
β”‚  All RX modules started at boot                  β”‚
β”‚  Event bus β†’ HTTP Client POST to master          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow

Master TX event
  β†’ esp_event_post(VANDAL_EVT_PAYLOAD_RECEIVED)
  β†’ master_payload_event_handler() updates s_master_payloads[]
  β†’ GET /status returns merged view (master + slave data)

Slave RX event
  β†’ http_event_handler() stores in s_payloads[]
  β†’ POST /messages every 5 s to master
  β†’ messages_post_handler() updates s_last_report
  β†’ GET /status merges s_last_report with s_master_payloads[]

Component Map

components/
β”œβ”€β”€ vandal_common/   # Types, event bus, payload generator, running-state API
β”œβ”€β”€ vandal_wifi/     # SoftAP (master) + STA (slave) setup
β”œβ”€β”€ vandal_http/     # HTTP server (master) / HTTP client (slave)
β”œβ”€β”€ vandal_uart/     # UART1 master TX / slave RX
β”œβ”€β”€ vandal_i2c/      # IΒ²C master write / slave v2 driver
β”œβ”€β”€ vandal_spi/      # SPI master TX / slave RX
β”œβ”€β”€ vandal_espnow/   # ESP-NOW broadcast TX / RX
β”œβ”€β”€ vandal_ble/      # NimBLE GATT server (master) / client (slave)
└── vandal_thread/   # OpenThread FTD, UDP multicast TX / RX

πŸ“‹ Prerequisites

Tool Version
ESP-IDF v5.5.2
Target ESP32-C6
pnpm β‰₯ 10 (for the React dashboard build)

The dashboard is pre-built in the website/ folder. You only need pnpm if you want to modify the React source (see vandal-monitor).


πŸš€ Build & Flash

# 1. Source the ESP-IDF environment
source ~/.espressif/v5.5.2/esp-idf/export.sh

# 2. Configure the role (default = MASTER)
idf.py menuconfig
#   β†’ Vandal CTF Configuration β†’ Board role β†’ Master / Slave

# 3. Build
idf.py build

# 4. Flash (USB Serial/JTAG)
idf.py -p /dev/ttyACM0 flash

# 5. Monitor
idf.py -p /dev/ttyACM0 monitor

Important: Erase NVS before first deployment (or after changing Thread network credentials) to avoid stale OpenThread datasets:

idf.py -p /dev/ttyACM0 erase-flash && idf.py -p /dev/ttyACM0 flash

Tip: Flash the master first, then change the role to Slave, rebuild, and flash the second board.

Partition Layout

Name Type Offset Size
nvs NVS 0x9000 24 KB
phy_init PHY 0xF000 4 KB
factory App 0x10000 3 MB
website FAT 0x310000 960 KB

The website partition is auto-generated from the website/ directory at build time via fatfs_create_spiflash_image().


βš™οΈ Configuration (KConfig)

All tunables are under Vandal CTF Configuration in menuconfig:

Menu Key Options
Board role Master / Slave
UART TX/RX pins, baud rate
IΒ²C SDA/SCL pins, slave address, clock
SPI MOSI/MISO/SCLK/CS pins, clock speed
ESP-NOW Channel, primary master key
BLE Service UUIDs, PIN, device name
WiFi AP SSID, password, channel, max connections
HTTP Port, master IP, slave POST interval
General Payload send interval, LED GPIO

Default Pin Mapping (ESP32-C6 DevKitC-1)

Function GPIO
UART TX / RX 16 / 17
IΒ²C SDA / SCL 22 / 23
SPI MOSI / MISO / SCLK / CS 18 / 20 / 19 / 21
User LED 15
Console USB Serial/JTAG (native)

πŸ”Œ HTTP API

All JSON endpoints. CORS enabled (Access-Control-Allow-Origin: *).

GET /status

Returns a merged view: slave-received payloads from POST /messages merged with any master-originated payloads (Thread TX, HTTP TX self-reported via the event bus).

{
  "UART":     "VANDAL payload #0042 sent through UART",
  "I2C":      "VANDAL payload #0042 sent through I2C",
  "SPI":      null,
  "ESP-NOW":  "VANDAL payload #0042 sent through ESP-NOW",
  "BLE-OPEN": "VANDAL payload #0042 sent through BLE-OPEN",
  "BLE-AUTH": "VANDAL payload #0042 sent through BLE-AUTH",
  "Thread":   "VANDAL payload #0042 sent through Thread",
  "HTTP":     "VANDAL payload #0042 sent through HTTP"
}

GET /system

{
  "heap_total": 327680,
  "heap_free": 215040,
  "heap_min_free": 198000,
  "temperature": 32.5,
  "uptime_s": 1234,
  "task_count": 14,
  "idf_version": "v5.5.2",
  "protocols": {
    "UART":     { "running": true,  "custom_payload": null },
    "BLE-AUTH": { "running": true,  "custom_payload": null },
    "Thread":   { "running": false, "custom_payload": null },
    ...
  }
}

POST /control

{ "protocol": "Thread", "action": "start" }

Response: { "status": "ok", "protocol": "Thread", "running": true }

POST /payload

{ "protocol": "UART", "payload": "MY-CUSTOM-DATA" }

Send "payload": null or "" to clear.


πŸ“ Project Structure

vandal-ctf/
β”œβ”€β”€ CMakeLists.txt          # Top-level project file
β”œβ”€β”€ partitions.csv          # Custom partition table
β”œβ”€β”€ sdkconfig.defaults      # Default KConfig values
β”œβ”€β”€ main/
β”‚   β”œβ”€β”€ main.c              # Entry point & boot orchestration
β”‚   β”œβ”€β”€ Kconfig.projbuild   # All KConfig menus
β”‚   └── CMakeLists.txt
β”œβ”€β”€ components/             # Modular protocol drivers (see above)
└── website/                # Pre-built React dashboard (FATFS image)

πŸ“œ License

Educational / security research project β€” vulnerable by design. Do not deploy in production.

About

Micro CTF platform for VANDAL project

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages