
Сканер Bluetooth Low Energy (BLE) с разрешением Resolvable Private Address (RPA) с использованием Identity Resolving Keys (IRKs)
A Bluetooth Low Energy (BLE) scanner with advanced Resolvable Private Address (RPA) resolution. Discover nearby BLE devices, track a specific device by MAC address, or resolve privacy-randomized addresses using an Identity Resolving Key (IRK).
Written by: David Kennedy (@HackingDave) Company: TrustedSec
-o -)Для привязки GPS-координат требуется запущенный демон gpsd с подключённым GPS-приёмником. Если gpsd не запущен, btrpa-scan продолжает работу без GPS.
Чтобы проверить, что gpsd работает:
# Check that gpsd is listening
gpspipe -w -n 5
# Or use the curses monitor
cgps
Этот проект использует pyproject.toml (PEP 621) — современный стандарт упаковки Python. Он определяет проект как устанавливаемый пакет с зарегистрированной CLI-командой — нет необходимости запускать .py-файлы напрямую.
uvx btrpa-scan --all
uvx --from git+https://github.com/hackingdave/btrpa-scan.git btrpa-scan --all
uv tool install btrpa-scan
Или напрямую с GitHub:
uv tool install git+https://github.com/hackingdave/btrpa-scan.git
pip install btrpa-scan
Для поддержки графического интерфейса (радар на основе Flask):
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)
Сканирование всех передающих BLE-устройств (тайм-аут по умолчанию 30 секунд):
btrpa-scan --all
С собственным тайм-аутом:
btrpa-scan --all -t 60
Поиск конкретного устройства по MAC-адресу:
btrpa-scan AA:BB:CC:DD:EE:FF
Разрешение Resolvable Private Addresses с помощью Identity Resolving Key. Этот режим по умолчанию работает бесконечно, пока не будет остановлен с помощью Ctrl+C:
btrpa-scan --irk 0123456789ABCDEF0123456789ABCDEF
IRK может быть указан в нескольких форматах:
| Формат | Пример |
|---|---|
| Простой hex | 0123456789ABCDEF0123456789ABCDEF |
| Через двоеточие | 01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF |
Загрузите один или несколько IRK из файла. Каждая строка должна содержать один IRK в любом поддерживаемом hex-формате. Строки, начинающиеся с #, считаются комментариями:
btrpa-scan --irk-file keys.txt
Пример keys.txt:
# Alice's phone
0123456789ABCDEF0123456789ABCDEF
# Bob's watch
FEDCBA9876543210FEDCBA9876543210
Когда загружено несколько IRK, каждый обнаруженный RPA проверяется по всем ключам. Сводка показывает общее количество совпадений по всем ключам.
Установите переменную окружения BTRPA_IRK, чтобы не передавать ключ в командной строке:
export BTRPA_IRK=0123456789ABCDEF0123456789ABCDEF
btrpa-scan
Приоритет: --irk > --irk-file > BTRPA_IRK
Показывать только устройства с уровнем сигнала выше порога:
btrpa-scan --all --min-rssi -70
BLE RSSI по своей природе зашумлён. Используйте скользящее окно усреднения для более стабильной оценки расстояния и отсеивания ложных слабых обнаружений:
btrpa-scan --all --rssi-window 5
Когда окно усреднения активно, на дисплее отображаются как исходный, так и усреднённый RSSI (например, RSSI: -65 dBm (avg: -62 dBm over 5 readings)), а оценка расстояния использует усреднённое значение. Фильтр --min-rssi также применяется к усреднённому RSSI, не позволяя единичному шумовому всплеску убрать устройство из списка.
Фильтруйте устройства по имени с поиском подстроки без учёта регистра:
btrpa-scan --all --name-filter "AirPods"
Будут показаны только устройства, чьё рекламируемое имя содержит указанный шаблон. Устройства без имени исключаются, когда активен фильтр по имени.
Пассивное сканирование (по умолчанию) видит только рекламные пакеты. Активное сканирование отправляет SCAN_REQ и получает SCAN_RSP, которые могут раскрыть дополнительные UUID сервисов и имена устройств:
btrpa-scan --all --active
Примечание: На macOS CoreBluetooth всегда выполняет активное сканирование независимо от этого флага. На Linux/BlueZ для активного сканирования могут потребоваться права root или возможность
CAP_NET_ADMIN.
Оценка расстояния использует показатель потерь пути, который зависит от окружения. По умолчанию (free_space, n=2.0) предполагается отсутствие препятствий. Для более реалистичной оценки внутри помещений:
btrpa-scan --all --environment indoor
| Пресет | Показатель потерь пути (n) | Применение |
|---|---|---|
free_space | 2.0 | Открытый воздух, прямая видимость |
Более высокие значения n дают большие оценки расстояния при том же RSSI, отражая затухание сигнала от стен и препятствий.
По умолчанию btrpa-scan вычисляет ожидаемый RSSI на расстоянии 1 метр из рекламируемой мощности TX Power, используя эмпирически подтверждённое смещение 59 дБ (стандарт iBeacon). Для ещё большей точности вы можете указать калиброванное значение, измеренное в вашем окружении:
--ref-rssi:btrpa-scan --all --ref-rssi -55
Когда задан --ref-rssi, TX Power полностью игнорируется. Это также позволяет оценивать расстояние для устройств, которые не передают TX Power.
Подача звукового сигнала и визуального оповещения, когда устройство, по оценке, находится в пределах заданного расстояния. Требуется, чтобы целевое устройство передавало TX Power:
btrpa-scan AA:BB:CC:DD:EE:FF --alert-within 5.0
Работает во всех режимах, включая разрешение IRK:
btrpa-scan --irk <key> --alert-within 3.0
Заменяет прокручиваемый вывод таблицей в терминале, обновляемой в реальном времени и отсортированной по уровню сигнала:
btrpa-scan --all --tui
TUI показывает все обнаруженные устройства в компактной таблице с адресом, именем, RSSI, усреднённым RSSI, оценочным расстоянием, количеством обнаружений и временем последнего появления. Совпадения, разрешённые через IRK, отображаются полужирным шрифтом, а устройства в пределах порога --alert-within выделяются.
Комбинируется с другими флагами:
btrpa-scan --irk <key> --tui --rssi-window 5 --environment indoor --alert-within 5.0
Запускает браузерный радар с анимированной развёрткой, отслеживанием устройств в реальном времени и GPS-картой:
btrpa-scan --all --gui
Возможности интерфейса:
Режим GUI по умолчанию сканирует непрерывно (без 30-секундного тайм-аута). Нажмите Ctrl+C для остановки. Используйте -t, чтобы задать конкретную продолжительность сканирования:
# 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
Примечание: Для
--guiтребуются Flask и flask-socketio (pip install btrpa-scan[gui]). Нельзя комбинировать с--tuiили--quiet.
Потоковая запись каждого обнаружения в CSV-файл по мере его появления (полезно для длительных сканирований, когда нужны инкрементальные данные):
btrpa-scan --all --log scan.csv
Это можно комбинировать с --output для отдельного пакетного экспорта:
btrpa-scan --all --log live.csv --output json -o results.json
Экспорт всех результатов по окончании сканирования в формате CSV, JSON или JSONL (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 записывает по одному JSON-объекту в строку, что упрощает передачу через jq:
btrpa-scan --all --output jsonl -o results.jsonl -t 10
cat results.jsonl | jq .
Вывод результатов в stdout для передачи по конвейеру:
btrpa-scan --all --output json -o - -t 10 -q | jq .
Одновременное сканирование несколькими Bluetooth-адаптерами для более широкого покрытия:
btrpa-scan --all --adapters hci0,hci1
Каждый адаптер запускает собственный экземпляр сканера, использующий общий callback обнаружения. Все обнаружения объединяются в единый вывод.
GPS включён по умолчанию. Каждое обнаружение помечается текущими GPS-координатами из gpsd. Сканер также отслеживает наилучшую GPS-фиксацию для каждого устройства — координаты из обнаружения с самым сильным RSSI (ближайшее расположение = наиболее точное местоположение).
Если gpsd не запущен, сканер выводит уведомление и продолжает обычную работу без GPS:
# 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-координаты отображаются:
latitude, longitude, gps_altitudeЗапуск в тихом режиме (только сводка, без вывода по каждому устройству — полезно с --output или --log):
btrpa-scan --all -q --output json -t 30
Запуск в подробном режиме (показ несовпадающих RPA в режиме IRK):
btrpa-scan --irk 0123456789ABCDEF0123456789ABCDEF -v
Устройства Bluetooth Low Energy используют Resolvable Private Addresses (RPA) для защиты от отслеживания. RPA — это временный MAC-адрес, который периодически меняется, но может быть разрешён любым, кто владеет Identity Resolving Key (IRK) устройства.
RPA состоит из:
01AES-128-ECB(IRK, padding || prand), усечённый до 3 байтbtrpa-scan реализует функцию ah() из спецификации Bluetooth Core (Vol 3, Part H, Section 2.2.2) для разрешения этих адресов в реальном времени.
Примечание об AES-ECB: Использование AES в режиме ECB для функции
ah()предписано спецификацией Bluetooth Core. Поскольку шифруется только один 16-байтовый блок, отсутствие диффузии между блоками в ECB не имеет значения — это не уязвимость.
ps. Чтобы не раскрывать IRK, используйте --irk-file для чтения из файла или установите переменную окружения BTRPA_IRK. Консольный вывод по умолчанию маскирует IRK (показывая только первые и последние 4 hex-символа).--no-gps, чтобы полностью отключить GPS.--output-file и --log записывают данные по указанному пути. Убедитесь, что у целевого расположения есть соответствующие права доступа для вашего сценария использования.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
Нажмите Ctrl+C в любой момент, чтобы корректно остановить сканирование и вывести сводную статистику.
| Платформа | Установка | Запуск |
|---|
| 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 через WSL или MSYS2 | См. инструкции для WSL выше |
| Платформа | Примечания |
|---|
| macOS | Использует CoreBluetooth. Режим IRK использует недокументированный API для получения реальных Bluetooth-адресов вместо UUID. --active не действует — CoreBluetooth всегда выполняет активное сканирование. |
| Linux | Для сканирования могут потребоваться права root или возможность CAP_NET_ADMIN. |
| Windows | Собственный API Bluetooth WinRT — реальные MAC-адреса доступны изначально. Для TUI требуется pip install windows-curses. |
| Через дефис | 01-23-45-67-89-AB-CD-EF-01-23-45-67-89-AB-CD-EF |
| С префиксом 0x | 0x0123456789ABCDEF0123456789ABCDEF |
outdoor | 2.2 | Парки, парковки |
indoor | 3.0 | Офисы, дома, здания |