История в двух частях. В первой мы расскажем о первых неудачных попытках болгарского ИТ-специалиста Радослава Герганова взломать свой автомобиль Hyundai Tucson 2020 года выпуска, а во второй — о том, как выполнялся взлом ШГУ автомобиля.
Я купил новенький Hyundai Tucson в 2020 году, а в 2022 году наткнулся на отличную серию постов о том, как можно взломать Hyundai Ioniq 2021 (перевод одной из статей). К сожалению, описанные там способы мне не подошли. В моей машине установлено предыдущее поколение D-Audio, которое сильно отличается от D-Audio 2V, описанного в блоге greenluigi1. Вот точные версии прошивки/программного обеспечения, которые у меня стоят:
Я также нашёл инженерное меню, защищённое паролем. Чтобы оно появилось, нужно 5 раз нажать слева от кнопки «Обновить», а затем нажать 2 раза справа.
Увы, ни один из общедоступных паролей не сработал (1200, 2400, 3802, текущее время и т.д.). Так что я решил скачать прошивку и попробовать перепрошить
Обновление прошивки
Файл прошивки доступен на update.hyundai.com. Вам необходимо скачать и установить Navigation Updater, а затем выбрать модель автомобиля. Программа обновления загружает все файлы и подготавливает SD-карту или USB-флешку. Для моего Hyundai он загрузил 23 ГБ данных, включая обновления навигации и прошивки.
В корневой папке съёмного носителя находится файл 2018_20_Tucson_EU.ver
, в котором перечислены все файлы обновления:
+|22Q1|TLFL.EUR.SOP.V126.220421.STD_M|HM|2018_20_Tucson_EU|1477|1
2018_20_Tucson_EUDAUDIOPLUS_Meur|vr.img|10|623073973|97644544|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdate|checksum|10|-755847668|1888|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdate|info.ini|10|-2103668610|256|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdate|update.ini|10|-1246074861|1883|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdategps|gps.inf|10|-1353122717|69|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdategps|gps_module.bin|10|-1514928853|561740|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatemicom|micom.inf|10|1086259435|68|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatemicom|micom_sw.bin|10|-468017694|1048452|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystem|qb_data.sparse.img|10|-143168397|6160556|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystem|snapshot.sparse.img|10|475782429|53428308|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystem|update_package.zip|10|-678170682|227494562|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystem|vr.inf|10|2034194806|58|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystem|vr.md5|10|-2044697631|41|1
2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystem|vr.sha|10|-189486074|137|1
...
Мы видим каталог, имя, CRC32 (как подписанное 32-битное целое число) и размер каждого файла. Я быстро понял, что самый интересный файл — 2018_20_Tucson_EUDAUDIOPLUS_Meurtlflupdatesystemupdate_package.zip
, это зашифрованный zip:
Я попытался разархивировать файл, используя обнаруженный greenluigi1 пароль (ahqltmTkrhk2018@@), но это не сработало.
Взлом zip-архива
Для взлома я решил попробовать bkcrack. Этот инструмент реализует атаку на основе открытых текстов, обнаруженную Эли Бихамом и Полом Кочером (Eli Biham и Paul C. Kocher). Для атаки требуется не менее 12 байт открытого текста. Мой зашифрованный zip содержит два zip-файла. Кого бы выбрать в качестве кандидата на открытый текст? Заголовок ZIP-файла, конечно! Вот как это выглядит:
Еще одним существенным преимуществом является то, что оба zip-файла update_package.zip
хранятся без сжатия (нет смысла сжимать уже сжатые файлы). Это можно проверить с помощью следующей команды:
$ bkcrack -L update_package.zip
bkcrack 1.5.0 - 2022-07-07
Archive: update_package.zip
Index Encryption Compression CRC32 Uncompressed Packed size Name
----- ---------- ----------- -------- ------------ ------------ ----------------
0 ZipCrypto Store fbe57f09 227492981 227492993 update.zip
1 ZipCrypto Store b4be54fe 1203 1215 otacerts.zip
Теперь нам просто нужно узнать 12 байт заголовка файла update.zip
или otacerts.zip
, чтобы выполнить атаку.
Вариантов для первых 10 байт не так уж и много. Первые 4 байта фиксированы ( 504b0304
). Вариативные байты в большинстве случаев — это либо1400,
либо 0a00
. Предполагая, что вложенные zip-файлы не зашифрованы, битовый флаг общего назначения должен быть 0000
. Метод сжатия: либо 0000
(store), либо0800
(deflate). Итак, у нас есть следующие варианты для первых 10 байт:
plain1.bin: 504b 0304 1400 0000 0000
plain2.bin: 504b 0304 1400 0000 0800
plain3.bin: 504b 0304 0a00 0000 0000
plain4.bin: 504b 0304 0a00 0000 0800
Нам нужны ещё два байта. Мы можем взять дату либо время модификации файла.
Время хранится в секундах, деленных с точностью до 2, что дает нам 246030 =43200 возможностей. Предполагая, что изменение файла произошло за последние 5 лет, у нас есть 5 * 365 = 1825 возможностей для поля даты.
Очевидно, что более эффективно проверять поле даты методом перебора. Однако один запуск этой атаки занимает 30 минут на моем ноутбуке, так что брутфорс будет неэффективен. Пришло время для ещё одной дикой догадки.
Дата изменения файлов update.zip и otacerts.zip «21 апреля 2022 года». Предположим, что дата изменения первой записи файла otacerts.zip
также «21 апреля 2022 года». Эта дата закодирована в формате MS-DOS как9554
. Теперь у нас есть 12 байт обычного текста, но мы пропустили время модификации файла. К счастью, bkcrack поддерживает указание смещения с помощью параметра -x
.
Первый запуск атаки с помощью plain1.bin завершился неудачей. Однако с помощью plain2.bin я успешно выполнил восстановление:
$ bkcrack -C update_package.zip -c otacerts.zip -p plain2.bin -x 12 9554
bkcrack 1.5.0 - 2022-07-07
[15:03:29] Z reduction using 3 bytes of known plaintext
100.0 % (3 / 3)
[15:03:29] Attack on 1677473 Z values at index 6
Keys: 850725d9 64202f01 143f9452
2.8 % (47031 / 1677473)
[15:04:05] Keys
850725d9 64202f01 143f9452
Извлечение zip-файлов:
$ bkcrack -C update_package.zip -c update.zip -k 850725d9 64202f01 143f9452 -d update.zip
$ bkcrack -C update_package.zip -c otacerts.zip -k 850725d9 64202f01 143f9452 -d otacerts.zip
otacerts.zip содержит единственный сертификат X509, изменённый 21 апреля 2022 года (да, мне очень повезло!):
update.zip содержит все самое интересное:
Реверс прошивки
Судя по всему, моя машина работает под управлением Android и system.ext4
имеет корневую файловую систему. Смонтируем и заглянем внутрь:
$ mkdir /tmp/car
$ sudo mount -t ext4 -o loop system.ext4 /tmp/car
$ ls -la /tmp/car
total 140
drwxr-xr-x 14 root root 4096 Jan 1 1970 .
drwxrwxrwt 25 root root 65536 Aug 11 15:40 ..
drwxr-xr-x 2 root root 4096 Apr 21 10:50 app
drwxr-xr-x 2 root 2000 4096 Apr 21 10:46 bin
-rw-r--r-- 1 root root 6020 Apr 21 10:26 build.prop
drwxr-xr-x 11 root root 4096 Apr 21 10:50 etc
drwxr-xr-x 2 root root 4096 Apr 21 10:35 fonts
drwxr-xr-x 2 root root 4096 Apr 21 10:50 framework
-rw-r--r-- 1 root root 1912 Apr 21 10:35 key_3000000.psr
-rw-r--r-- 1 root root 1913 Apr 21 10:35 key_921600.psr
drwxr-xr-x 8 root root 8192 Apr 21 10:46 lib
drwx------ 2 root root 4096 Jan 1 1970 lost+found
drwxr-xr-x 4 root root 4096 Apr 21 10:35 media
drwxr-xr-x 7 root root 4096 Apr 21 10:38 usr
drwxr-xr-x 4 root 2000 4096 Apr 21 10:35 vendor
drwxr-xr-x 2 root root 4096 Apr 21 10:35 wifi
drwxr-xr-x 2 root 2000 4096 Apr 21 10:45 xbin
Практически все приложения находятся в папке /app
. Каждое приложение имеет как .apk, так и .odex версию, например:
$ ls -l /tmp/car/app/HKMC_EngineerMode.*
-rw-r--r-- 1 root root 2124079 Apr 21 10:50 /tmp/car/app/HKMC_EngineerMode.apk
-rw-r--r-- 1 root root 1630136 Apr 21 10:50 /tmp/car/app/HKMC_EngineerMode.odex
Я использовал baksmali для преобразования файлов odex в smali и jadx для декомпиляции smali в Java. Давайте рассмотрим приложения для инженерного меню, а затем файлы обновления.
Пароль инженерного меню
Пароль на инженерное меню добывается из getKeyString()
методом com.hkmc.system.app.engineering.ime.InputPasswordExt
. Он берет последнюю цифру текущего года, а затем выполняет поиск ресурсов:
Это соответствующие строки ресурсов:
В этом году пароль 2702 . Попробовал на машине, работает:
Пароль для обновления
Хотя я могу извлекать обновления прошивки с помощью ключей, полученных с помощью bkcrack, мне было любопытно узнать пароль для update_package.zip. Простой grep по update_package.zip приводит к методу getPassword() com.hkmc.system.app.swupdate.ImageFileCopy
:
Статический пароль «+Ekfrl51Qkshsk#@zpdhkdWkd~-f» не работал. В моем случае пароль был получен в результате объединения следующих системных свойств:
ro.product.model=daudioplus
ro.product.brand=hyundai
ro.product.name=tlfl_eu
ro.product.device=daudiopluslow_tlfl_eu
ro.product.board=daudio
ro.product.cpu.abi=armeabi-v7a
ro.product.cpu.abi2=armeabi
ro.product.manufacturer=mobis
ro.product.locale.language=en
ro.product.locale.region=GB
Метод SHA512Checking()
вычисляет SHA512-дайджест данной строки и возвращает результат в виде шестнадцатеричной строки в верхнем регистре. Делаем это дважды и берём подстроку:
SHA512Checking(SHA512Checking(tmp1)).substring(10, 38) = "15DAA85C8D44B3979CD152A387F6"
Пароль 15DAA85C8D44B3979CD152A387F6
Что дальше
Я почти уверен, что смогу создать обновление прошивки с бэкдором и получить доступ в корневую оболочку. Но есть небольшой шанс, что что-то пойдёт не так и заблокирует мою машину, поэтому я пока не собираюсь этого делать :) У меня есть некоторые идеи, которые я попробую провернуть. Конечная цель, конечно же, — играть в Doom на экране моей машины.
Как Радослав добрался до ШГУ своего автомобиля, расскажем в следующей статье.
Что ещё интересного есть в блоге Cloud4Y
→ Информационная безопасность и глупость: необычные примеры
→ Как распечатать цветной механический телевизор на 3D-принтере
→ Создание e-ink дисплея с прогнозом погоды
→ Аналоговый компьютер Telefunken RA 770
Подписывайтесь на наш Telegram-канал, чтобы не пропустить очередную статью. Пишем только по делу. А ещё напоминаем про второй сезон нашего сериала ITить-колотить. Его можно посмотреть на YouTube и ВКонтакте.
Автор: Cloud4Y