
Всем привет. В этот раз я решил затронуть тему безопасности устройств, которыми пользуются большинство автовладельцев. Речь пойдёт о трёх самых популярных автомобильных сигнализациях (иммобилайзерах), представленных на российском рынке.
Забегая вперёд, скажу, что отчёты обо всех найденных недостатках были направлены производителям, а также во ФСТЭК России. Из ответа регулятора я узнал, что в качестве уязвимостей отчёты зарегистрированы не будут, так как «данное программно-аппаратное средство не используется на объектах ГИС и КИИ». Производители же сообщили, что описанные недостатки устранят в новых моделях сигнализаций. За информацией о том, что делать с уже существующими моделями, я рекомендую обращаться к производителям.
О проекте
Исследования проводились с большим разбросом по времени. Первое я выполнил в конце 2022 года, два других — в 2024-м, с небольшим интервалом. Целью проекта был вовсе не поиск уязвимостей, а простой азарт: если что-то зашифровано, я хочу это расшифровать. Опыт получился достаточно интересный. О нём — в этой статье.
О первом исследованном устройстве
Что меня радует в моей работе, так это возможность уделять время собственным ресёрчам. Так, в поисках подопытного я решил посмотреть содержимое одной коробочки, которая лежала на полке с артефактами от предыдущих проектов. Описание на ней гласило: «Охранно-противоугонная микросигнализация — CAN иммобилайзер PANDECT X-1000 BT», а внутри коробки лежали какие-то проводки, инструкция, кнопка на шлейфе, основной модуль сигнализации, а также брелок и «верещалка».

Первым делом нужно понять, что искать и куда копать. И проще всего начать с… запуска сигналки. А точнее — с банальной её настройки и подключения к ПК и смартфону. Читаю инструкцию, устанавливаю соответствующие приложения, втыкаю USB-шнурок и, конечно же, не забываю для всего этого добра собрать USB-трафик с помощью Wireshark для последующего анализа.

Так, например, одним из потенциальных векторов исследования может быть процесс обновления устройства по USB. По идее, если мне удастся разобраться, как он происходит, и найти в нём недостатки, я смогу самостоятельно формировать файлы обновления и загружать их в сигнализацию.


Процесс обновления
По утверждению Wireshark, подключенное USB-устройство распознаётся как HID, а всё общение в трафике выглядит как набор пакетов GET_REPORT/SET_REPORT. Если присмотреться к содержимому одного из первых пакетов, можно заметить, что отправляются байтики, идентичные байтам в хедере файла прошивки (его я нашёл на официальном сайте производителя). Почему я решил, что это именно хедер? Раз уж содержимое идёт отдельным пакетом, имеет совпадения с началом файла и содержит строку версии — это точно хедер!



Как можно заметить, начиная со следующего пакета отправляется уже само зашифрованное содержимое прошивки (тело) — по 64 байта (ограничение HID?). Можно ли уже попробовать что-то сделать, обладая этими знаниями?


Я решил поменять один единственный бит где-нибудь в хедере прошивки, не отправляя всё остальное (либо, если нужно, отправить первый блок тела), и посмотреть, что будет. Результат — ПО сигнализации перестало видеть устройство, хотя сам USB-девайс появляется, да и лампочки на сигналке говорят о том, что она что-то да запускает. Значит, нужно понять, что именно идёт не так и почему ПО перестало «видеть». Нормальный человек изучил бы USB-трафик, а я зачем-то полез изучать саму утилиту.


Утилита от производителя
Беглое изучение программы показало следующее:
Она точно использует JS.
Скомпилирована с использованием Awesomium SDK.
Не содержит строк в читаемом виде.
Файл
data.asrна деле оказывается запароленным ZIP-архивом.Без отладки не разобраться.

После непродолжительной отладки приложения мне удалось выяснить пароль от архива: aoeuiqjkxb. Далее я добавил в js-файл (уже не помню какой) строчку, которая помогла бы понять различия между двумя сигналками: почти окирпиченной и нормальной.

