courses

Bluetooth: Classic and Low Energy

Why this matters

“Bluetooth” names two protocols that share a band, a brand, and almost nothing else. Bluetooth Classic (BR/EDR) is a cable replacement for streaming audio and serial data. Bluetooth Low Energy is a different radio, a different link layer, and a different data model, designed for devices that wake up, say one thing, and go back to sleep for an hour.

Nearly everything in IoT is LE. Nearly every audio device is Classic. Plenty of devices do both, and — as you will see under Cross-transport key derivation — supporting both is itself a vulnerability class.

What makes Bluetooth worth a week of attention is that it is the one radio on a device you can usually reach from a phone in your pocket, with no special hardware, while the device sits in someone’s house. The bar for reconnaissance is zero.

The radio layer

Both variants live in the 2.4 GHz ISM band alongside WiFi, Zigbee and Thread, and both hop to survive it. How they hop is the main practical difference for anyone trying to listen.

  Bluetooth Classic (BR/EDR) Bluetooth LE
Channels 79 × 1 MHz 40 × 2 MHz
Hopping FHSS, 1600 hops/s Adaptive, one hop per connection event
Modulation GFSK (1 Mb/s); π/4-DQPSK, 8DPSK for EDR GFSK
PHYs BR, EDR 2/3 Mb/s 1M, 2M, Coded (S=2, S=8)
Discovery Inquiry / page Advertising on 37, 38, 39
Typical power Class 2, ~2.5 mW ~1 mW, duty-cycled to microamps

Classic hops 1600 times a second across 79 channels in a pseudorandom sequence derived from the master’s clock and address. Following that without already knowing those parameters is genuinely hard, and it is why sniffing Classic is a specialist activity while sniffing LE is a $10 problem.

LE splits its 40 channels into three advertising channels and 37 data channels. Channels 37, 38 and 39 are deliberately placed in the gaps between the common WiFi channels 1, 6 and 11 — a nice piece of spectrum diplomacy, and the reason advertising works at all in a crowded flat.

LE Coded PHY trades data rate for range using forward error correction (S=2 gives 500 kb/s, S=8 gives 125 kb/s at roughly four times the range). It is worth knowing about because a device that seems out of range may simply be advertising on a PHY your scanner is not configured for.

Listening to it

The critical asymmetry: advertisements are trivial to capture, connections are not. An advertiser transmits on three fixed channels with no pairing, no connection, and no access control. Anything with a BLE radio can hear it.

Once a connection forms, the two ends agree a hop increment and start moving. To follow, a sniffer must catch the CONNECT_IND packet that sets up the hop sequence — which means being present at the moment of connection.

Tool Captures Notes
Phone (nRF Connect, LightBlue) Advertisements, GATT Zero cost, no connection sniffing
bluetoothctl + btmon Host-side HCI Sees your own traffic, not third parties
nRF52840 dongle + Sniffle LE connections Cheap, follows connections and Coded PHY
Nordic nRF Sniffer firmware LE connections Wireshark plugin, vendor-supported
Ubertooth One LE, partial Classic Older; still the usual answer for BR/EDR
SDR Raw IQ Demodulating GFSK is work; hopping is more work

⚠️ btmon is not a sniffer. It traces the HCI interface between your host and your own Bluetooth controller. It is excellent for understanding what your stack is doing — and it shows you nothing about a conversation between two other devices. Students conflate these constantly.

Bluetooth LE: the data model

Once connected, LE exposes everything through GATT, built on ATT. The structure is a shallow hierarchy that amounts to a key-value store with permissions:

Service (UUID 0x180F, Battery Service)
 └── Characteristic (UUID 0x2A19, Battery Level)
      ├── Properties: Read, Notify
      ├── Value: 0x4B
      └── Descriptor (0x2902, Client Characteristic Configuration)

Enumerating GATT gives you the device’s entire control API. Vendors expose custom 128-bit UUID services for their own functions — firmware update, factory reset, unlock, configuration — and the characteristic properties tell you which are writable. There is no equivalent of a hidden endpoint: the attribute table is discoverable by design.

Three properties matter when triaging:

Worked example: enumerating a device from the command line

$ bluetoothctl
Agent registered
[bluetooth]# scan on
Discovery started
[NEW] Device A4:CF:12:34:56:78 AL-2100-Gateway
[CHG] Device A4:CF:12:34:56:78 ManufacturerData Key: 0x02E5
[CHG] Device A4:CF:12:34:56:78 ManufacturerData Value: 01 04 2b 00 3f
[bluetooth]# connect A4:CF:12:34:56:78
Attempting to connect to A4:CF:12:34:56:78
Connection successful
[AL-2100-Gateway]# menu gatt
[AL-2100-Gateway]# list-attributes
Primary Service (Handle 0x000a)
        /org/bluez/hci0/dev_A4_CF_12_34_56_78/service0009
        0000180f-0000-1000-8000-00805f9b34fb
        Battery Service
Characteristic (Handle 0x000c)
        .../service0009/char000a
        00002a19-0000-1000-8000-00805f9b34fb
        Battery Level
