Was ist Bluetooth Low Energy (BLE)?
Bluetooth Low Energy (BLE) ist ein Protokoll, das von vielen modernen Geräten verwendet wird. Der wesentliche Unterschied zu herkömmlichem Bluetooth besteht darin, dass BLE auf einen geringeren Energieverbrauch ausgelegt ist, während eine vergleichbare Kommunikationsreichweite beibehalten wird.
Dies wird durch die Implementierung einer Always-Off-Technologie erreicht, bei der Daten ausschließlich in kurzen Übertragungen gesendet werden, wenn dies erforderlich ist. BLE nutzt das ISM-Frequenzband (2,4 GHz) mit 40 Kanälen, wobei drei dieser Kanäle für das Advertising verwendet werden.
Bevor wir mit dem Hacking starten, werfen wir einen Blick auf die Grundlagen von BLE – denn nur wer das System versteht, kann es auch effektiv angreifen.
Central und Peripheral
Stellen wir uns vor, wir haben gerade einen modernen Fitness-Tracker erworben, der auch eine iOS- oder Android-App für unser Smartphone bereitstellt. Wenn wir den Tracker beispielsweise zur Messung unserer Herzfrequenz verwenden, kommuniziert er direkt mit der App, die dann die Daten anzeigt. Dies ist ein typisches Beispiel für BLE-Kommunikation, bei der Daten von einem Gerät zu einem anderen gesendet werden. Diese Geräte bezeichnet man üblicherweise als Peripheral (sendend) und Central (empfangend). Peripherals sind meist kleine, energiesparende Geräte, die sich mit leistungsfähigeren Centrals verbinden können.
Advertising
Der Tracker (Peripheral) sendet in regelmäßigen Abständen von X Millisekunden (definiert durch ein Advertising-Intervall) Advertising-Daten aus, die von einem Central-Gerät erkannt werden können. Wenn das Central-Gerät bereit ist, diese Datenpakete zu empfangen, antwortet es mit einer Scan-Response-Anfrage.
In unserem Beispiel scannt die App auf unserem Smartphone nach der spezifischen MAC-Adresse unseres Trackers, die höchstwahrscheinlich bereits in die App selbst einprogrammiert wurde. Sobald der Tracker gefunden wird, sendet die App eine Response-Anfrage zurück.
Die Advertising-Daten beinhalten verschiedene Informationen wie den Gerätenamen, TX-Powerlevel, eine ID oder verfügbare Services.
Funktionsweise von BLE
Untersuchen wir nun die Funktionsweise des BLE-Protokolls, indem wir die verschiedenen Schichten betrachten, aus denen es besteht. Das gesamte Protokoll lässt sich in folgende Schichten und Unterprotokolle aufteilen:

