
Bluetooth-Low-Energy-Scanner (BLE) mit Auflösung von Resolvable Private Addresses (RPA) mithilfe von Identity Resolving Keys (IRKs)
Ein Bluetooth-Low-Energy-Scanner (BLE) mit fortschrittlicher Auflösung von Resolvable Private Addresses (RPA). Entdecken Sie BLE-Geräte in der Nähe, verfolgen Sie ein bestimmtes Gerät anhand seiner MAC-Adresse oder lösen Sie aus Datenschutzgründen randomisierte Adressen mithilfe eines Identity Resolving Keys (IRK) auf.
Geschrieben von: David Kennedy (@HackingDave) Firma: TrustedSec
-o -)Die GPS-Standortmarkierung erfordert den laufenden gpsd-Daemon mit einem angeschlossenen GPS-Empfänger. Wenn gpsd nicht läuft, setzt btrpa-scan den Betrieb normal ohne GPS fort.
Um zu überprüfen, ob gpsd funktioniert:
# Check that gpsd is listening
gpspipe -w -n 5
# Or use the curses monitor
cgps
Dieses Projekt verwendet pyproject.toml (PEP 621), den modernen Python-Packaging-Standard. Es definiert das Projekt als installierbares Paket mit einem registrierten CLI-Befehl – es ist nicht nötig, .py-Dateien direkt auszuführen.
uvx btrpa-scan --all
uvx --from git+https://github.com/hackingdave/btrpa-scan.git btrpa-scan --all
uv tool install btrpa-scan
Oder direkt von GitHub:
uv tool install git+https://github.com/hackingdave/btrpa-scan.git
pip install btrpa-scan
Für GUI-Unterstützung (Flask-basierte Radarschnittstelle):
pip install btrpa-scan[gui]
git clone https://github.com/hackingdave/btrpa-scan.git
cd btrpa-scan
pip install .
usage: btrpa-scan [-h] [-a] [--irk HEX] [--irk-file PATH] [-t TIMEOUT]
[--output {csv,json,jsonl}] [-o FILE] [--log FILE]
[-v | -q] [--min-rssi DBM] [--rssi-window N] [--active]
[--environment {free_space,indoor,outdoor}]
[--ref-rssi DBM] [--name-filter PATTERN]
[--alert-within METERS] [--tui] [--gui] [--gui-port PORT]
[--no-gps] [--adapters LIST] [mac]
BLE Scanner — discover all devices or hunt for a specific one
positional arguments:
mac Target MAC address to search for (omit to scan all)
optional arguments:
-h, --help show this help message and exit
-a, --all Scan for all broadcasting devices
--irk HEX Resolve RPAs using this Identity Resolving Key (32 hex chars)
--irk-file PATH Read IRK(s) from a file (one per line, hex format)
-t, --timeout TIMEOUT Scan timeout in seconds (default: 30, or infinite for --irk)
--output {csv,json,jsonl}
Batch output format written at end of scan
-o, --output-file FILE
Output file path (default: btrpa-scan-results.<format>;
use - for stdout)
--log FILE Stream detections to a CSV file in real time
-v, --verbose Verbose mode — show additional details
-q, --quiet Quiet mode — suppress per-device output, show summary only
--min-rssi DBM Minimum RSSI threshold (e.g. -70) — ignore weaker signals
--rssi-window N RSSI sliding window size for averaging (default: 1 = no averaging)
--active Use active scanning (sends SCAN_REQ for additional data)
--environment {free_space,indoor,outdoor}
Distance estimation path-loss model (default: free_space)
--ref-rssi DBM Calibrated RSSI at 1 metre for distance estimation
--name-filter PATTERN Filter devices by name (case-insensitive substring match)
--alert-within METERS Proximity alert when device is within this distance
--tui Live-updating terminal table instead of scrolling output
--gui Launch web-based radar interface in the browser
--gui-port PORT Port for GUI web server (default: 5000)
--no-gps Disable GPS location stamping (GPS is on by default via gpsd)
--adapters LIST Comma-separated Bluetooth adapter names (e.g. hci0,hci1)
Scannt alle sendenden BLE-Geräte (Standard-Timeout: 30 Sekunden):
btrpa-scan --all
Mit einem benutzerdefinierten Timeout:
btrpa-scan --all -t 60
Sucht nach einem bestimmten Gerät anhand der MAC-Adresse:
btrpa-scan AA:BB:CC:DD:EE:FF
Löst Resolvable Private Addresses mithilfe eines Identity Resolving Keys auf. Dieser Modus läuft standardmäßig unbegrenzt, bis er mit Ctrl+C gestoppt wird:
btrpa-scan --irk 0123456789ABCDEF0123456789ABCDEF
Der IRK kann in mehreren Formaten angegeben werden:
| Format | Beispiel |
|---|---|
| Reines Hex | 0123456789ABCDEF0123456789ABCDEF |
| Mit Doppelpunkten getrennt |
Lädt einen oder mehrere IRKs aus einer Datei. Jede Zeile sollte einen IRK in einem beliebigen unterstützten Hex-Format enthalten. Zeilen, die mit # beginnen, werden als Kommentare behandelt:
btrpa-scan --irk-file keys.txt
Beispiel-keys.txt:
# Alice's phone
0123456789ABCDEF0123456789ABCDEF
# Bob's watch
FEDCBA9876543210FEDCBA9876543210
Wenn mehrere IRKs geladen sind, wird jede erkannte RPA gegen alle Schlüssel geprüft. Die Zusammenfassung zeigt die Gesamtzahl der Übereinstimmungen über alle Schlüssel hinweg.
Setzen Sie die Umgebungsvariable BTRPA_IRK, um den Schlüssel nicht über die Befehlszeile übergeben zu müssen:
export BTRPA_IRK=0123456789ABCDEF0123456789ABCDEF
btrpa-scan
Priorität: --irk > --irk-file > BTRPA_IRK
Nur Geräte mit einer Signalstärke oberhalb eines Schwellenwerts anzeigen:
btrpa-scan --all --min-rssi -70
BLE-RSSI ist von Natur aus verrauscht. Verwenden Sie einen gleitenden Durchschnitt für stabilere Entfernungsschätzungen und zum Herausfiltern unregelmäßiger schwacher Erkennungen:
btrpa-scan --all --rssi-window 5
Wenn die Fensterung aktiv ist, zeigt die Anzeige sowohl das rohe als auch das gemittelte RSSI (z. B. RSSI: -65 dBm (avg: -62 dBm over 5 readings)), und die Entfernungsschätzung verwendet den gemittelten Wert. Der --min-rssi-Filter gilt ebenfalls für das gemittelte RSSI und verhindert, dass ein einzelner verrauschter Ausschlag ein Gerät aus der Liste entfernt.
Filtert Geräte nach Namen mithilfe eines case-insensitiven Teilstring-Abgleichs:
btrpa-scan --all --name-filter "AirPods"
Es werden nur Geräte angezeigt, deren beworbener Name das angegebene Muster enthält. Geräte ohne Namen werden ausgeschlossen, solange ein Namensfilter aktiv ist.
Passives Scannen (Standard) sieht nur Werbepakete. Aktives Scannen sendet SCAN_REQ und erhält SCAN_RSP, wodurch zusätzliche Service-UUIDs und Gerätenamen sichtbar werden können:
btrpa-scan --all --active
Hinweis: Unter macOS scannt CoreBluetooth unabhängig von diesem Flag immer aktiv. Unter Linux/BlueZ kann aktives Scannen
root-Rechte oderCAP_NET_ADMINerfordern.
Die Entfernungsschätzung verwendet einen Pfadverlust-Exponenten, der je nach Umgebung variiert. Die Standardeinstellung (free_space, n=2.0) geht von keinerlei Hindernissen aus. Für realistischere Schätzungen in Innenräumen:
btrpa-scan --all --environment indoor
| Voreinstellung | Pfadverlust-Exponent (n) | Anwendungsfall |
|---|---|---|
free_space | 2.0 | Freie Luft, Sichtlinie |
Höhere n-Werte ergeben bei gleichem RSSI größere Entfernungsschätzungen, was die Signaldämpfung durch Wände und Hindernisse widerspiegelt.
Standardmäßig leitet btrpa-scan das erwartete RSSI bei 1 Meter aus der beworbenen TX Power mit einem empirisch validierten 59-dB-Offset ab (der iBeacon-Standard). Für eine noch bessere Genauigkeit können Sie einen in Ihrer eigenen Umgebung gemessenen, kalibrierten Wert angeben:
--ref-rssi:btrpa-scan --all --ref-rssi -55
Wenn --ref-rssi gesetzt ist, wird TX Power vollständig ignoriert. Dies ermöglicht außerdem Entfernungsschätzungen für Geräte, die keine TX Power bewerben.
Löst einen akustischen Glockenton und einen visuellen Alarm aus, wenn ein Gerät innerhalb einer bestimmten Entfernung geschätzt wird. Voraussetzung ist, dass das Zielgerät TX Power bewirbt:
btrpa-scan AA:BB:CC:DD:EE:FF --alert-within 5.0
Funktioniert in allen Modi, einschließlich IRK-Auflösung:
btrpa-scan --irk <key> --alert-within 3.0
Ersetzt die scrollende Ausgabe durch eine live aktualisierte Terminaltabelle, sortiert nach Signalstärke:
btrpa-scan --all --tui
Die TUI zeigt alle erkannten Geräte in einer kompakten Tabelle mit Adresse, Name, RSSI, gemitteltem RSSI, geschätzter Entfernung, Anzahl der Erkennungen und letztem Sichtzeitpunkt. Aufgelöste IRK-Übereinstimmungen werden fett dargestellt, und Geräte innerhalb des --alert-within-Schwellenwerts werden hervorgehoben.
Kombinierbar mit anderen Flags:
btrpa-scan --irk <key> --tui --rssi-window 5 --environment indoor --alert-within 5.0
Startet eine browserbasierte Radarschnittstelle mit animiertem Sweep, Echtzeit-Geräteverfolgung und GPS-Karte:
btrpa-scan --all --gui
Die GUI bietet:
Der GUI-Modus scannt standardmäßig kontinuierlich (kein 30-Sekunden-Timeout). Stoppen Sie mit Ctrl+C. Verwenden Sie -t, um eine bestimmte Scandauer festzulegen:
# Scan for 60 seconds with indoor path-loss model
btrpa-scan --all --gui -t 60 --environment indoor
# Custom port
btrpa-scan --all --gui --gui-port 8080
# Combine with RSSI averaging and proximity alerts
btrpa-scan --all --gui --rssi-window 5 --alert-within 5.0
Hinweis:
--guierfordert Flask und flask-socketio (pip install btrpa-scan[gui]). Kann nicht mit--tuioder--quietkombiniert werden.
Schreibt jede Erkennung direkt in eine CSV-Datei, während sie stattfindet (nützlich für lang laufende Scans, bei denen Sie inkrementelle Daten benötigen):
btrpa-scan --all --log scan.csv
Dies kann mit --output für einen separaten Stapel-Export kombiniert werden:
btrpa-scan --all --log live.csv --output json -o results.json
Exportiert alle Ergebnisse am Ende des Scans im CSV-, JSON- oder JSONL-Format (JSON Lines):
btrpa-scan --all --output json -o results.json -t 30
btrpa-scan --all --output csv -t 30
btrpa-scan --all --output jsonl -o results.jsonl -t 30
JSONL schreibt ein JSON-Objekt pro Zeile, sodass es sich einfach durch jq pipen lässt:
btrpa-scan --all --output jsonl -o results.jsonl -t 10
cat results.jsonl | jq .
Ausgabe zur Weiterverarbeitung an stdout ausgeben:
btrpa-scan --all --output json -o - -t 10 -q | jq .
Scannt gleichzeitig mit mehreren Bluetooth-Adaptern für eine größere Abdeckung:
btrpa-scan --all --adapters hci0,hci1
Jeder Adapter führt eine eigene Scanner-Instanz aus, die denselben Erkennungs-Callback verwendet. Alle Erkennungen werden zu einer einzigen Ausgabe zusammengeführt.
GPS ist standardmäßig aktiviert. Jede Erkennung wird mit den aktuellen GPS-Koordinaten von gpsd markiert. Der Scanner verfolgt außerdem den besten GPS-Fix pro Gerät – die Koordinaten der Erkennung mit dem stärksten RSSI (nächste Nähe = genauester Standort).
Wenn gpsd nicht läuft, gibt der Scanner einen Hinweis aus und setzt den Betrieb normal ohne GPS fort:
# With gpsd running — detections include lat/lon
btrpa-scan --all --output json
# Without gpsd — works fine, GPS fields are empty
btrpa-scan --all
# Explicitly disable GPS (skips connection attempt)
btrpa-scan --all --no-gps
GPS-Koordinaten erscheinen in:
latitude, longitude, gps_altitudeIm Ruhemodus ausführen (nur Zusammenfassung, keine Ausgabe pro Gerät – nützlich mit --output oder --log):
btrpa-scan --all -q --output json -t 30
Im ausführlichen Modus ausführen (zeigt nicht übereinstimmende RPAs im IRK-Modus):
btrpa-scan --irk 0123456789ABCDEF0123456789ABCDEF -v
Bluetooth-Low-Energy-Geräte verwenden Resolvable Private Addresses (RPAs), um Tracking zu verhindern. Eine RPA ist eine temporäre MAC-Adresse, die sich regelmäßig ändert, aber von jedem aufgelöst werden kann, der den Identity Resolving Key (IRK) des Geräts besitzt.
Eine RPA besteht aus:
01 gesetzt sindAES-128-ECB(IRK, padding || prand), gekürzt auf 3 Bytesbtrpa-scan implementiert die ah()-Funktion aus der Bluetooth Core Specification (Vol 3, Part H, Abschnitt 2.2.2), um diese Adressen in Echtzeit aufzulösen.
Hinweis zu AES-ECB: Die Verwendung von AES im ECB-Modus für die
ah()-Funktion wird von der Bluetooth Core Specification vorgeschrieben. Da immer nur ein einzelner 16-Byte-Block verschlüsselt wird, ist die fehlende Diffusion von ECB über Blöcke hinweg irrelevant – dies ist keine Schwachstelle.
ps sichtbar. Um den IRK nicht offenzulegen, verwenden Sie --irk-file, um aus einer Datei zu lesen, oder setzen Sie die Umgebungsvariable BTRPA_IRK. Die Konsolenausgabe maskiert IRKs standardmäßig (sie zeigt nur die ersten und letzten 4 Hex-Zeichen).--no-gps, um GPS vollständig zu deaktivieren.--output-file und --log schreiben in den angegebenen Pfad. Stellen Sie sicher, dass das Zielverzeichnis über die für Ihren Verwendungszweck erforderlichen Berechtigungen verfügt.pip install pytest
python -m pytest test_btrpa_scan.py -v
Mode: DISCOVER ALL - showing every broadcasting device
Scanning: passive
GPS: connected (37.774929, -122.419418)
Timeout: 30s | Press Ctrl+C to stop
------------------------------------------------------------
============================================================
DEVICE #1 - seen 1x
============================================================
Address : AA:BB:CC:DD:EE:FF
Name : MyDevice
RSSI : -45 dBm
TX Power : -59 dBm
Est. Distance: ~0.4 m
Manufacturer : 0x004C -> 0215abcdef
Best GPS : 37.774929, -122.419418
Timestamp : 14:32:07
============================================================
------------------------------------------------------------
Scan complete - 30.0s elapsed
Total detections : 142
Unique devices : 12
Results written to btrpa-scan-results.json
Drücken Sie jederzeit Ctrl+C, um den Scan sauber zu beenden und die Zusammenfassungsstatistiken anzuzeigen.
| Plattform | Installation | Start |
|---|
| macOS | brew install gpsd | gpsd -n /dev/tty.usbserial-* |
| Debian/Ubuntu | sudo apt install gpsd gpsd-clients | sudo systemctl start gpsd |
| Fedora/RHEL | sudo dnf install gpsd gpsd-clients | sudo systemctl start gpsd |
| Arch | sudo pacman -S gpsd | sudo systemctl start gpsd |
| Windows | gpsd über WSL oder MSYS2 verwenden | Siehe WSL-Anweisungen oben |
| Plattform | Hinweise |
|---|
| macOS | Verwendet CoreBluetooth. Der IRK-Modus nutzt eine undokumentierte API, um echte Bluetooth-Adressen anstelle von UUIDs abzurufen. --active hat keine Wirkung – CoreBluetooth scannt immer aktiv. |
| Linux | Kann für das Scannen root-Rechte oder die Capability CAP_NET_ADMIN erfordern. |
| Windows | Native WinRT-Bluetooth-API – echte MAC-Adressen nativ verfügbar. Die TUI erfordert pip install windows-curses. |
01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF |
| Mit Bindestrichen getrennt | 01-23-45-67-89-AB-CD-EF-01-23-45-67-89-AB-CD-EF |
| Mit 0x-Präfix | 0x0123456789ABCDEF0123456789ABCDEF |
outdoor | 2.2 | Parks, Parkplätze |
indoor | 3.0 | Büros, Wohnungen, Gebäude |