BLE Spam - Advertising packet flood

BLE Advertising Packets: How BLESpam Works at the Packet Level

BLE Advertising Packets: How BLESpam Works at the Packet Level

Your phone didn't get a popup asking to connect to AirPods it doesn't own because of a security vulnerability. It got that popup because it was working exactly as designed. Bluetooth Low Energy advertising is built around the idea that nearby devices broadcast their presence and capabilities to anyone who wants to listen. The problem is that nothing stops a device from broadcasting whatever it wants.

BLESpam - sending crafted BLE advertising packets that trigger popups on iOS, Android, and Windows - works because all three operating systems trust the content of advertising data from unverified sources. Understanding why requires understanding the structure of BLE advertising packets from the ground up.

BLE Advertising Basics

Classic Bluetooth uses frequency hopping across 79 channels. BLE uses 40 channels, each 2 MHz wide, spread across the 2.4 GHz band. Of these 40 channels, three are reserved specifically for advertising: channels 37, 38, and 39. These map to 2402 MHz, 2426 MHz, and 2480 MHz respectively - frequencies chosen to minimize overlap with the three most common WiFi channels (1, 6, 11).

When a BLE device wants to announce itself, it broadcasts advertising packets on channels 37, 38, and 39 in sequence. This is called an advertising event. Between advertising events, the device may sleep or do other work. Advertising intervals range from 20 ms (aggressive) to 10.24 seconds (power-saving). A device advertising at a 100 ms interval will be visible to any scanner within about half a second.

Any BLE device in scanner mode can receive advertising packets without any pairing, bonding, or prior relationship with the advertiser. Advertising is intentionally public. That's the design: devices announce themselves so other devices can discover them.

Advertising Packet Structure

At the physical layer, a BLE advertising packet looks like this:

[ Preamble   ] 1 byte  - alternating 01 pattern for clock recovery
[ Access Addr] 4 bytes - always 0x8E89BED6 for advertising channels
[ PDU        ] 2-257 bytes - Protocol Data Unit
[ CRC        ] 3 bytes - 24-bit CRC over PDU, using polynomial x^24+x^10+x^9+x^6+x^4+x^3+x+1

Preamble (1 byte): The preamble is 0x55 (for 0-bit access addresses) or 0xAA (for 1-bit access addresses). Its purpose is to allow the receiver's hardware to synchronize its clock and bit detection circuitry before the actual data arrives. You never see this in software - it's handled by the radio chipset.

Access Address (4 bytes): On advertising channels, the access address is always 0x8E89BED6 - a fixed value defined in the BLE specification. Every BLE device knows to listen for this address on channels 37, 38, and 39. For connection-oriented data channels, a unique random access address is negotiated per connection; this prevents one connection's traffic from interfering with another's. But advertising is always 0x8E89BED6.

PDU (2 to 257 bytes): The Protocol Data Unit contains the actual advertising content. This is where the interesting structure lives.

CRC (3 bytes): A 24-bit CRC that allows receivers to detect corrupted packets. Calculated over the PDU using a polynomial defined in the BLE specification, initialized to 0x555555. A packet with a bad CRC is discarded by the radio hardware. Any valid crafted packet must have a correctly computed CRC - which is trivially calculated by software.