Generic Access Profile (GAP)
Das GAP implementiert den zuvor besprochenen Advertising-Prozess. Es ist außerdem dafür verantwortlich, die Rollen der Geräte in der BLE-Kommunikation zu definieren. Bei den Rollen unterscheidet man zwischen: Broadcaster, Observer, Peripheral und Central. Je nach Verbindungstyp – Broadcast (Eins-zu-viele) oder Unicast (Eins-zu-eins) – werden den Geräten diese Rollen zugewiesen. Peripheral und Central werden im Unicast verwendet, Broadcaster und Observer im Broadcast.
Generic Attribute Protocol (GATT)
Ein weiteres essentielles Unterprotokoll ist GATT. Dieses Protokoll definiert, wie zwei BLE-Geräte Daten miteinander austauschen. Dieser Datenaustausch beginnt, nachdem der Advertising-Prozess (GAP) abgeschlossen wurde. Das Kernkonzept des Datenaustauschs basiert dabei auf sogenannten Characteristics und Services.
Characteristics
Eine Characteristic lässt sich vereinfacht als grundlegender "API-Endpunkt" verstehen, beispielsweise:
GET /tracker/heart_rate
Geräte können darauf zugreifen und sie aufrufen, um Daten zu lesen (READ), zu schreiben (WRITE) oder auf Aktualisierungen (NOTIFY) zu hören. Im BLE-Kontext werden diese "API-Endpunkte" allerdings häufig nicht in aussagekräftige Bezeichnungen wie
GET /tracker/heart_rate
übersetzt, sondern erscheinen als UUID wie
AAE28F0071B534ABCF182F...
Wenn wir eine solche UUID sehen, können wir in der Regel davon ausgehen, dass es sich um eine vom Hersteller individuell erstellte Characteristic handelt. Zu Beginn einer Verbindung tauschen die Geräte eine Reihe von Characteristics und den Service-Namen aus. Auf diese Weise kann das Central-Gerät den Service identifizieren.
Das Besondere an BLE ist, dass die meisten Geräte standardmäßig so konfiguriert sind, dass sie Verbindungen von jedem Gerät akzeptieren, ohne dass vorher ein Pairing oder Bonding erforderlich ist. Dies ermöglicht uns die Interaktion mit dem Gerät und das Abrufen der Services und Characteristics. Allerdings können diese auch so konfiguriert werden, dass sie ein Pairing oder Bonding erfordern – dazu später mehr.
Services
Ein Service ist einfach eine Bündelung verschiedener Characteristics. Übertragen auf unser "API-Endpunkt"-Beispiel könnte man sich den Pfad
/tracker/
vorstellen, der verschiedene Funktionalitäten wie
/heart_rate
zusammenfasst. Diese Bündelung von Characteristics erfolgt typischerweise auf logische Weise, wie wir es am Beispiel des Trackers mit der zugehörigen Herzfrequenz-Funktion gesehen haben.
Einfache Angriffe auf BLE
Voraussetzungen
Für das Hacken von Protokollen wie Bluetooth, WiFi, Zigbee und anderen ist in der Regel spezielle Hardware erforderlich. Für den Einstieg in BLE-Hacking empfehlen wir den nRF52840 Dongle. Dieses Gerät kostet zwischen 10 und 20 Euro und unterstützt verschiedene Protokolle. Es wird mit bereits kompilierten Programmen wie einem BLE-Sniffer und weiteren nützlichen Werkzeugen ausgeliefert.
Enumeration
Zunächst überprüfen wir mittels hci
-Tools, ob die gewünschte Schnittstelle auf unserem PC erkannt wird. HCI (Host Controller Interface) wird zwischen der Controller- und Host-Schicht des BLE-Stacks verwendet.
❯ hciconfig
hci1: Type: Primary Bus: USB
BD Address: 5C:F3:70:XX:XX:XX ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING
RX bytes:1414 acl:0 sco:0 events:84 errors:0
TX bytes:4689 acl:0 sco:0 commands:69 errors:0
hci0: Type: Primary Bus: USB
BD Address: D8:80:83:XX:XX:XX ACL MTU: 1021:6 SCO MTU: 240:8
UP RUNNING
RX bytes:3551738 acl:1126 sco:636 events:436453 errors:2
TX bytes:363080346 acl:422502 sco:362 commands:2761 errors:0
Als nächstes führen wir einen ersten einfachen LE-Scan durch, um die Geräte in unserer Umgebung zu identifizieren:
❯ sudo hcitool lescan
LE Scan ...
38:18:4C:24:30:3E LE_WH-1000XM3
38:18:4C:XX:XX:XX (unknown)
...
Für dieses Beispiel verwenden wir die gefundenen Kopfhörer (LE_WH-1000XM3). Sobald die MAC-Adresse des gewünschten Geräts gefunden wurde, können wir mit der Aufzählung der Services und Characteristics mittels bettercap fortfahren.
❯ sudo bettercap --eval "ble.recon on"
BLE » ble.show
┌─────────┬───────────────────┬───────────────┬────────────────────────────────────────────┬──────────────────────────────────────────────┬─────────┬──────────┐
│ RSSI ▴ │ MAC │ Name │ Vendor │ Flags │ Connect │ Seen │
├─────────┼───────────────────┼───────────────┼────────────────────────────────────────────┼──────────────────────────────────────────────┼─────────┼──────────┤
│ -74 dBm │ 38:18:4c:24:30:3e │ LE_WH-1000XM3 │ Sony Home Entertainment&Sound Products Inc │ │ ✔ │ 01:41:39 │
...
In der Tabelle können wir anhand des "Connect"-Feldes (✔
) noch einmal erkennen, dass dieses Gerät eine Verbindung ohne vorheriges Pairing oder Bonding erlaubt.
BLE » ble.enum 38:18:4c:24:30:3e
[01:47:26] [sys.log] [inf] ble.recon connecting to 38:18:4c:24:30:3e ...
BLE »
┌──────────────┬──────────────────────────────────────┬─────────────────────┬─────────────────────────┐
│ Handles │ Service > Characteristics │ Properties │ Data │
├──────────────┼──────────────────────────────────────┼─────────────────────┼─────────────────────────┤
│ 0001 -> 0004 │ Generic Attribute (1801) │ │ │
│ 0003 │ Service Changed (2a05) │ INDICATE │ │
│ │ │ │ │
│ 0005 -> 0009 │ Generic Access (1800) │ │ │
│ 0007 │ Device Name (2a00) │ READ │ LE_WH-1000XM3 │
│ 0009 │ Appearance (2a01) │ READ │ Unknown │
│ │ │ │ │
│ 000a -> 0011 │ 69a7f243e52f4443a7f9cb4d053c74d6 │ │ │
│ 000c │ be8692b13b29410d94d350281940553e │ WRITE │ │
│ 000e │ 3f92019dac1d48dc9d9486a0fb507591 │ READ │ │
│ 0011 │ 5bc06a57f84d4086a65a2a238cb39cdb │ READ, WRITE │ insufficient encryption │
│ │ │ │ │
│ 0012 -> 001e │ fe59bfa87fe34a059d9499fadc69faff │ │ │
│ 0014 │ 104c022e48d64dd28737f8ac5489c5d4 │ WRITE │ │
│ 0016 │ 69745240ec294899a2a8cf78fd214303 │ NOTIFY │ │
│ 0019 │ 70efdf0043754a9e912d63522566d947 │ NOTIFY │ │
│ 001c │ eea2e8a089f04985a1e2d91dc4a52632 │ READ │ 02 │
│ 001e │ a79e2bd1d6e44d1e8b4f141d69011cbb │ WRITE │ │
│ │ │ │ │
│ 001f -> 002b │ 91c10d9caaef42bdb6d68a648c19213d │ │ │
│ 0021 │ 99d1064e451746aa8fb46be64dd1a1f1 │ READ, WRITE, NOTIFY │ insufficient encryption │
│ 0024 │ fbe87f6c3f1a44b6b5770bac731f6e85 │ WRITE, NOTIFY │ │
│ 0027 │ 420791c0bff54bd1b957371614031136 │ WRITE, NOTIFY │ │
│ 002a │ e4ef5a4630f94287a3e7643066acb768 │ WRITE, NOTIFY │ │
│ │ │ │ │
│ 002c -> 0031 │ fe03 │ │ │
│ 002e │ f04eb177300543a7ac61a390ddf83076 │ WRITE │ │
│ 0030 │ 2beea05b18794bb48a2f72641f82420b │ READ, NOTIFY │ insufficient encryption │
│ │ │ │ │
│ 0032 -> 0039 │ 5b833e056bc748028e9a723ceca4bd8f │ │ │
│ 0034 │ 5b833c116bc748028e9a723ceca4bd8f │ WRITE │ │
│ 0036 │ 5b833c136bc748028e9a723ceca4bd8f │ NOTIFY │ │
│ 0039 │ 5b833c146bc748028e9a723ceca4bd8f │ READ │ WH-1000XM3 │
│ │ │ │ │
│ 003a -> ffff │ 5b833e066bc748028e9a723ceca4bd8f │ │ │
│ 003c │ 5b833c106bc748028e9a723ceca4bd8f │ WRITE │ │
│ 003e │ 5b833c126bc748028e9a723ceca4bd8f │ NOTIFY │ │
│ │ │ │ │
└──────────────┴──────────────────────────────────────┴─────────────────────┴─────────────────────────┘
Die erste Zeile erscheint als eine "Gruppierung" der darunter aufgeführten UUIDs. Wenn wir uns an die vorherigen Abschnitte erinnern, handelt es sich hierbei um die Services. Unter jedem Service finden wir die einzelnen Characteristics mit ihren Eigenschaften (READ, WRITE, NOTIFY) sowie die Daten, die bettercap automatisch für uns ausliest und anzeigt. Zusätzlich sehen wir die Speicheradressen, an denen die Daten abgelegt sind, die als Handles bezeichnet werden.
│ 0005 -> 0009 │ Generic Access (1800) │ │ │
│ 0007 │ Device Name (2a00) │ READ │ LE_WH-1000XM3 │
│ 0009 │ Appearance (2a01) │ READ │ Unknown │
Hierbei ist es wichtig zu beachten, dass die Speicheradressen lückenlos aufeinanderfolgen sollten, beispielsweise
[0001 -> 0004] -> [0005 -> 0009]
und so weiter. Lücken zwischen den Handles könnten auf verborgene Services hinweisen. Desweiteren können wir sehen, dass einige dieser Handles eine Form von Pairing oder Bonding erfordern, was durch den Hinweis
insufficient encryption
angezeigt wird.
Bei erneuter Betrachtung der Tabelle fällt auf, dass viele der Services und Characteristics individuell implementiert wurden und lediglich als UUID dargestellt werden. Für eine potenzielle Analyse des Geräts wäre es erforderlich, die tatsächliche Funktionalität hinter jeder UUID zu kennen. Dies erfordert Reverse Engineering der einzelnen Characteristics, beispielsweise durch Untersuchung und Experimentieren mit dem Datenverkehr in Wireshark. Diese komplexe Thematik würde jedoch den Rahmen dieses Blogartikels sprengen.
Lesen und Schreiben von Daten
Wie bereits ersichtlich wurde, liest und zeigt bettercap automatisch die Daten aus READ-Eigenschaften an. Es besteht jedoch auch die Möglichkeit, Daten manuell von einem spezifischen Handle auszulesen.
❯ sudo gatttool -b 38:18:4c:24:30:3e --char-read -a 0x0039 | awk -F: '{print $2}' | xxd -r -p;printf '\n'
WH-1000XM3
Das Schreiben von Daten in einen Handle erfolgt auf ähnliche Weise. Da wir die Characteristics noch nicht durch Reverse Engineering analysiert haben, müssen wir allerdings den vom Gerät erwarteten Datentyp abschätzen. Wir können jedoch den --listen
-Parameter verwenden, der möglicherweise über die NOTIFY-Eigenschaft innerhalb des Service zusätzliche Informationen liefert.
# String schreiben wird abgelehnt
❯ sudo gatttool -b 38:18:4c:24:30:3e --char-write-req -a 0x0034 -n $(echo -n "test" | xxd -ps) --listen
Characteristic Write Request failed: Attribute value length is invalid
# Ein byte schreiben wird akzeptiert und liefert einen wert über NOTIFY
❯ sudo gatttool -b 38:18:4c:24:30:3e --char-write-req -a 0x0034 -n 00 --listen
Characteristic value was written successfully
Notification handle = 0x0036 value: 01
❯ sudo gatttool -b 38:18:4c:24:30:3e --char-write-req -a 0x0034 -n 01 --listen
Characteristic value was written successfully
Notification handle = 0x0036 value: 00
Notify
Services and characteristics - Nordic Developer Academy
Gelegentlich empfangen wir trotz vorhandener Notify-Eigenschaft keine Daten von einer Characteristic über den --listen
-Befehl. In solchen Fällen ist es möglicherweise erforderlich, den Client Characteristic Configuration Descriptor (CCCD) zu konfigurieren, damit der Server weiß, dass wir Benachrichtigungen oder Indikationen erhalten möchten.
Der CCCD ist ein spezieller Descriptor-Typ, der es einem Client ermöglicht, Updates für eine Characteristic zu abonnieren, die serverseitig initiierte Operationen unterstützt (das heißt Notifications oder Indications). In unserem Fitness-Tracker-Beispiel kann das Smartphone den CCCD nutzen, um die Herzfrequenzmessungs-Characteristic zu abonnieren und automatisch Updates zu erhalten, anstatt die Daten aktiv abfragen zu müssen.
nRF Connect
Eine wesentlich einfachere Alternative zur manuellen Methode bietet der zuvor empfohlene nRF Dongle mittels nRF Connect app. Die Anwendung stellt verschiedene Programme zur Verfügung, darunter auch BLE-spezifische Tools.
Wir erhalten die gleichen Ergebnisse durch einfaches Klicken auf "Start scan" und den entsprechenden "Connect"-Button. Die Software liest, ähnlich wie bettercap, automatisch die Daten aus READ-Eigenschaften aus, sofern dies möglich ist.
Das Tool bietet somit eine benutzerfreundliche grafische Oberfläche für die BLE-Analyse, die die komplexe Befehlszeilensyntax überflüssig macht. Diese Automatisierung und visuelle Darstellung ermöglicht auch weniger erfahrenen Nutzern einen einfachen Einstieg in die BLE-Analyse, während gleichzeitig die gleiche Funktionalität wie bei den manuellen Methoden gewährleistet ist.
Das Schreiben von Daten und das Aktivieren von Benachrichtigungen ist ebenfalls durch einfaches Klicken eines Buttons oder die Eingabe von Werten möglich. Die Software bietet allerdings nicht die automatische Dekodierung der Bytes von 57 48 2D..
zu WH-1000XM3
, wie wir es bei bettercap gesehen haben.
│ 0039 │ 5b833c146bc748028e9a723ceca4bd8f │ READ │ WH-1000XM3 │
Zusammenfassung
In diesem Artikel haben wir uns eingehend mit den grundlegenden Aspekten von BLE und dessen Funktionsweise beschäftigt. Wir begannen mit der Untersuchung der wesentlichen Unterschiede zwischen BLE und klassischem Bluetooth, wobei wir die energieeffiziente Kommunikation von BLE und dessen einzigartigen Advertising-Mechanismus hervorgehoben haben. Wir haben zentrale BLE-Komponenten wie GAP und GATT analysiert und gezeigt, wie sie für das Advertising, das Verbindungsmanagement und den Datenaustausch über Services und Characteristics genutzt werden.
Anschließend wendeten wir uns den praktischen Aspekten des BLE-Hackings zu. Anhand von Werkzeugen wie bettercap und gatttool demonstrierten wir, wie sich BLE-Geräte in der Umgebung aufspüren, ihre Services untersuchen und mit ihren Characteristics interagieren lassen – sei es durch Lesen, Schreiben oder das Aktivieren von Benachrichtigungen. Dabei wurde deutlich, dass viele Geräte keine ausreichenden Sicherheitsmechanismen nutzen, was unautorisierte Zugriffe ermöglicht.

Max Randhahn
Max ist ein engagierter Penetration Tester und verfügt über eine umfassende Erfahrung in der Identifizierung und Ausnutzung von Schwachstellen.