Разбор уязвимости умного Bluetooth-замка

  • Автор темы Автор темы MORGAN
  • Дата начала Дата начала

MORGAN

Активный пользователь
Регистрация
04.06.2025
Сообщения
1 179
Реакции
1 068
Баллы
113
Привет, Хабр! Сегодня предлагаем разобрать успешный взлом коммерческого умного замка с поддержкой Bluetooth, который открывается по отпечатку пальца или через беспроводное соединение. Здесь будет реверс-инжиниринг мобильного приложения, манипуляции с API-запросами и перехват протокола связи Bluetooth Low Energy (BLE).

Для анализа использовались динамические инструменты и инструмент для атак «человек посередине» (MitM) в BLE‑канале. После объединения нескольких уязвимостей в архитектуре системы, удалось зарегистрироваться и управлять замком, не имея физического доступа к нему. В результате была полностью скомпрометирована функция разблокировки.

Коротко для тех, кому лень читать​

Фокус внимания был направлен на два компонента:

  1. Общение между Android-приложением и удалённым API-сервером.
  2. BLE-связь между приложением и самим замком.
Доступ получен за счёт комбинации уязвимостей:

  • Ненадёжный API для привязки устройств.
  • Статическое шифрование (одинаковый ключ для всех замков).
  • Кастомный BLE-протокол без защиты от перехвата и повторного использования команд.
Хотя BLE-трафик был зашифрован, в нём отсутствовали механизмы проверки целостности сообщений или защиты от атак повторного воспроизведения.

Инструменты​

Весь BLE-трафик перехватывался и анализировался с помощью BLE:Bit — мощного инструмента для исследования BLE, позволяющего мониторить трафик в реальном времени и внедрять команды. Изначально этот инструмент разрабатывался для внутренних нужд, но позже стал open-source проектом и помогает сообществу ИБ-специалистов.

Регистрация замка без физического доступа​

Приложение привязывает замок к аккаунту пользователя через простой HTTP POST-запрос. По логике, это должно быть возможно только при нахождении рядом с замком (через BLE). Однако выяснилось, что сервер разрешает привязку, зная только MAC-адрес замка.

Пример запроса:

POST /lock/bind<br>Headers:<br> token: &lt;redacted&gt;<br> uid: &lt;redacted&gt;<br>Body:<br>{<br> "name": "lock1",<br> "userId": &lt;redacted&gt;,<br> "mac": "&lt;redacted&gt;"<br>}
Сервер успешно обрабатывал запрос, даже если он отправлялся с устройства, не находящегося рядом с замком и не связанного с ним ранее. Никаких криптографических проверок, подтверждения близости или доказательства владения не требовалось.

Извлечение учётных данных замка через API​

После регистрации замка приложение получает его данные через ещё один POST-запрос:

POST /lock/getLockList<br>Body:<br>{<br> "userId": &lt;redacted&gt;<br>}
В ответе сервера присутствует поле encryptedData, содержащее зашифрованные данные замка: ключ для BLE‑шифрования, пароль и MAC‑адрес.

Пример ответа:

{<br> "name": "lock1",<br> "mac": "&lt;redacted&gt;",<br> "encryptedData": "RUQ2RDJCODZFQ...=="<br>}

Расшифровка данных с помощью статического ключа​

После декомпиляции приложения был обнаружен следующий код:

public void setData() {<br> String[] split = new String(<br> b.b(<br> c.a(new String(Base64.decodeBase64(this.encryptedData.getBytes()))),<br> c.a("58966742920123314112157843194045")<br> )<br> ).split("&amp;");<br><br> this.lockKey = split[0];<br> this.lockPwd = split[1];<br> this.mac = split[2].trim();<br>}
Видите проблемы, да? Жёстко зашитый AES‑ключ (58966742920123314112157843194045) использовался для расшифровки учётных данных блокировки. А ещё приложение использовало AES в режиме ECB без заполнения (AES/ECB/NoPadding) — это небезопасно, так как позволяет расшифровать данные любого замка, имея доступ к бинарнику приложения.

После расшифровки получаем:

lockKey: &lt;redacted&gt; <br>lockPwd: &lt;redacted&gt; <br>mac: &lt;redacted&gt;
Этих данных достаточно для формирования валидных BLE-команд и разблокировки замка.

Структура BLE-протокола​

Связь между мобильным приложением и замком осуществляется по протоколу Bluetooth Low Energy через две GATT‑характеристики:

  • 0×36f5 — для отправки зашифрованных команд от приложения к замку.
  • 0×36f6 — для ответов от замка, которые приходят в приложение.
Все сообщения шифруются AES в режиме ECB (без защиты от replay‑атак). Ключ (lockKey) уникален для каждого замка, но извлекается из encryptedData (который можно расшифровать из‑за статического ключа).

