THREAT-BLEBeacon-AdvertisingChannelExfil Elastic Security · Elastic

Detect Covert Data Exfiltration via Bluetooth LE Advertising Packet Encoding (Beacon Stuffing) in Elastic Security

Bluetooth Low Energy advertising packets (the broadcast frames used by beacons such as iBeacon/Eddystone) can carry up to 31 bytes of arbitrary manufacturer-specific data and are transmitted connectionlessly — no pairing, no GATT session, and no bonding ever occurs. An adversary or insider with a foothold on a Linux host (or an Android/embedded device) can encode staged data directly into the advertising payload using raw HCI commands (`hcitool cmd 0x08 0x0008`/`0x0006`, `btmgmt add-adv`) or a scripting library (bleak, bluepy, pybluez, gatttool) and repeatedly rewrite that payload at a fixed interval, effectively trickling data out a few dozen bytes at a time to any passive scanner within radio range — a phone, SBC, or dedicated receiver carried past the facility. This is a materially different exfiltration mechanism from the existing T1011.001 coverage on this platform (THREAT-Bluetooth-AirGapCourierExfil), which keys on a policy-disabled Bluetooth service being re-enabled and a subsequent OBEX file transfer following device pairing. The advertising-channel variant requires none of that: it needs no pairing, no bonding, no established connection, and can run on a host where Bluetooth was never disabled by policy in the first place (routine peripheral use), making the pairing/OBEX-based detection blind to it entirely. The reliable discriminator is process lineage and cadence rather than protocol state: legitimate BLE beacon deployments (retail/asset-tracking beacons) are configured once via a vendor daemon or systemd-managed service and left static, whereas advertising-based exfiltration requires the same low-level CLI tool or script to repeatedly re-issue the advertising-data-set command with a changing payload in a short window — a pattern with essentially no benign equivalent outside of BLE development/testing.

MITRE ATT&CK

Tactic
Exfiltration

Elastic Detection Query

Elastic Security (Elastic)
eql
process where host.os.family == "linux" and event.type == "start" and (
  (process.name in ("hcitool", "btmgmt") and process.command_line : ("*0x0008*", "*0x0006*", "*add-adv*", "*advertise*")) or
  (process.name in ("python", "python3") and process.command_line : ("*bleak*", "*bluepy*", "*pybluez*", "*gatttool*") and process.command_line : ("*advertis*", "*adv_data*"))
)
medium severity medium confidence

Detects connectionless BLE advertising-channel exfiltration using Elastic Endpoint (Auditbeat/Elastic Agent) process events. Matches raw HCI advertising-data-set commands via hcitool/btmgmt and Python BLE-library invocations with advertising-related arguments. Pair with a terms aggregation on host.name/user.name over a short time bucket to reconstruct the repeated-invocation frequency signal.

Data Sources

Elastic Endpoint Security (Linux)Auditbeat (auditd module)

Required Tables

logs-endpoint.events.process-*auditbeat-*

False Positives & Tuning

  • BLE developers/QA repeatedly testing advertising payloads during active development
  • Beacon fleet management software intentionally rotating advertising payloads on a schedule
  • Authorized red team BLE covert-channel testing as part of an approved engagement

Other platforms for THREAT-BLEBeacon-AdvertisingChannelExfil


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Set Custom BLE Advertising Data via Raw HCI Command

    Expected signal: auditd EXECVE record for hcitool with 'cmd 0x08 0x0008' in argv and the hex advertising payload as trailing arguments. BlueZ bluetoothd/btmon capture (if enabled) showing the HCI_LE_Set_Advertising_Data command.

  2. Test 2Repeatedly Rewrite Advertising Payload to Simulate Data Trickle

    Expected signal: Ten sequential auditd EXECVE records for hcitool within roughly 50 seconds, each with a distinct hex payload in argv.

  3. Test 3Advertise Custom Payload via Python BLE Library (bleak)

    Expected signal: auditd EXECVE record for python3 with '-c' and the inline script referencing bleak and 'advertis' in the command line.


Response Playbook