Primary Service (Handle 0x0010)
        .../service000f
        6e400001-b5a3-f393-e0a9-e50e24dcca9e
        Vendor specific

That last UUID is the Nordic UART Service — a serial port over BLE. Finding it on a device usually means there is a text command interface behind it, and it is the first thing to poke:

[AL-2100-Gateway]# select-attribute 6e400002-b5a3-f393-e0a9-e50e24dcca9e
[AL-2100-Gateway:...]# write "0x76 0x65 0x72 0x0a"
Attempting to write ...
[CHG] Attribute .../char0013 Value: 41 4c 2d 32 31 30 30 20 76 31 2e 34 0a

The device answered AL-2100 v1.4 to a ver\n written with no authentication at all.

⚠️ hcitool and gatttool are deprecated and missing from current BlueZ builds. Tutorials using hcitool lescan are stale; use bluetoothctl, btmgmt, or a Python library such as Bleak for scripted work.

Pairing is where the security is

Both transports have the same shape of problem: the cryptography is sound and the association model is chosen by the device, which usually chooses the weakest one.

Model User action MITM protection
Just Works None None
Passkey Entry Type a 6-digit code Yes
Numeric Comparison Compare two displayed numbers Yes
Out of Band NFC tap, QR, etc. Yes (depends on channel)

Just Works is the default for anything without a display or keyboard — which is most IoT. It performs the full ECDH exchange, so it resists passive eavesdropping, but an active attacker in the middle completes a pairing with each side and neither can detect it.

The generational split also matters:

Classic follows the same arc: legacy PIN pairing, then Secure Simple Pairing (2.1) using P-192, then Secure Connections (4.1) using P-256 with a stronger key derivation.

Identity and privacy

LE devices may use Resolvable Private Addresses that rotate every 15 minutes, resolvable only by a peer holding the IRK exchanged at pairing. Done properly this defeats long-term tracking.

Done in practice: an enormous number of devices advertise a static public address forever, or rotate the address while leaving a constant, unique value in the manufacturer-specific data — which makes the rotation decorative. Check for this; it is a straightforward privacy finding and easy to demonstrate.

Known attack families

These are worth knowing by name because you will meet them in vendor advisories and because they illustrate distinct failure modes.

KNOB (Key Negotiation of Bluetooth, 2019) — the BR/EDR encryption key entropy is negotiated in the clear and unauthenticated, and the specification permitted as little as one byte. An attacker forces both sides to 1 byte and brute-forces the key in real time. Fixed by enforcing a minimum key length; verify the device enforces it rather than trusting the version number.

BIAS (Bluetooth Impersonation AttackS, 2020) — the legacy authentication procedure is unidirectional, so an attacker can impersonate a previously paired device without the link key, and can claim not to support Secure Connections to force the weaker path. Combined with KNOB it becomes a full MITM.

BLURtooth — see below.

BLUFFS (2023) — attacks forward and future secrecy by manipulating session key derivation so that the same key is reused across sessions, letting one compromised session decrypt others.

SweynTooth / BrakTooth — not protocol flaws but families of implementation bugs in specific vendors’ SoC stacks, causing crashes, deadlocks and occasional code execution from malformed packets. These matter more than the protocol attacks for practical IoT work, because a crash that reboots a lock is a security event.

Stealtooth (2025) — abuses silent automatic pairing behaviours to establish a pairing without any user interaction or indication.

Cross-transport key derivation

CTKD lets a dual-mode device pair once and derive keys for both transports. BLURtooth exploits it: where CTKD is unauthenticated, an attacker pairs over the weaker transport and overwrites the existing, stronger key on the other one — downgrading or replacing an authenticated relationship.

The general lesson is the one that recurs across this whole course: the weak path in a system with two paths sets the security level of both, and convenience features that link them are where it happens. Compare WPA3 transition mode and Z-Wave’s S2-to-S0 downgrade.

Where the specification is now

The Bluetooth SIG moved to a twice-yearly cadence with Core 6.x. Version 6.0 (August 2024) introduced Channel Sounding, which provides cryptographically verified distance measurement — a direct answer to relay attacks on proximity-unlock systems, where an attacker tunnels the radio exchange between a key fob indoors and a car outside. Core 6.2 (December 2025) added amplitude-based attack resilience to Channel Sounding, and Core 6.3 (May 2026) is current.

The security relevance: proximity has historically been inferred from signal strength, which an attacker controls with an amplifier. Channel Sounding measures it. Whether the device in front of you uses it is a separate question, and the answer for anything already deployed is no.

Key takeaways

References


Related course pages: Radio Protocols · WiFi · Thread and Matter · Other IoT radios · Attacks · Tools of the Trade

🛠️ Maintenance note: the Bluetooth SIG now ships twice a year, so the “current version” paragraph needs a check every offering — 6.3 was current as of mid-2026. BlueZ’s deprecation of hcitool/gatttool is complete in current distributions but half the tutorials online still use them; re-verify the bluetoothctl transcript against the installed BlueZ before lab. Sniffle and the Nordic sniffer both track nRF SDK releases and occasionally need firmware reflashing after a host-tool update.