Каждая команда представляет собой 16-байтовое сообщение, состоящее из:

  • Кода операции (2 байта) — действие (например, «открыть», «проверить заряд батареи»).
  • Параметра (переменная длина) — полезная нагрузка в зависимости от типа команды.
  • Случайных данных (до 16 байт) — заполняет блок до полных 16 байт.
После формирования сообщение шифруется с помощью lockKey и отправляется.

Ответы от замка имеют ту же структуру, но могут содержать байты состояния, данные или подтверждения.

Мобильное приложение и замок общаются через симметричный зашифрованный канал без какой-либо формы MAC (кода аутентификации сообщений), nonce (одноразового числа) или последовательного номера. Это делает протокол уязвимым к replay- и injection-атакам, что было подтверждено на практике.

Каждое сообщение обрабатывается как независимый атомарный блок. Отсутствует контекст сессии, handshake-аутентификация или stateful-сопряжение после первоначального подключения. Это нетипично для безопасных BLE-реализаций, где используются сессионные ключи, методы сопряжения (например, Just Works, Passkey), аутентифицированные характеристики для защиты от подмены данных.

С точки зрения ИБ, такая структура делает протокол легко обратимым и эмулируемым, особенно при наличии постоянного формата сообщений и известного ключа шифрования.

Перехваченный трафик​

С помощью BLE:Bit и его возможностей MitM мы записали BLE-трафик между мобильным приложением и замком в реальном времени.

Кусочек перехваченного трафика:

WRITE Android → SmartLock @ 0x36f5: 3E 62 BB 1D F5 6C 60 94 84 E0 E3 87 26 0A 8B BE<br>NOTIFY SmartLock → Android @ 0x36f6: 93 C6 50 7E 00 79 94 24 6E 6E 40 EA D7 F8 86 7E<br><br>WRITE Android → SmartLock @ 0x36f5: FC B1 5D A6 3E 3C DD E4 56 72 60 2D 03 34 84 98<br>NOTIFY SmartLock → Android @ 0x36f6: DE 4F 0D BB F5 1B 34 08 5F DD F9 FC 59 A9 C5 EF<br><br>WRITE Android → SmartLock @ 0x36f5: C6 9D BC DA 2F 39 C7 AD 32 8D DA 21 B2 14 61 FE<br>NOTIFY SmartLock → Android @ 0x36f6: DE 4F 0D BB F5 1B 34 08 5F DD F9 FC 59 A9 C5 EF
Из этих данных видно, что каждая команда WRITE от приложения сопровождалась ответом NOTIFY от замка. Содержимое сообщений варьировалось в зависимости от типа операции, но всегда имело фиксированный размер 16 байт и шифровалось AES.

Каждая операция (например, открытие замка, проверка статуса, сброс пароля) имела уникальный код операции. Например, OPEN_LOCK в приложении был определён как 0501 в перечислении BLE-сообщений.

Создание и отправка команд разблокировки​

Команда разблокировки в приложении создавалась классом вроде такого:

public class i extends z {<br> public i(String password) {<br> super(TYPE.OPEN_LOCK);<br> char[] chars = password.toCharArray();<br> a((byte) 6, (byte) chars[0], ..., (byte) chars[5]);<br> }<br>}
После создания полезная нагрузка шифруется и передаётся с помощью:

BLEService.a(context, b.a(new i("000000")));
Извлекая пароль из расшифрованного файла encryptedData, мы смогли воспроизвести эту последовательность и самостоятельно выдать команду разблокировки с помощью специального скрипта.

Уязвимость к replay-атакам​

BLE‑сообщения были статичными и повторно используемыми. Поскольку не было механизма проверки актуальности (nonce, счётчик, сессионный ключ), мы смогли перехватить валидную команду разблокировки и отправить её позже — замок выполнял её без каких‑либо дополнительных проверок.

Это полноценная уязвимость replay‑атаки, позволяющая любому злоумышленнику в радиусе действия BLE перехватывать и повторно использовать команды разблокировки.

Анализ причин уязвимости​

Компрометация стала возможной из‑за нескольких ошибок в проектировании:

  1. API привязки устройства не проверял авторизацию и близость пользователя.
  2. Шифрование использовало статический ключ, встроенный в клиент.
  3. BLE-канал не имел защиты целостности сообщений или механизмов против replay-атак.
  4. Код приложения раскрывал все криптографические операции и структуру протокола без обфускации.
Чтобы предотвратить подобные атаки, производителям следует:

  • Добавить проверку близости при привязке (например, через BLE challenge-response).
  • Использовать уникальные ключи для каждого устройства, безопасно прошитые на этапе производства.
  • Добавить коды аутентификации сообщений (MAC) с nonce или счётчиками для защиты от replay-атак.
  • Заменить режим ECB на безопасный (например, AES-GCM).
  • Обфусцировать код приложения и защитить его от динамического анализа.
Вот так вот комбинация небезопасного API, слабой криптографии и плохой реализации BLE приводит к полной компрометации устройства. Так что, создавая умный дом, делайте его ещё и безопасным.
 
Назад
Верх