Triage

  1. Confirm whether the host is expected to run any legitimate BLE beacon or advertising workload — check for a known vendor beacon-management daemon or systemd unit; if none exists, treat direct CLI/script advertising invocation as anomalous.
  2. Pull the full set of ProcessCommandLine/a0 values captured across the flagged invocations and attempt to decode any hex-encoded advertising payload fields (manufacturer-specific data, service data) for recognizable plaintext, base64, or structured data.
  3. Identify the account and interactive/remote session active on the host during the window — is this a known developer or automation account, or an unexpected session?
  4. Check whether the host has an unusually high number of distinct advertising-payload rewrites in a short window versus its historical baseline (a fixed beacon rarely if ever changes payload after initial configuration).
  5. Review DeviceFileEvents (or auditd file-open records) immediately preceding the advertising activity for access to sensitive files, credential stores, or archive creation that could be the source of the staged data.
  6. Check physical proximity/scanning logs if available (facility BLE scanners, mobile device management BLE inventory) for any newly observed nearby BLE receiver during the activity window.

Containment

  1. Terminate the offending process and, if the host has no legitimate BLE workload, disable the Bluetooth adapter/service (`rfkill block bluetooth` or `systemctl stop bluetooth`) pending investigation.
  2. Isolate the host from the network via EDR if the data being encoded is confirmed sensitive, since the exfiltration channel itself bypasses network-based controls entirely.
  3. Revoke or rotate any credentials/tokens found decoded from the captured advertising payloads.
  4. If tied to an interactive user session, coordinate with HR/Legal before personnel action if insider activity is suspected.

Evidence Collection

  1. Full auditd EXECVE records (argv) for every hcitool/btmgmt/python invocation in the flagged window, including exact advertising-payload hex strings
  2. BlueZ D-Bus advertising registration logs (`btmon` capture or `bluetoothd` debug log) if collected, showing the LE Set Advertising Data HCI command sequence
  3. Process ancestry for the flagged CLI/script invocation (parent shell, script file path, and any preceding file access to a staged data source)
  4. Host BLE adapter presence/state history (rfkill status, `hciconfig` output) to establish whether BLE was expected to be active on this asset class

Escalation Criteria

  • !The host is in a segment designated air-gapped, classified, isolated OT/ICS, or otherwise prohibited from having an active BLE radio by policy
  • !Decoded advertising payload content includes recognizable credentials, PII, or proprietary source/data fragments
  • !The invocation pattern spans multiple hosts, suggesting a coordinated or repeated exfiltration operation rather than isolated development/testing activity
  • !No legitimate BLE workload, change ticket, or documented exception exists for the flagged host

Investigation Guide

Related Techniques

Forensic Artifacts

  • >auditd EXECVE records (/var/log/audit/audit.log) for hcitool/btmgmt/python process invocations with full argv, including the hex advertising payload
  • >BlueZ bluetoothd logs and `btmon`/`hcidump` captures (if enabled) showing the raw HCI LE Set Advertising Data command sequence and payload history
  • >Shell history (~/.bash_history, ~/.zsh_history) or script files referencing hcitool, btmgmt, bleak, bluepy, or gatttool
  • >rfkill and systemd unit state history establishing whether the Bluetooth adapter was expected to be active/inactive on this asset class
  • >Any staged data file referenced immediately prior to the advertising loop in file-access or auditd logs

Tuning Guidance

This detection is highest-value on asset classes that should never run a BLE advertising workload at all (general-purpose servers, hardened workstations, OT/ICS endpoints) — apply the invocation-count threshold loosely there since even a single occurrence is worth reviewing. On hosts with legitimate BLE development or beacon-management functions, raise the InvocationCount/window thresholds and maintain an allowlist keyed on the specific host/service account combination rather than the tool name, since hcitool/btmgmt/bleak are also the standard legitimate tooling for that exact workload. Where available, cross-reference facility BLE scanning logs or MDM BLE device inventories to corroborate that a receiving device was actually present during the flagged window, which meaningfully raises confidence beyond the process-telemetry signal alone.


Hunting Queries