Результат такой отладки показал различия в поле версии. В одном случае содержимое поля version было нормальным, а в другом — нечитаемым. Исходя из этого можно сделать следующие выводы:
Содержимое USB-пакета с модифицированным хедером сразу же записалось во внутреннюю память устройства.
При взаимодействии по USB содержимое читается из памяти, ПО не может сравнить его с нормальной строкой версии прошивки, и устройство перестаёт быть видимым.


Для дальнейших экспериментов мне хотелось восстановить работу сигналки, поэтому я поставил бряк на выход из ReadFile() и просто подменил нужные байтики в lpBuffer на корректные. Благодаря этому мне удалось запустить процесс обновления целиком и прошить нормальный хедер заново, после чего сигнализация ожила.

Продолжаем обновляться
Если позволить процессу обновления отработать полностью, при этом оставив модифицированный бит в заголовке, можно выяснить: какой бы ни была контрольная сумма (цифровая подпись), она проверяется в самом конце, после отправки всех байт. Об этом будет свидетельствовать сообщение об ошибке в программе (извините, но скрин у меня не сохранился за давностью лет).
Можно ли теперь собрать все полученные знания в скрипт и заменить прошивку сигнализации на свою? К сожалению, пока ещё нет. Играть в «раскирпичь меня» после каждой попытки мне не очень-то хотелось. Поэтому было решено наконец-таки разобрать девайс и посмотреть, что можно сделать, обладая, так сказать, некоторыми навыками пайки.
Внутренний мир
В основном блоке сигнализации обнаружились чипы с собственной прошивкой:
STM32 (уже не помню, какая именно).
nRF52832 (основной модуль).
nRF51822 (брелок).
Также на основном модуле легко нашлись две гребёнки по пять выводов каждая: одна ближе к STM32, вторая — к nRF52. Прозвонка показала, что два вывода из пяти — земля и питание на обоих группах контактов. Остальные же (не помню почему, но, возможно, потому что на тот момент контакты чипов были жутко мелкими для меня) я не стал вызванивать, а сразу решил, что это SWD. В результате непродолжительного перебора различных вариантов так оно и оказалось.
Отладка
Подключившись отладчиком JLink к STM32, мне удалось выяснить, что внутренняя память чипа не читается, а вот SRAM читать можно — это говорит о включенном режиме RDP1. В принципе, с этим уже можно работать. Идея была такая:
Запускаю режим обновления прошивки.
Отправляю первый блок.
Подключаю отладчиком.
Читаю SRAM в файл dump1.bin.
Отправляю второй блок.
Читаю SRAM в файл dump2.bin.
Сравниваю файлы и ищу закономерности.
С этой последовательностью возникла проблема: после подключения отладчиком сигнализация не смогла принимать USB-пакеты — это связано с работой режима RDP1, не позволяющего делать полноценную «паузу» на STM32. Пришлось адаптировать алгоритм: на этапе отправки второго блока сначала перезагружать устройство, отправлять первый блок, затем второй и уже после этого читать SRAM.
Автоматизация
Чтобы автоматизировать процесс, я попросил коллегу написать небольшой «дропер» питания на Arduino, который бы ожидал на одном из GPIO-пинов команду ресета и при помощи MAX4619 (переключатель) на некоторое время обрывал линию 5V на USB-шнурке.


В результате, кроме больших участков с неинициализированной памятью, удалось обнаружить две области, в которых происходило что-то интересное. Но сказать что-либо однозначное по ним я пока не мог — нужно было набрать больше дампов, порядка тысячи.

К сожалению, замеры продолжительности одной итерации, вкупе с арифметической прогрессией времени загрузки каждого последующего блока (напомню, что каждый новый блок требовал загрузки всех предыдущих), показали удручающую картину: на всю прошивку уйдёт месяца три, а на тысячу блоков — примерно неделя. Цифры приблизительные — за давностью проекта уже не смогу сказать точнее. Тем не менее с этим нужно было что-то делать.


Убер-автоматизация
К счастью, на полках с артефактами обнаружились ещё две сигнализации этой модели (итого — три). К тому же у нас на работе было целых два J-Link, и один EDU я притащил из дома. Что ещё может понадобиться для качественной автоматизации, кроме трёх препарированных USB-кабелей, как вы думаете?
Правильный ответ: три зажима для бумаги, обмотанные изолентой. Не спрашивайте меня почему — я не вспомню. Но вот фото с пруфом, что это точно было нужно.

