BLE Mesh security research tool โ scan, capture, enumerate, fuzz, analyze firmware, check CVEs, generate reports.
Built for authorized testing on BLE Mesh deployments: industrial gateways, smart lighting controllers, sensor networks, and anything running SIG Mesh, Wirepas, Thread, or a custom BLE stack.
For authorized testing only. Do not use against systems you do not own or have written permission to test.
meshbreaker recon โ Scan nearby BLE devices, fingerprint the protocol
meshbreaker capture โ Passive listen: decode beacons, map the mesh topology
meshbreaker enumerate โ Connect to target, dump all GATT services + SDP
meshbreaker firmware โ Feed a binary: arch, RTOS, keys, credentials, URLs
meshbreaker fuzz โ Send malformed packets to GATT, L2CAP, SDP, or Mesh
meshbreaker cve-check โ Match kernel + BlueZ version against 46 known CVEs
meshbreaker report โ Export everything as Markdown, HTML, or JSON
Everything runs inside Docker โ no Python dependency hell, no distro-specific setup.
- Linux or Windows
- USB Bluetooth dongle โ for BLE commands (recon, fuzz, enumerate, capture)
- Python 3.10+ โ Windows only (Linux uses Docker, Python is inside the image)
Do not run
install.shwith sudo. The script calls sudo itself where needed. Running it as root breaks the user setup.
git clone https://github.com/NerdTIV/MeshBreaker
cd MeshBreaker
bash install.shinstall.sh will:
- Detect your package manager (apt, dnf, pacman, zypper...)
- Install Docker if missing โ uses sudo internally, you will be prompted for your password
- Add your user to the
dockergroup so you don't need sudo to run Docker - Build the image (~2 min, only once)
- Install a
meshbreakercommand in~/.local/bin
After install: log out and back in (or run newgrp docker) so the group change takes effect. Until you do, the wrapper falls back to sudo docker automatically โ it still works either way.
If meshbreaker is not found after relogging:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcgit clone https://github.com/NerdTIV/MeshBreaker
cd MeshBreaker
.\install.ps1install.ps1 does everything automatically โ no admin rights required:
- Looks for Python 3.10+. If missing, installs it via
winget(built into Windows 10/11) or Chocolatey if available. Falls back to a direct download link only if both fail. - Installs all Python dependencies
- Creates a
meshbreakercommand in your PATH
Restart your terminal after install.
What works on Windows:
| Command | Status |
|---|---|
recon, capture, enumerate |
โ via Windows BLE (WinRT) |
fuzz --type gatt |
โ |
firmware, cve-check, report, session |
โ |
fuzz --type l2cap / fuzz --type sdp |
โ raw BT sockets โ Linux only |
# Scan for BLE devices nearby (default 10 seconds)
meshbreaker recon
# Scan for longer and save a target
meshbreaker recon --time 30
# Scan and lock onto a specific MAC
meshbreaker recon -t AA:BB:CC:DD:EE:FF
# Save the target for all subsequent commands
meshbreaker set-target AA:BB:CC:DD:EE:FFrecon scans with the local BT adapter, decodes advertising data (AD types), and runs the protocol fingerprinter to identify whether the target is running SIG Mesh, Wirepas, Thread, or a proprietary BLE stack. Confidence score is shown for each match.
Example output:
14:22:03 [INF] BLE scan (15s, active)โฆ
14:22:18 [OK ] Scan complete โ 4 devices found
14:22:18 [INF] Protocol fingerprintingโฆ
โญโโโโโโโโโโโโโโโโโโโโ Protocol Identification โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ Protocol Confidence Evidence โ
โ SIG Mesh โโโโโโโโโโโโโโโโโโโโ 80% service UUID 1827; โ
โ service UUID 1828 โ
โ Wirepas โโโโโโโโโโโโโโโโโโโโ 35% company ID 0x0077 โ
โ Thread / OpenThread โโโโโโโโโโโโโโโโโโโโ 10% name match 'ot' โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
14:22:18 [TGT] Target: AA:BB:CC:DD:EE:FF RSSI -61 dBm (SolidSense-n6gsdl)
# Passive capture for 60 seconds
meshbreaker capture --duration 60
# Reload and decode an existing capture file
meshbreaker parse-capture output/capture_20250101_120000.jsoncapture listens passively โ no connection, nothing sent. Decodes BLE Mesh beacons (Secure Network Beacon, Unprovisioned Device Beacon) and builds a topology map: which nodes are provisioned, which are relays, which are proxies.
# Enumerate GATT services on target
meshbreaker enumerate
# Enumerate with a specific target
meshbreaker enumerate -t AA:BB:CC:DD:EE:FF
# Also run an SDP service browse (Bluetooth Classic)
meshbreaker enumerate --sdpConnects to the target and dumps all GATT services, characteristics, and descriptors. Reads values from readable characteristics. Highlights writable characteristics โ those are the attack surface for fuzzing. Also runs sdptool browse if --sdp is passed.
# Analyze a firmware binary
meshbreaker firmware /path/to/firmware.bin
# The path can be anywhere on your machine โ it gets mounted automatically
meshbreaker firmware ~/Downloads/router_fw_v2.3.1.binStatic analysis only โ no emulation, no execution. Detects:
- Format: ELF, raw binary, Intel HEX, gzip, SquashFS, U-Boot image, UF2, and more
- Architecture: ARM32, ARM64, MIPS, x86, RISC-V, Xtensa (ESP32), PowerPC, AVR, and more
- RTOS: FreeRTOS, Zephyr, VxWorks, ThreadX, mbed OS, BusyBox/Linux, and more
- SoC: nRF52/53, ESP32, STM32, TI CC26xx, EFR32, and more
- Secrets: AES keys (entropy scan), hardcoded passwords, private keys, BLE Mesh network keys, URLs, IP addresses
Example output:
14:23:11 [INF] Loaded: router_fw_v2.3.1.bin (4,194,304 bytes)
14:23:11 [INF] Format detected: elf
14:23:11 [INF] ELF 32 little-endian arch=arm32
14:23:11 [INF] Strings extracted: 2847
14:23:11 [OK ] RTOS detected: BusyBox / Embedded Linux
14:23:11 [OK ] SoC detected: NXP i.MX (score=3)
โญโโโโโโโโโโโโโโโโ Firmware Report โ router_fw_v2.3.1.bin โโโโโโโโโโโโโโโโโโโโโโฎ
โ Field Value โ
โ Path /firmware/router_fw_v2.3.1.bin โ
โ Size 4,194,304 bytes โ
โ Format elf โ
โ Architecture arm32 (little-endian) โ
โ RTOS BusyBox / Embedded Linux โ
โ SoC NXP i.MX โ
โ Encrypted No (entropy 4.31) โ
โ Compressed No โ
โ Strings 2847 โ
โ URLs 8 โ
โ IPs 3 โ
โ Credentials 2 โ
โ AES key candidates 0 โ
โ BLE Mesh keys 0 โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
14:23:12 [INF] URLs:
14:23:12 [INF] http://kapua.example.io/api/v1
14:23:12 [INF] mqtt://broker.example.io:1883
14:23:12 [WRN] Credentials found:
14:23:12 [WRN] admin:admin
14:23:12 [WRN] user:default123
14:23:12 [OK ] Analysis exported โ output/router_fw_v2.3.1_analysis.json
Results go to output/.
# Fuzz all GATT writable characteristics
meshbreaker fuzz --type gatt
# Fuzz L2CAP PSMs (common ones by default)
meshbreaker fuzz --type l2cap
# Fuzz specific L2CAP PSMs
meshbreaker fuzz --type l2cap --psm 1,3,5,7
# Fuzz SDP
meshbreaker fuzz --type sdp
# Fuzz BLE Mesh (proxy PDUs)
meshbreaker fuzz --type meshSends a set of crafted payloads per target. Payloads include: empty, max-size, all-zeros, all-0xFF, cyclic patterns (AAAB AAAC...), format string probes, malformed protocol headers. Crashes are flagged when the device resets or goes silent. Results go to output/.
Example output (GATT):
14:31:07 [INF] GATT fuzzer โ AA:BB:CC:DD:EE:FF
14:31:08 [OK ] Connected โ enumerating writable characteristicsโฆ
14:31:08 [INF] Fuzzing [0x0012] 0000ffe1-0000-1000-8000-00805f9b34fb (14 payloads)
14:31:09 [DBG] [00] 512B โ ACK
14:31:09 [DBG] [01] 512B โ ACK
14:31:10 [DBG] [02] 512B โ ACK
14:31:10 [DBG] [03] 4B โ ACK
14:31:11 [DBG] [04] 4B โ ACK
14:31:11 [DBG] [05] 4B โ ACK
14:31:12 [DBG] [06] 200B โ ACK
14:31:12 [WRN] [07] 0B โ CRASH: Disconnected: [org.bluez.Error.Failed]
14:31:12 [WRN] CRASH on handle 0x0012 len=0
14:31:12 [OK ] Fuzzing complete โ 8 payloads sent, 1 crash
# Check if BleedingTooth A2MP surface is reachable
meshbreaker exploit --method bleedingtooth
# Run SDP buffer overflow probe
meshbreaker exploit --method sdp-bof
# Run all exploit probes in sequence
meshbreaker exploit --method all
# Run a custom plugin
meshbreaker exploit --method plugin --plugin-name my_attack# Auto-detect from firmware analysis (run firmware first)
meshbreaker cve-check
# Override manually if you know the versions
meshbreaker cve-check --kernel 5.4.47 --bluez 5.72
# Add extra tags (protocols present on target)
meshbreaker cve-check --tags wirepas,kura,mqttIf you ran meshbreaker firmware first, the kernel and BlueZ versions are extracted automatically from the binary strings (Linux version X.X.X, bluetoothd X.X) and reused here โ no manual input needed.
If the firmware doesn't contain those strings (stripped binary, custom build), provide the versions manually. You can get them from:
- An SSH session on the device:
uname -randbluetoothd --version - An SDP or HTTP banner if exposed
- The device's documentation or release notes
Matches against a local CVE database (data/cve_db.json) covering BlueZ, Linux kernel BT stack, and SIG Mesh protocol weaknesses.
# Generate all formats
meshbreaker report --format all
# Markdown only
meshbreaker report --format md
# HTML (dark theme, self-contained)
meshbreaker report --format html
# Machine-readable JSON
meshbreaker report --format jsonAggregates all results from the current session into a structured report. Saved in output/reports/.
# Show current session (target, protocol, results summary)
meshbreaker session
# Set a target MAC (persists across commands)
meshbreaker set-target AA:BB:CC:DD:EE:FF
# Set a target IP (for network-based exploits)
meshbreaker set-ip 192.168.1.100Drop a .py file into src/plugins/ and it is automatically loaded at startup.
# src/plugins/my_attack.py
from src.core.plugin_base import PluginBase, PluginMeta
class MyAttack(PluginBase):
meta = PluginMeta(
name = "my_attack",
version = "1.0",
description = "My custom attack",
author = "T.I.V.",
category = "exploit", # recon | fuzz | exploit | post
)
def run(self) -> dict:
# self.target โ MAC address of the target
# self.adapter โ BT adapter in use (e.g. "hci0")
# self.session โ results from previous phases
# do your attack here
return {"result": "found something"}Run it:
meshbreaker exploit --method plugin --plugin-name my_attackThree ready-to-copy templates are in src/plugins/:
template_recon.pyโ passive info gatheringtemplate_firmware.pyโ firmware binary analysistemplate_mesh_attack.pyโ active attack over BLE Mesh Proxy
Files starting with template_ are skipped at load time. Rename yours.
output/
โโโ session.json โ current session state (target, results)
โโโ reports/
โโโ report_TIMESTAMP.md
โโโ report_TIMESTAMP.html โ dark-theme, self-contained
โโโ report_TIMESTAMP.json
meshbreaker: command not found
~/.local/bin is not in your PATH. Fix:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrcpermission denied while trying to connect to the Docker daemon
You haven't relogged since install. Either log out and back in, or run:
newgrp dockerAfter that, meshbreaker works without sudo.
No Bluetooth adapter found
Plug in a USB Bluetooth dongle โ internal laptop adapters don't pass through into Docker. Check the dongle is seen by the host:
hciconfigYou should see hci0 listed. If not, try sudo hciconfig hci0 up.
Permission denied on Bluetooth socket / BT errors inside the container
The Bluetooth service may not be running on the host. Start it:
sudo systemctl start bluetoothThis is the only time you need sudo after the initial install.
Output files owned by root Docker writes output as root. Fix permissions once:
sudo chown -R $USER:$USER output/Edit code locally without rebuilding the image on every change:
docker compose --profile dev run dev recon --time 10
docker compose --profile dev run dev firmware /firmware/fw.bin
# Mount a firmware directory
FIRMWARE_DIR=/path/to/firmwares docker compose --profile dev run dev firmware /firmware/fw.binRebuild after changes to requirements.txt or Dockerfile:
docker compose buildMIT. Use responsibly.
Built by T.I.V.