30-day hunt across the fleet for any host invoking BLE advertising CLI tools or scripting libraries at all, regardless of frequency — establishes a baseline of expected BLE development/beacon-management hosts to allowlist and surfaces any asset class (particularly hardened or air-gapped tiers) where this activity has no legitimate explanation.

Hunting — KQL
kql
DeviceProcessEvents
| where Timestamp > ago(30d)
| where DeviceOS =~ "Linux"
| where FileName in~ ("hcitool", "btmgmt", "python", "python3")
| where ProcessCommandLine has_any ("cmd 0x08 0x0008", "add-adv", "advertise", "bleak", "bluepy", "pybluez", "gatttool")
| summarize Executions = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp), Commands = make_set(ProcessCommandLine, 20)
    by DeviceName, AccountName, FileName
| where Executions >= 3
| sort by Executions desc
Hunting — SPL
spl
index=linux sourcetype="linux:audit" type=EXECVE exe IN ("*/hcitool","*/btmgmt","*/python","*/python3")
  (a0="*0x0008*" OR a0="*add-adv*" OR a0="*advertise*" OR a0="*bleak*" OR a0="*bluepy*" OR a0="*pybluez*" OR a0="*gatttool*")
| stats count as Executions, values(a0) as Args by host, uid, exe
| where Executions >= 3
| sort - Executions

Atomic Red Team Tests

Test 1 Set Custom BLE Advertising Data via Raw HCI Command
linux

Simulates encoding data into a BLE advertising payload using a raw HCI command via hcitool, the core mechanism of connectionless advertising-channel exfiltration.

Command

bash
sudo hciconfig hci0 up && sudo hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 74 65 73 74 64 61 74 61 30 30 30 31 00 00 00 00 C5 00

Cleanup

bash
sudo hcitool -i hci0 cmd 0x08 0x000A 00 2>/dev/null; sudo hciconfig hci0 down 2>/dev/null || true

Expected Telemetry

auditd EXECVE record for hcitool with 'cmd 0x08 0x0008' in argv and the hex advertising payload as trailing arguments. BlueZ bluetoothd/btmon capture (if enabled) showing the HCI_LE_Set_Advertising_Data command.

Expected Detection

KQL/SPL RawHciAdvertisingCommand signal fires on the hcitool invocation matching 'cmd 0x08 0x0008'.

Test 2 Repeatedly Rewrite Advertising Payload to Simulate Data Trickle
linux

Loops the raw HCI advertising-data-set command with a changing payload to simulate trickling staged data out over multiple advertising intervals, the frequency signature this detection keys on.

Command

bash
for i in $(seq 1 10); do sudo hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 $(printf '%02x' $i)$(printf '%02x' $i)000000000000000000000000000000 C5 00; sleep 5; done

Cleanup

bash
sudo hcitool -i hci0 cmd 0x08 0x000A 00 2>/dev/null; sudo hciconfig hci0 down 2>/dev/null || true

Expected Telemetry

Ten sequential auditd EXECVE records for hcitool within roughly 50 seconds, each with a distinct hex payload in argv.

Expected Detection

KQL/SPL aggregation stage fires once InvocationCount reaches the 8-invocation threshold within the 10-minute window, flagging the DeviceName/AccountName pair.

Test 3 Advertise Custom Payload via Python BLE Library (bleak)
linux

Simulates a scripted, library-driven variant of the same technique using the bleak BLE library instead of raw hcitool commands, reflecting a more common real-world implementation approach.

Command

bash
python3 -c "import asyncio; from bleak import BleakScanner; print('bleak advertis_data simulation: set_advertising_data test-payload-0001')"

Cleanup

bash
true

Expected Telemetry

auditd EXECVE record for python3 with '-c' and the inline script referencing bleak and 'advertis' in the command line.

Expected Detection

KQL/SPL ScriptedBleAdvertising signal fires on the python3 invocation matching a BLE script marker (bleak) combined with an advertising-related keyword.

Related Detections

Detection Variants (1)

Different telemetry and tradecraft for the same technique — pick the one that matches the data you collect.