
Инструмент для исследований в области безопасности, который выявляет и демонстрирует уязвимость CVE-2025-36911: обход режима быстрой пары (Fast Pair)
Глубокое погружение в CVE-2025-36911 и пробелы безопасности в экосистеме Google Fast Pair
Google Fast Pair был разработан, чтобы сделать сопряжение по Bluetooth бесшовным: нажал на уведомление — и ты подключён. Но что происходит, когда этот бесшовный опыт становится угрозой безопасности? WhisperPair-PoC-Tool — это инструмент для исследования безопасности, который выявляет два критических класса уязвимостей, затрагивающих миллионы Bluetooth-аксессуаров: обход несанкционированного сопряжения и эксплуатация сети Find My Device.
В этом посте описываются технические детали WhisperPair-PoC-Tool, слабые места протокола, которые он эксплуатирует, и что это значит для экосистемы Bluetooth-аксессуаров.
Спецификация Google Fast Pair явно указывает:
"Если присутствует необязательное поле Public Key: если устройство не находится в режиме сопряжения, игнорируйте запись и выйдите."
Это критический защитный шлюз. Устройства должны только отвечать на запросы Key-Based Pairing, когда пользователь явно перевёл устройство в режим сопряжения (обычно удержанием кнопки). Это обеспечивает намерение пользователя, чтобы нельзя было подключиться к чьим-то наушникам, пока они надеты.
Проблема: Многие производители полностью пропускают эту проверку. Они обрабатывают запросы на сопряжение независимо от состояния режима сопряжения, что позволяет:
Сеть Find My Device Network (FMDN) от Google позволяет отслеживать Bluetooth-аксессуары через краудсорсинговую сеть Android-устройств. Для этого требуется Account Key — 16-байтовый симметричный ключ, связывающий устройство с учётной записью Google.
Проблема: Характеристика Account Key часто принимает записи без аутентификации:
Прежде чем углубляться в эксплуатацию, давайте разберёмся с легитимным потоком Fast Pair:
┌─────────────────────────────────────────────────────────────┐
│ BLE Advertisement │
├─────────────────────────────────────────────────────────────┤
│ Service UUID: 0xFE2C (Fast Pair) │
│ Service Data: │
│ [Pairing Mode] → 3 bytes: Model ID only │
│ [Not Pairing] → 4+ bytes: 0x00 + Account Key Filter │
└─────────────────────────────────────────────────────────────┘
Формат рекламного объявления раскрывает состояние сопряжения:
Seeker (Phone) Provider (Accessory)
│ │
│───── GATT Connect ──────────────────────────>│
│ │
│───── Discover Services ─────────────────────>│
│<──── Service: 0xFE2C ────────────────────────│
│ │
│───── Enable Notifications (0xFE2C1234) ─────>│
│ │
│───── Write Key-Based Pairing Request ───────>│
│ [16-byte encrypted block] │
│ [64-byte ECDH Public Key] (optional) │
│ │
│ ┌────────────────────────────────────┐ │
│ │ SECURITY CHECK: │ │
│ │ If Public Key present AND │ │
│ │ device NOT in pairing mode: │ │
│ │ → IGNORE and EXIT │ │
│ │ Else: │ │
│ │ → Process request │ │
│ └────────────────────────────────────┘ │
│ │
│<──── Notification: Encrypted Response ───────│
│ [Provider's BR/EDR Address] │
│ │
│═══════ Bluetooth Classic Pairing ═══════════>│
Уязвимость возникает, когда устройства полностью пропускают блок "SECURITY CHECK".
WhisperPair-PoC-Tool — это инструмент для исследования безопасности на Python, построенный на основе BLE-библиотеки Bleak. Он работает в несколько этапов:
┌────────────────────────────────────────────────────────────────┐
│ WhisperPair-PoC-Tool │
├────────────────────────────────────────────────────────────────┤
│ CLI Layer │
│ ├── Argument parsing (--target-name, --scan-duration) │
│ ├── TargetPolicy construction │
│ └── REPL initialization │
├────────────────────────────────────────────────────────────────┤
│ Discovery Engine │
│ ├── BLE scanning via Bleak │
│ ├── Advertisement parsing │
│ ├── Protocol detection (Fast Pair, FMDN, Swift Pair) │
│ └── Device fingerprinting (Model ID, OUI lookup) │
├────────────────────────────────────────────────────────────────┤
│ Check Engines │
│ ├── FastPairCheckEngine (passive advertisement analysis) │
│ ├── FastPairBypass (active CVE-2025-36911 testing) │
│ ├── FindHubCheckEngine (Account Key status detection) │
│ └── RiskScorer (composite vulnerability assessment) │
├────────────────────────────────────────────────────────────────┤
│ Connection Manager │
│ ├── GATT connect with MTU negotiation │
│ ├── Service/characteristic discovery │
│ ├── Read/Write/Notify operations │
│ └── Error handling and retry logic │
├────────────────────────────────────────────────────────────────┤
│ Exploitation Modules │
│ ├── ring_device() - Trigger locator sound │
│ ├── set_account_key() - Write Account Key │
│ └── Response parsing (BR/EDR address extraction) │
└────────────────────────────────────────────────────────────────┘
discovery.py)Сканер использует callback-функции обнаружения Bleak для захвата BLE-рекламы:
async def _detection_callback(
self, device: BLEDevice, advertisement_data: AdvertisementData
) -> None:
"""Process each detected BLE advertisement."""
discovered = DiscoveredDevice(
address=device.address,
name=device.name or advertisement_data.local_name,
rssi=advertisement_data.rssi,
advertisement=self._convert_advertisement(advertisement_data),
first_seen=datetime.now(UTC),
last_seen=datetime.now(UTC),
)
self._devices[device.address] = discovered
Для каждого устройства инструмент извлекает:
0xFE2C, FMDN 0xFD44 и т.д.)0x00E0, Apple 0x004C)fastpair.py)Режим сопряжения определяется путём анализа рекламы устройства:
def _analyze_service_data(self, evidence: FastPairEvidence) -> None:
"""Analyze Fast Pair service data to infer pairing mode."""
data = evidence.service_data_bytes
# 3 bytes = Model ID only = Pairing Mode (discoverable)
if len(data) == 3:
evidence.inferred_pairing_mode = PairingModeState.IN_PAIRING_MODE
return
# 4+ bytes with version 0x00 = Not in pairing mode
if data[0] == 0x00:
akd_byte = data[1]
akd_type = akd_byte & 0x0F # Lower 4 bits
# Type 0x00 = Show UI, Type 0x02 = Hide UI
# Both indicate NOT in pairing mode
evidence.inferred_pairing_mode = PairingModeState.NOT_IN_PAIRING_MODE
Это критически важно: если устройство определено как не находящееся в режиме сопряжения, и оно всё равно отвечает на запрос сопряжения, значит оно уязвимо.
fastpair_attack.py)Основной тест уязвимости отправляет запросы Key-Based Pairing и отслеживает ответы:
async def check_vulnerability(self, device: DiscoveredDevice) -> BypassCheckResult:
"""Test if device responds to pairing requests when not in pairing mode."""
# Enable notifications to receive response
await self.connection_manager.start_notify(
KEY_BASED_PAIRING_CHAR,
self._notification_handler,
)
# Build and send request (multiple strategies)
for strategy in self.strategies:
request, flags = self._build_strategy_request(device.address, strategy)
await self.connection_manager.write_characteristic(
KEY_BASED_PAIRING_CHAR,
request,
)
# Wait for response
try:
await asyncio.wait_for(
self._response_received.wait(),
timeout=self.response_timeout,
)
# Response received = VULNERABLE
return BypassCheckResult(result=BypassResult.VULNERABLE, ...)
except asyncio.TimeoutError:
# No response = Device correctly ignored request
continue
return BypassCheckResult(result=BypassResult.NOT_VULNERABLE, ...)
Инструмент реализует несколько стратегий запросов, потому что разные устройства реагируют на разные комбинации флагов:
Когда уязвимое устройство отвечает, инструмент извлекает BR/EDR (Bluetooth Classic) адрес:
def _parse_response(self, response_data: bytes) -> str | None:
"""Extract provider's BR/EDR address from response."""
# Strategy 1: Standard response (type 0x01)
if response_data[0] == 0x01:
return self._extract_address(response_data, offset=1)
# Strategy 2: Extended response (type 0x02)
if response_data[0] == 0x02:
addr_count = response_data[2]
return self._extract_address(response_data, offset=3)
# Strategy 3: Brute force pattern matching
for offset in range(len(response_data) - 5):
addr = self._extract_address(response_data, offset)
if self._is_valid_mac(addr):
return addr
Этот BR/EDR-адрес может быть использован для инициирования сопряжения по Bluetooth Classic (хотя WhisperPair-PoC-Tool останавливается на обнаружении).
Исследование выявило типичные ошибки реализации:
Самая распространённая проблема: производители просто не реализуют проверку:
// VULNERABLE: No pairing mode check
void handle_kbp_write(uint8_t* data, size_t len) {
if (len >= 80 && has_public_key(data)) {
// Should check: if (!is_in_pairing_mode()) return;
process_pairing_request(data); // Processes regardless
}
}
Характеристика Account Key должна требовать аутентификации:
// VULNERABLE: No authentication required
void handle_account_key_write(uint8_t* key, size_t len) {
if (len == 16) {
store_account_key(key); // Accepts any key from anyone
}
}
// SECURE: Verify caller knows existing key
void handle_account_key_write_secure(uint8_t* encrypted_key, size_t len) {
if (!verify_encrypted_with_existing_key(encrypted_key)) {
return; // Reject unauthorized writes
}
store_account_key(decrypt(encrypted_key));
}
Устройства, рекламирующие данные службы Fast Pair, когда не находятся в режиме сопряжения, раскрывают:
WhisperPair-PoC-Tool использует многоуровневый подход к обнаружению:
Подключение не требуется. Инструмент анализирует то, что транслирует устройство:
┌─────────────────────────────────────────────────────────────┐
│ Passive Checks │
├─────────────────────────────────────────────────────────────┤
│ ✓ Fast Pair service UUID present (0xFE2C) │
│ ✓ FMDN service UUID present (0xFD44) │
│ ✓ Pairing mode inferred from service data length │
│ ✓ Model ID extracted (when in pairing mode) │
│ ✓ Account Key Filter detected (when not in pairing mode) │
│ ✓ Address type analysis (static vs. random) │
└─────────────────────────────────────────────────────────────┘
Result: "Device advertising Fast Pair data while NOT in pairing mode"
→ Potential gating violation (needs active test to confirm)
Требуется подключение. Инструмент взаимодействует со службами GATT:
┌─────────────────────────────────────────────────────────────┐
│ Active Checks │
├─────────────────────────────────────────────────────────────┤
│ 1. Connect to device via BLE │
│ 2. Discover Fast Pair service (0xFE2C) │
│ 3. Locate Key-Based Pairing characteristic (0xFE2C1234) │
│ 4. Enable notifications │
│ 5. Write Key-Based Pairing request │
│ 6. Wait for response (with timeout) │
│ 7. Response received → VULNERABLE │
│ Timeout/Rejected → NOT VULNERABLE │
└─────────────────────────────────────────────────────────────┘
Вычисляется составная оценка риска:
Уровни риска:
WhisperPair-PoC-Tool включает контролируемые функции эксплуатации для демонстрации воздействия:
ring)Запускает характеристику FMDN Beacon Actions для воспроизведения звука локатора:
ЗАРЕДАКТИРОВАНО ДЛЯ ПУБЛИКАЦИИ
Воздействие: Злоумышленник может беспокоить жертву, многократно вызывая звук, или использовать это для определения местоположения устройства, которое хочет украсть.
set account-key)Записывает новый Account Key на устройство:
ЗАРЕДАКТИРОВАНО ДЛЯ ПУБЛИКАЦИИ
Воздействие:
WhisperPair-PoC-Tool намеренно останавливается до полной эксплуатации:
if (has_public_key(request) && !is_in_pairing_mode()) {
return; // Ignore request per spec
}
Требуйте аутентификацию для записи Account Key:
Минимизируйте раскрытие в рекламных объявлениях:
Механизм обновления прошивки:
Этот инструмент предназначен для:
WhisperPair-PoC-Tool демонстрирует, что «бесшовный» опыт Fast Pair сопряжён с компромиссами в безопасности, которые многие производители не устраняют. Проверка режима сопряжения — это единственное условие, которое отделяет безопасное устройство от уязвимого, и тем не менее оно часто опускается.
Модель доверия Fast Pair предполагает, что устройства будут обеспечивать намерение пользователя. Когда этого не происходит, злоумышленники получают возможности тихого сопряжения, отслеживания и векторов отказа в обслуживании для устройств жертв.
Этот инструмент призван помочь экосистеме идентифицировать и устранять эти проблемы, делая Bluetooth-аксессуары более безопасными для всех.
WhisperPair-PoC-Tool выпущен только для авторизованных исследований безопасности. Никакой ответственности за неправильное использование этого инструмента не предполагается.
| Стратегия | Флаги | Описание |
|---|
RAW_KBP | 0x11 | INITIATE_BONDING | EXTENDED_RESPONSE |
WITH_PUBLIC_KEY | 0x11 | 80-байтовый запрос с открытым ключом ECDH |
RETROACTIVE | 0x0A | Обходит некоторые проверки производителей |
EXTENDED | 0x10 | Для более новых прошивок устройств |
| Сигнал | Баллы | Значение |
|---|
| Нарушение шлюза (пассивное) | +2 | Рекламирует FP, когда не в режиме сопряжения |
| Подтверждён обход (активный) | +2 | Ответил на KBP, когда не в режиме сопряжения |
| FMDN без Account Key | +2 | Отслеживается через сеть Find My |
| Статический BLE-адрес | +1 | Устройство постоянно отслеживаемо |
| Наблюдается смена адреса | -1 | Поведение, сохраняющее конфиденциальность |
| Возможность | Реализовано | Причина |
|---|
| Обнаружение уязвимости | ✅ Да | Основная цель |
| Извлечение BR/EDR-адреса | ✅ Да | Сбор доказательств |
| Сопряжение по Bluetooth Classic | ❌ Нет | Требует платформозависимого кода |
| Перехват аудио HFP | ❌ Нет | Выходит за рамки BLE-инструмента |
| Постоянное внедрение | ❌ Нет | Вредоносная возможность |