English | 中文
A BLE (Bluetooth Low Energy) link-layer relay attack tool using MQTT for long-range, cross-network communication. Built on top of the Sniffle BLE sniffer framework.
Traditional BLE relay attacks require both relay nodes to be on the same local network (TCP direct connection). This tool overcomes that limitation by using an MQTT broker as the transport layer, enabling relay attacks across the internet — from anywhere to anywhere.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Phone/Central │◄──BLE──►│ relay_peripheral │ │ │
│ (e.g., App) │ │ (Phone-side) │ │ MQTT Broker │
└──────────────────┘ │ + Sniffle Board │◄──MQTT──► (Public Server) │
└──────────────────┘ │ │
└────────┬─────────┘
│ MQTT
┌──────────────────┐ │
│ relay_central │◄─────────────────┘
│ (Device-side) │
│ + Sniffle Board │◄──BLE──►┌──────────────────┐
└──────────────────┘ │ BLE Peripheral │
│ (e.g., Car PKE) │
└──────────────────┘
- Device-side (
relay_central.py) scans and captures the target peripheral's ADV_IND + SCAN_RSP - Captured advertisement data is published to the MQTT broker (with retain flag)
- Peripheral-side (
relay_peripheral.py) subscribes to MQTT, receives the advertisement, and clones the target's BLE identity - The peripheral-side starts advertising, waiting for the legitimate central (phone) to connect
- When the phone connects, the CONNECT_IND is forwarded via MQTT to the device-side
- The device-side uses the CONNECT_IND parameters to establish a real BLE connection to the peripheral
- All subsequent link-layer data PDUs are bidirectionally relayed through MQTT
- 2× TI CC1352/CC2652 development boards (e.g., LAUNCHXL-CC1352R1 or LAUNCHXL-CC26X2R1) flashed with Sniffle firmware
- USB cables for connecting boards to computers
You need a publicly accessible MQTT broker. Options:
-
Self-hosted Mosquitto (recommended):
# On your VPS/cloud server sudo apt install mosquitto mosquitto-clients sudo systemctl enable --now mosquitto
-
Cloud MQTT services: EMQX Cloud, HiveMQ Cloud, etc.
⚠️ For security research only. Ensure proper authentication on production MQTT brokers.
git clone https://github.com/yourname/RelayonMQTT.git
cd RelayonMQTT
pip install -r requirements.txtpython relay_central.py -B <MQTT_BROKER_IP> -t <TARGET_MAC> -s <SERIAL_PORT>Example:
python relay_central.py -B mqtt.example.com -t C6:07:59:15:53:5F -s /dev/ttyACM0python relay_peripheral.py -B <MQTT_BROKER_IP> -s <SERIAL_PORT>Example:
python relay_peripheral.py -B mqtt.example.com -s /dev/ttyACM1Note: Thanks to MQTT retained messages, the startup order does not matter. The device-side relay publishes advertisement data with the retain flag, so the peripheral-side relay will receive it even if it starts later.
| Option | Description | Default |
|---|---|---|
-B, --broker |
MQTT broker address (required) | — |
-P, --mqtt-port |
MQTT broker port | 1883 |
-t, --target |
Target BLE MAC address (required) | — |
-s, --serport |
Sniffle serial port | auto-detect |
-o, --output |
PCAP output file | none |
-q, --quiet |
Suppress per-packet output | false |
--pub-topic |
MQTT publish topic | /ble_relay/to_phone |
--sub-topic |
MQTT subscribe topic | /ble_relay/to_device |
| Option | Description | Default |
|---|---|---|
-B, --broker |
MQTT broker address (required) | — |
-P, --mqtt-port |
MQTT broker port | 1883 |
-s, --serport |
Sniffle serial port | auto-detect |
-o, --output |
PCAP output file | none |
-q, --quiet |
Suppress per-packet output | false |
--pub-topic |
MQTT publish topic | /ble_relay/to_device |
--sub-topic |
MQTT subscribe topic | /ble_relay/to_phone |
Messages exchanged between relay nodes use a simple text protocol over MQTT:
| Prefix | Direction | Description |
|---|---|---|
adv:<hex> |
Device → Peripheral | Full ADV_IND PDU body |
rsp:<hex> |
Device → Peripheral | Full SCAN_RSP PDU body |
con:<hex> |
Peripheral → Device | CONNECT_IND PDU body |
dat:<event_hex>:<pdu_hex> |
Bidirectional | Data PDU with event counter |
Both relay scripts support PCAP output (-o flag) for offline analysis in Wireshark:
# Device-side with capture
python relay_central.py -B broker.example.com -t AA:BB:CC:DD:EE:FF -s /dev/ttyACM0 -o device_capture.pcapng
# Peripheral-side with capture
python relay_peripheral.py -B broker.example.com -s /dev/ttyACM1 -o peripheral_capture.pcapng| Symptom | Likely Cause | Fix |
|---|---|---|
| "Waiting for advertisement data..." hangs | Device-side not running or broker unreachable | Check broker connectivity; start device-side first |
| Peripheral-side never sees phone connect | Phone not in range, or advertisement data incorrect | Ensure phone BLE scanning is active; check target MAC |
| "HW packet error" messages | Sniffle firmware issue or USB disconnect | Reconnect board, re-flash firmware |
| Serial port "resource busy" on Linux | ModemManager is probing the serial device | sudo systemctl stop ModemManager && sudo systemctl disable ModemManager |
| High latency / dropped packets | Network latency to broker | Use broker geographically close to both nodes |
- Only supports legacy advertising (ADV_IND + SCAN_RSP), not extended advertising
- Relay latency depends on network round-trip to MQTT broker
- Does not handle BLE encryption (attacker must relay before pairing/bonding)
- Single connection at a time
- Sniffle by Sultan Qasim Khan (NCC Group) — BLE sniffer framework
- MQTT transport concept for extending BLE relay range beyond local networks
This project is licensed under the GNU General Public License v3.0 — see LICENSE for details.
This is a derivative work based on Sniffle (GPLv3).
This tool is intended for authorized security research and testing only. Users are responsible for complying with all applicable laws. Do not use this tool against systems you do not own or have explicit written permission to test.