Найти в Дзене
mamaich

Расшифровка прошивки Яндекс IP камеры

Яндекс не так давно начал шифровать прошивки своих новых устройств. Этот факт был одной из причин, сподвигнувших меня на покупку именно их камеры - интересно было посмотреть как сделано шифрование. Код расшифровщика прошивки Яндекс не прятал - в сдампленном с устройства разделе recovery находится скрипт /etc/init.d/S80swupdate, содержащий такие строки: Как видно, утилита sstar-crypto расшифровывает файл, используя ключ номер 1. Если скопировать файл обновления на устройство и с консоли вызвать: sstar-crypto dec файл_зашифрованной_прошивки расшифрованный_файл 1 то мы получим расшифрованный файл в формате CPIO. Однако, это не всё. Остаются зашифрованными разделы kernel, rkernel и u-boot. Чтобы понять как их расшифровать - требуется немного покопаться в имеющихся у нас исходниках u-boot. Моё внимание привлекла функция sig_auth в файле drivers\mstar\aesdma\cmd_sigauth.c, вызывающая функцию runDecrypt: runDecrypt(data, image_size, E_AESDMA_KEY_OTP_EFUSE_KEY1, (U16*)KeyAES); KeyAES у нас

Яндекс не так давно начал шифровать прошивки своих новых устройств. Этот факт был одной из причин, сподвигнувших меня на покупку именно их камеры - интересно было посмотреть как сделано шифрование.

Код расшифровщика прошивки Яндекс не прятал - в сдампленном с устройства разделе recovery находится скрипт /etc/init.d/S80swupdate, содержащий такие строки:

Как видно, утилита sstar-crypto расшифровывает файл, используя ключ номер 1. Если скопировать файл обновления на устройство и с консоли вызвать:

sstar-crypto dec файл_зашифрованной_прошивки расшифрованный_файл 1

то мы получим расшифрованный файл в формате CPIO.

-2

Однако, это не всё. Остаются зашифрованными разделы kernel, rkernel и u-boot. Чтобы понять как их расшифровать - требуется немного покопаться в имеющихся у нас исходниках u-boot. Моё внимание привлекла функция sig_auth в файле drivers\mstar\aesdma\cmd_sigauth.c, вызывающая функцию runDecrypt:

runDecrypt(data, image_size, E_AESDMA_KEY_OTP_EFUSE_KEY1, (U16*)KeyAES);

KeyAES у нас нулевой, мы это знаем по логу загрузки:

подчеркнутое знчение передается в (U16*)KeyAES
подчеркнутое знчение передается в (U16*)KeyAES

Так что используется первый ключ AES из OTP (отсчет ключей в OTP идет от нуля) - то есть тот же ключ, которым дешифровали прошивку утилитой sstar-crypto.

Берем утилиту sstar-crypto, и смотрим что же она делает. Код отлично декомпилируется IDA и мы получаем вполне читаемый текст функции main(). Сперва в функции проверяются параметры на валидность и открываются файлы, затем из расшифровываемого файла читается первые 16 байт - они будут IV:

-4

Далее идет инициализация криптобиблиотеки (находится в libsstar-crypto.so) и расшифровка файла.

-5

Во всей библиотеке интересен только момент инициализации ключа:

-6

Цифра 11 в строке 51 - это значение CRYPTO_AES_CBC, см исходники криптодрайвера SigmaStar.

Взаимодействие с крипто-движком процессора SigmaStar идет через драйвер, и в драйвер в качестве ключа передается магическая строка "SStarU", после которой следует один байт со значением от 1 до 4 (это номер ключа), далее следуют нулевые байты.

Увы, но утилита sstar-crypto для расшифровки kernel/u-boot нам не подходит. В ней используется AES с CBC, а в команде sigauth используется AES с ECB:

-7

К счастью, в исходниках ядра в папке drivers\sstar\crypto\cryptodev\examples есть примеры - и можно на их основе сделать свой расшифровщик. Либо можно просто запатчить библиотеку libsstar-crypto.so и утилиту sstar-crypto, чтобы всегда использовать IV из нулевых байт и CRYPTO_AES_ECB (значение 23) вместо CRYPTO_AES_CBC (11) - так поступил я.

Для расшифровки файлов требуется отрезать заголовок, это первые 0x40 байт:

на примере u-boot
на примере u-boot

после чего скормить файл исправленной утилите расшифровки:

утилиту не привожу, но выше я рассказал как ее сделать самому
утилиту не привожу, но выше я рассказал как ее сделать самому

Видим, что файл успешно расшифровался (decryption error: success - потому что в конце файла надо было отрезать подпись). В начале файла видим заголовок XZ:

-10

И после распаковки XZ (архиватор ругнется, так как в конце файла будет немного мусора, который, в общем, не мешает) видим текстовые строки u-boot:

-11

Аналогичным образом расшифровывается и ядро - kernel и rkernel.

Если исправить ядро и зашифровать назад - устройство откажется его грузить, так как настроен Secure Boot и проверяются подписи разделов. Secure Boot не сложно обойти, но я расскажу об этом только в конце октября, так как сдал информацию в bug bounty Яндекса и должен выждать положенные 90 дней - хотя уже более двух недель от Яндекса ноль реакции, несмотря на напоминания.