graph LR
    subgraph LINK["Link Layer Packet"]
        PRE["Preamble
1 byte"] --> AA["Access Address
4 bytes
0x8E89BED6"] AA --> PDU["PDU"] PDU --> CRC["CRC
3 bytes"] end subgraph PDU_DETAIL["Advertising PDU"] HDR["Header
2 bytes
Type + Length"] --> ADVA["AdvA
6 bytes
Device address"] ADVA --> ADVDATA["AdvData
0-31 bytes
AD structures"] end PDU --> PDU_DETAIL

BLE advertising packet structure - the fixed access address 0x8E89BED6 identifies all advertising packets, and the PDU carries up to 31 bytes of advertisement data

PDU Types

The PDU type field (4 bits in the PDU header) specifies what kind of advertising the device is doing:

ADV_IND (0x00) - Connectable Undirected: The most common type. Device announces itself and indicates it accepts connection requests from any scanner. Used by most consumer BLE devices: headphones, fitness trackers, speakers.

ADV_DIRECT_IND (0x01) - Connectable Directed: Device announces itself but only accepts connection requests from a specific peer, whose address is included in the PDU. Used for fast reconnection to a known device.

ADV_NONCONN_IND (0x02) - Non-Connectable Undirected: Device broadcasts data but is not accepting connections. Beacons, iBeacons, Eddystone beacons, and BLESpam all use this type. The device is purely transmitting - it will not enter a connection state regardless of what it receives. This is the PDU type used for BLESpam.

ADV_SCAN_IND (0x06) - Scannable Undirected: Device accepts SCAN_REQ packets from scanners, allowing them to request additional data (SCAN_RSP) beyond what fits in the main advertising payload.

SCAN_REQ (0x03): Sent by a scanner to request additional data from an ADV_SCAN_IND advertiser.

SCAN_RSP (0x04): The response to a SCAN_REQ. Contains additional advertising data, up to 31 bytes.

BLESpam uses ADV_NONCONN_IND for two reasons: it requires no connection setup (reducing latency between transmissions), and it avoids any state that might interfere with the BLESpam device's mesh or management connection.

PDU Header

The PDU starts with a 2-byte header:

PDU Type (bits 3-0): The PDU type as described above.

RFU (bit 4): Reserved for Future Use. Must be 0. Receivers may ignore or reject packets with this set.

ChSel (bit 5): Channel Selection Algorithm bit. Indicates whether the advertiser supports the LE Channel Selection Algorithm #2 (introduced in BLE 5.0) for connection setup. Not relevant for ADV_NONCONN_IND.

TxAdd (bit 6): Transmitter Address type. 0 = the AdvA field contains a public (OUI-assigned) address. 1 = the AdvA field contains a random address. BLESpam sets this to 1 and uses a randomly generated AdvA to prevent the receiving device from filtering repeated messages from the same source address.

RxAdd (bit 7): Receiver Address type. Used only for directed advertising PDU types. 0 for ADV_NONCONN_IND.

Length (bits 15-8): Length of the PDU body in bytes, not including the 2-byte header. Maximum 37 bytes for advertising PDUs (6 bytes AdvA + 31 bytes AdvData maximum).

AdvA and AdvData Fields

AdvA (6 bytes): The advertiser's address. Can be a public (factory-assigned) address or a random address. BLE supports two types of random addresses:

  • Static random address: a random address that persists across power cycles. The top two bits are 11.
  • Resolvable private address (RPA): a rotating address derived from a device's Identity Resolving Key (IRK), used for privacy. The top two bits are 01. Devices with the IRK can resolve the rotating address to a stable identity; others can't track the device across advertising events.
  • Non-resolvable private address: a random address with no resolution mechanism. Top two bits are 00. Completely opaque to all observers.

BLESpam typically uses a randomly generated address in each advertising event (or rotates frequently) specifically so iOS and other operating systems treat each advertisement as coming from a new device. This prevents the OS from recognizing it as a recently-seen address and suppressing the popup.

AdvData (0-31 bytes): The advertising data payload. This is where device-specific information is encoded. It contains one or more AD (Advertising Data) structures.

AD Structures

AdvData is not a free-form field. It's a concatenation of AD structures, each with this format:

[ Length ] 1 byte  - number of bytes in the remainder of this AD structure (type + data)
[ AD Type] 1 byte  - identifies the type of data in this structure
[ Data   ] (Length - 1) bytes - the actual data

AD types are assigned by the Bluetooth SIG. Common ones:

0x01 - Flags: A bitfield indicating basic advertising capabilities. Common bits: LE General Discoverable Mode (bit 1), BR/EDR Not Supported (bit 2). Most BLE-only devices set this to 0x06 (General Discoverable, no classic Bluetooth).

0x02 / 0x03 - Incomplete/Complete List of 16-bit Service UUIDs: Services the device exposes. A device advertising a heart rate service includes the Heart Rate Service UUID (0x180D) here.

0x09 - Complete Local Name: The human-readable device name as UTF-8. This is what shows up as the device name in Bluetooth settings.

0x16 - Service Data - 16-bit UUID: Arbitrary data associated with a service UUID. Used by Google Fast Pair and other protocols to encode device-specific proximity information.

0xFF - Manufacturer Specific Data: Arbitrary data prefixed with a 2-byte company identifier assigned by the Bluetooth SIG. This is the field used by Apple (company ID 0x004C), Samsung (0x0075), Microsoft (0x0006), and many others. No standardization beyond the company ID - the rest of the bytes are interpreted by the receiving OS based on company ID.

How Apple Nearby Actions Works

When iOS sees an advertising packet with Manufacturer Specific Data using company ID 0x004C (Apple Inc.), it inspects the following bytes to determine what action to take. Apple's protocol is undocumented but has been reverse-engineered extensively.

The byte after the company ID is a subtype. Key subtypes:

  • 0x07: AirPods - triggers the AirPods connection popup
  • 0x09: Apple TV Pairing
  • 0x0A: Apple TV Setup
  • 0x0D: Apple Watch pairing
  • 0x0F: Nearby Action - general proximity notification, used for HomePod setup, Apple Vision Pro pairing, etc.
  • 0x10: AirPods Pro

For the Nearby Action type (0x0F), the following byte is an action code that determines what popup appears: setup for new device, transfer, pairing, etc.

iOS does not validate that the advertising device is actually an Apple product. It sees company ID 0x004C and the right payload structure, and it shows the popup. That's the entire trust model: matching bytes.

The popup is generated at the OS level, appears over any app, and sometimes persists until dismissed. For most of Apple's legitimate use cases (someone nearby having new AirPods), this UX is intentional. The advertising device is expected to be nearby and real.

How Samsung and Google Fast Pair Works

Android's Fast Pair protocol triggers similarly on specific Service Data patterns. The Fast Pair spec uses 16-bit service UUID 0xFE2C (or earlier, 0xFE2C is the Google-registered UUID for Fast Pair).

When Android sees an advertising packet containing Service Data for UUID 0xFE2C, it decodes the payload to identify the device model. Google maintains a registry of model IDs - these are 3-byte values that map to specific products (specific Pixel Buds SKUs, various third-party headphones that have licensed the Fast Pair spec). If the model ID is recognized, Android shows a popup with the device's name and image. If the model ID isn't recognized, it shows a generic "Device nearby" notification.

Samsung's Quick Pair uses Samsung's own company ID (0x0075) in Manufacturer Specific Data, with Samsung-specific byte patterns that trigger Samsung's own connection popup on Galaxy devices running One UI.

Neither Android nor Samsung validates that the advertising device is the actual hardware it claims to be. A packet with the right bytes looks identical to the real thing at the software layer.

How Windows Swift Pair Works

Microsoft's Swift Pair uses Manufacturer Specific Data with company ID 0x0006 (Microsoft). The payload structure starts with a Swift Pair subtype byte (0x03 for the proximity pairing scenario), followed by a display reason byte, followed by optionally a device name.

When Windows sees this pattern, it shows a toast notification at the bottom right of the screen: "New device found - [device name]" with a "Connect" button. The notification appears in the Action Center and can persist until dismissed or the advertising stops.

Unlike iOS popups, Windows Swift Pair notifications are less intrusive by default - they appear as toast notifications rather than full-screen modals. But on devices with notifications enabled and the Bluetooth service running, they are visible.

BLESpam on BLEShark Nano

The BLEShark Nano implements BLESpam using a dedicated mode that crafts ADV_NONCONN_IND packets with precisely structured Manufacturer Specific Data and Service Data payloads targeting each OS.

iOS mode: Cycles through Apple Nearby Actions subtypes: AirPods, AirPods Pro, Apple TV setup, Apple Watch pairing, Nearby Action variants. Each advertisement uses a freshly randomized AdvA (TxAdd = 1, non-resolvable private address) to prevent iOS from recognizing and suppressing repeated frames from the same source. The broadcast interval is tuned to saturate iOS popup generation without overloading the radio.

Android mode: Broadcasts Fast Pair payloads using UUID 0xFE2C with a rotating selection of known and unknown model IDs. Known model IDs trigger named device popups. Unknown model IDs trigger generic "Device nearby" notifications. Samsung Quick Pair payloads (company ID 0x0075) are also included for maximum Galaxy device coverage.

Windows mode: Broadcasts Swift Pair payloads (company ID 0x0006, subtype 0x03) with varying device names. The device name field in the Swift Pair payload is what appears in the toast notification - BLEShark Nano can cycle through a list of plausible device names.

All mode: Interleaves all three targeting modes, cycling through iOS, Android, and Windows payloads in sequence. Each advertising event uses the appropriate payload for one OS. This is less efficient per-OS than a dedicated mode but works in environments with mixed device types.

In all modes, the packet construction is done at the raw PDU level: the BLEShark Nano's radio is programmed with the correct preamble, access address, PDU type bits, AdvA, AdvData with properly formatted AD structures (correct Length/Type/Data fields, correctly computed CRC). The result is indistinguishable from a legitimate device at the radio and packet level because it follows the same specification.

BLESpam is a research and demonstration tool. Its purpose is to help security researchers understand proximity-based attack surfaces, test organizational policies around Bluetooth advertising, and demonstrate why proximity-triggered UI interactions deserve scrutiny from a security standpoint. Running BLESpam in a crowded public space without authorization is not a security test - it's just disruptive. Use it in controlled environments where you own or have permission to test the targets.

Shiver Mesh: BLESpam Across Multiple Nodes

A single BLEShark Nano broadcasting BLESpam reaches devices within its radio range - maybe 10-30 meters in typical indoor conditions. For testing how an organization's device fleet responds to proximity attacks across a larger space (a whole floor of an office, for example), a single node has obvious limitations.

Shiver mesh enables coordinated BLESpam across multiple BLEShark Nano units. Each node operates its BLE radio for BLESpam advertising during its allocated radio windows, then briefly switches to the mesh channel to sync status and receive updated configuration. Because BLE radio switching is fast (on the order of microseconds to milliseconds), the gap in BLESpam advertising is imperceptible to target devices.

Nodes can be assigned different modes (one doing iOS, one doing Android, one doing All) or all running the same mode for saturation testing. The mesh coordinator tracks which nodes are active and provides a unified view of advertising activity across all nodes.

From a research perspective, multi-node BLESpam lets you answer questions that single-node testing can't: Does an organization's MDM policy suppress Bluetooth proximity popups fleet-wide? Are there physical locations in the building where BLE advertising penetrates unexpectedly (through glass, across elevator shafts)? How do different device generations within the same OS respond to the same advertising payloads?

Why This Matters

BLE advertising is designed to be trustworthy-looking by necessity. Devices need to announce their capabilities before any secure channel exists. The consequence is that operating system UI that reacts to nearby advertising data - popups, notifications, pairing prompts - is reacting to unverified broadcast data from anonymous sources.

Apple, Google, and Microsoft have all improved their proximity-triggered UI over time, adding thresholds (some popups only show if the advertising device has been in range for some minimum time), rate limiting (suppressing repeated popups from the same address), and RSSI filtering (ignoring weak signals). But the fundamental architecture - OS UI triggered by structurally correct advertising bytes from unauthenticated sources - remains intact.

Understanding the packet structure is the starting point for understanding the attack surface. If you're responsible for securing an environment with mixed BLE-capable devices, BLESpam testing helps you understand what your users would actually see and experience if someone ran this against your organization.

BLEShark Nano is designed for authorized security research and educational use. BLESpam testing should only be performed in environments where you have authorization to test the affected devices.

Get BLEShark Nano - $36.99+

Back to blog

Leave a comment