После отладки этой конструкции я оставил её работать на целую неделю… Так думал я, пока не пришёл на работу на следующий день. Там меня ожидал сюрприз: окошко JLink с предложением принять условия использования EDU-версии. Многие, кто работают с этим отладчиком, видят окно постоянно, но наверняка, как и я, абсолютно машинально нажимают кнопку Accept и забывают о нём. Как оказалось, сам JLink вспоминает о нём ровно в полночь. Как я это обходил — отдельный вопрос и, пожалуй, не стоящий упоминания в этой статье.

Какие-то успехи
Спустя несколько дней набралось достаточно дампов SRAM, чтобы обнаружить и атрибутировать в них:
зашифрованные 8 байт текущего блока,
8 байт XOR-ключа для этого блока,
расшифрованные 8 байт.
Таким образом, если набрать достаточное количество байт XOR-ключа для первых N-байт прошивки, можно зашифровать ими свою собственную, которая, например, блок за блоком сдампит туда же в SRAM содержимое загрузчика (который, предположительно, будет содержать и алгоритм шифрования целиком). Сказано — сделано! Детали будут в конце статьи, а пока перейдём ко второму чипу на плате сигнализации — nRF52.
nRF52 и nRF51
На момент работы над проектом у меня, к сожалению, не было опыта с глитчами по питанию (fault injection), а вот у моего коллеги, к счастью, он был. Поэтому с его помощью, а также опираясь на публично доступную статью с описанием уязвимости в чипе nRF52 (Wayback Machine), я получил на руки полный дамп прошивки беспроводной части сигнализации.


Что касается брелока: в нём установлен похожий чип nRF51, который не требует таких продвинутых техник обхода защиты. Ну и, конечно же, статья о том, как сдампить с него прошивку (Wayback Machine).


Вместо выводов
Алгоритмом, который использовался для шифрования прошивки, оказался ГОСТ 28147-89. Благодаря возможности пошагово получать содержимое SRAM и некорректному использованию алгоритма (промежуточные результаты работы оставались в памяти) мне удалось полностью восстановить прошивку основного блока и изучить механизм его обновления по USB. А ещё я написал скрипт, который позволяет полностью расшифровывать файлы обновлений и шифровать их обратно.

Взаимодействие с производителем
В конце 2022 года результаты, которые можно было бы со спокойной душой отправить вендору, были сформированы. Я написал письмо с подробным описанием проделанных шагов, а также указал рекомендации по устранению найденных проблем. Производитель сообщил, что в курсе выявленных уязвимостей, но иммобилайзер уже снят с производства. Исправления же учтут в будущих моделях.
Результаты
Что мы получаем в итоге:
Алгоритм шифрования ГОСТ используется некорректно (в памяти остаются следы применяемого ключа).
Проверка подписи файлов не реализована.
Можно загрузить в сигнализацию модифицированную прошивку (включая низкоуровневые загрузчики) либо изменив файлы обновлений, либо через SWD-пины.
P. S. Спасибо за внимание. Скоро опубликую статью о следующем производителе автомобильных сигнализаций — Starline. Остаёмся на связи!
jaha33
Чтобы получать более безопасные устройства лучше таки использовать контроллеры на M23/33 и правильно пользоваться возможностями ядра. Если разработчик все правильно сделает, то и к swd не прицепиться будет, и гличи по питанию не помогут. В отдельных вариациях M33 даже есть фиксация физического вскрытия корпуса микросхемы с автоочитской памяти
Насколько я помню, с 22г, когда западные микросхемы резко перестали быть доступны, Пандора перешли на какие то китайские. Как там с безопасностью - не очень понятно
Сам встречал китайскую микросхему на Corex M0, где разъем программирования не лочится в принципе
DrMefistO Автор
Ядро от всего не защитит. Алгоритмы тоже должны быть написаны грамотно, с учётом специфики конкретной железки