Защита от считывания памяти микроконтроллеров stm32

Обновлено: 06.07.2024

Есть личный опыт чтения прошивок с защищенных чипов STM32F1xx и STM32F0xx.

Список доступных для считывания дампа прошивки защищенных битом защиты микроконтроллеров см. ниже.

В основном ко мне общаются ремонтники. Частые причины:
1. После неудачного обновления устройство не запускается (кирпич).
2. У микроконтроллера отгорело часть ножек, но чип ещё видится программатором (не в замыкании по питанию).
В обоих случаях могу помочь - высылайте чип-донор работающего такого же устройства с таким же чипом. В большинстве случаев помогает.
В редких случаях в прошивке есть проверка ID чипа и перенос содержимого Flash памяти ничего не даст (нужно ковырять прошивку), но это редкость.

Полный список успешно протестированных считанных в обход защиты микросхем:

Серия STM32F1:
STM32F100C8T6B, Микроконтроллер 32-Бит, Cortex-M3, 64КБ Flash [LQFP-48]
STM32F100RBT6B, Микроконтроллер, 32-bit ARM Cortex M3, 128KB Flash 2.5V/3.3V [LQFP-64]
STM32F103C8T6, Микроконтроллер 32-Бит, Cortex-M3, 64КБ Flash, USB, CAN [LQFP-48]
STM32F103CBT6, Микроконтроллер 32-Бит, Cortex-M3, 128КБ Flash, USB, CAN, [LQFP-48]
STM32F103RET6, Микроконтроллер 32-Бит, Cortex-M3, 512КБ Flash [LQFP-64]
STM32F103RCT6, Микроконтроллер 32-Бит, Cortex-M3, 256КБ Flash, USB, CAN [LQFP-64]
STM32F103RBT6, Микроконтроллер 32-Бит, Cortex-M3, 128КБ Flash, USB, CAN [LQFP-64]
STM32F103VET6, Микроконтроллер ARM 512KB FLASH MEM [LQFP-100]
STM32F103T8U6, Микроконтроллер 32BIT ARM 64K FLASH [VFQFPN-36]
STM32F105RBT6, Микроконтроллер 32-Бит, Cortex-M3, 128КБ Flash [LQFP-64]
STM32F107RCT6, Микроконтроллер 32-Бит, Cortex-M3, 256КБ Flash [LQFP-64]
STM32F405RGT6, Микроконтроллер 32-Бит, Cortex-M4 + FPU, 1МБ Flash, USB OTG HS/FS [LQFP-64]

Серия STM32F0:
STM32F030K6T6, Микроконтроллер 32-bit ARM Cortex M0 RISC 32KB Flash 2.5V/3.3V [LQFP-32]
STM32F030K6T6TR, Микроконтроллер 32-Бит, Cortex-M0, 32КБ Flash [LQFP-32]
STM32F030C6T6, Микроконтроллер 32-bit ARM Cortex M0 RISC 32KB Flash 2.5V/3.3V [LQFP-48]
STM32F030C8T6, Микроконтроллер 32-Бит, Cortex-M0, 64КБ Flash [LQFP-48]
STM32F030R8T6, Микроконтроллер 32-Бит, Cortex-M0, 64КБ Flash [LQFP-64]
STM32F051C8T6, Микроконтроллер 32-Бит, Cortex-M0, 64КБ Flash [LQFP-48]
STM32F051R8T6, Микроконтроллер 32-Бит, Cortex-M0, 64КБ Flash [LQFP64]
STM32F072RBT6, Микроконтроллер 32-бит 128KB FLASH [LQFP-64]


Безумная иллюминация в стиле Жана Мишеля Жарра или новый альбом группы Rammstein из колонок в половине пятого утра — это все милые шалости по сравнению с тем, к каким последствиям может привести взлом автоматических кормушек для питомцев или носимых медицинских устройств.

Обновления «по воздуху» и многочисленные отладочные интерфейсы умных устройств могут оказаться серьезной дырой в безопасности, которая позволит опытному злоумышленнику подменить заводскую прошивку своей собственной, — не говоря уж о банальной краже чужой интеллектуальной собственности. Глупый, глупый современный IoT!

Для чего нужен Secure Boot

В общем случае разработчику, который хочет защитить свое устройство, предстоит решить две ключевые задачи.

  • В первую очередь следует реализовать механизм подтверждения подлинности прошивки (аутентификации). Для этого используются различные криптографические алгоритмы (например, SHA-256 и NIST P256). Они позволяют убедиться, что на устройстве будет исполняться только доверенный код.
  • Кроме того, необходимо защитить память от внешних атак и лишить злоумышленника доступа к критичным регионам, который он может в теории получить с помощью уязвимостей ПО либо при использовании отладочных интерфейсов (например, JTAG) или логического анализатора.

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

Как это работает



Базовую безопасность при этом обеспечивают следующие меры: во-первых, исключается возможность альтернативных методов загрузки. Для этого применяется подтвержденный Secure Boot, который формирует root of trust в нашей системе. Во-вторых, приватные ключи шифрования должны храниться в прошивке устройства и быть индивидуальными.



Кроме того, конкретную реализацию криптографического алгоритма следует проверять на устойчивость к АВК (атака по второстепенным каналам, side-channel attack) или АМИС (атака методом индуцированных сбоев, fault injection attack). К этому мы еще вернемся.

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

Аппаратные средства

Посмотрим теперь, как выглядит применение подобных рекомендаций на практике, для линейки микроконтроллеров STM32.

Стоит заметить, что набор доступных средств защиты зависит от конкретного семейства МК (F, G, L и H). Демонстрационные примеры в пакете X-CUBE-SBSFU охватывают большую часть из этого набора, но за полной информацией в любом случае следует обращаться к документации. Конкретно сегодня нас интересуют:

    — ключевой материал о безопасности микроконтроллеров STM32; — руководство по фреймворку SBSFU в пакете XCUBE; — апноут для MPU (Memory Protection Unit); — мануал по механизмам защиты для ядра Cortex-M7; — даташит на МК H743; — референс на МК H743.

Все ссылки — на PDF.

Защита от чтения, RDP

Это базовый механизм безопасности, который предотвращает доступ к содержимому памяти микроконтроллера различными отладочными средствами (JTAG, SWV и ETM). Его применение рекомендуется во всех случаях на готовых серийных устройствах. Отключение RDP возможно только для первого уровня защиты и приводит к стиранию содержимого флеш-памяти. Включение второго уровня — необратимая операция для микросхемы.

Теоретически все это может осложнить сервисное обслуживание и поиск причины неисправности возвращенного пользователем оборудования. Однако, так как само приложение все равно сохраняет способность писать в постоянную память и изменять ее, возможность обновлений прошивки (в том числе с помощью SFU) остается. При включенном RDP попытка доступа к защищенному участку памяти приводит к генерации ошибки на шине AHB.

На H743 за эту функцию отвечают биты RDP [15:8] в паре регистров FLASH_OPTSR_CUR и FLASH_OPTSR_PRG из области Option Bytes. При этом значение 0xAA соответствует нулевому уровню защиты (по умолчанию), значение 0xCC — первому, а любое другое — второму (максимальному) уровню.

Формально на диаграммах STMicroelectronics Option Bytes относятся к внутренней флеш-памяти, однако непосредственный доступ к ним невозможен. Для взаимодействия и внесения изменений пользователю нужно обращаться к регистрам и следовать определенной процедуре (подробнее см. раздел Option Bytes Modification на с. 157 RM0433).

Продолжение доступно только участникам

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Александр Бурага

Инженер-конструктор радиоэлектронной техники. С вниманием следит за прогрессом IoT и носимой электроники.



В предыдущей статье мы разбирались с Vcc-glitch-атаками при помощи ChipWhisperer. Нашей дальнейшей целью стало поэтапное изучение процесса считывания защищенной прошивки микроконтроллеров. С помощью подобных атак злоумышленник может получить доступ ко всем паролям устройства и программным алгоритмам. Яркий пример – взлом аппаратного криптокошелька Ledger Nano S с платой МК STM32F042 при помощи Vcc-glitch-атак.

Интересно? Давайте смотреть под кат.

О возможности считывания защищенной прошивки мы узнали из статьи, в которой приведены результаты выполнения Vcc-glitch-атаки – обхода байта защиты RDP через масочный загрузчик (bootloader) для нескольких микроконтроллеров (далее – МК). Также рекомендуем к прочтению статью о взломе ESP32.

Теоретической базой исследования послужило руководство успешного считывания защищенной прошивки для LPC1114 через масочный загрузчик с использованием ChipWhisperer.

Так же, как и в первой статье, мы решили проводить эксперименты на плате МК STM32F103RBT6:




Возможность записи данных в сектор флеш-памяти и RAM-памяти или их чтения, а также выполнения других действий с памятью МК определяется значением байта защиты (для STM32 – RDP). Для разных МК значения и назначение байтов защиты, а также алгоритм их проверки различается.

Аппаратная настройка

Приступим к проведению эксперимента. Для начала необходимо подключить ChipWhisperer к МК согласно рисунку:




Схема подключения ChipWhisperer к STM32 для считывания защищенной прошивки через масочный загрузчик

На схеме зачеркнуты элементы, которые следует удалить из платы STM32F103RBT6 (в отличие от стандартного подключения МК). Стрелками обозначены места подключения ChipWhisperer, а подписями – его пины.

Наличие внешнего кварца, представленного на схеме, не обязательно, поскольку при работе с масочным загрузчиком плата МК STM32F103RBT6 использует внутренний CLOCK с частотой 24 МГц, поэтому синхронизация между ChipWhisperer и МК отсутствует.

Перейдем к настройке ChipWhisperer. Как уже было отмечено выше, рекомендуемая частота работы ChipWhisperer – 24 МГц (или другое кратное значение). Чем выше кратность этой частоты, тем точнее можно настроить момент атаки. Из-за отсутствия синхронизации подбор параметра scope.glitch.offset необязателен, ему можно присвоить любое значение.

Параметры scope.glitch.repeat и scope.glitch.width необходимо подбирать в зависимости от установленной частоты ChipWhisperer. При большом значении частоты все кратковременные импульсы, количество которых устанавливается при помощи scope.glitch.repeat, сливаются в один длительный импульс. Поэтому можно подбирать значение параметра scope.glitch.width, а scope.glitch.repeat зафиксировать, либо наоборот. Мы обнаружили, что оптимальная длительность импульса должна составлять около 80 нс (определяется как ширина импульса на его полувысоте).

Осталось подобрать значение параметра scope.glitch.ext_offset.

Подбор scope.glitch.ext_offset

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




Алгоритм ответа на запрос о чтении данных сектора флеш-памяти

Чтобы удостовериться в верности такой схемы проверки, мы считали исполняемый код загрузчика подобного МК без защиты RDP через ST-Link. На рисунках ниже показаны части алгоритма обработки команды Read Memory command.




Общий вид обработки команды чтения памяти (хорошо видны вызов функции проверки RDP и посылка NACK в случае неудачной проверки)




Тело функции проверки RDP

Обратим внимание на тело функции проверки RDP: видно, что происходит чтение регистра по адресу 0x40022000 + 0x1C , логический сдвиг на 30 разрядов и ветвление. Из документации PM0075 Programming manual (STM32F10xxx Flash memory microcontrollers) становится понятно, что 0x40022000 – это базовый адрес контроллера flash memory, а 0x1C – это смещение регистра FLASH_OBR, в котором нас интересует второй бит RDPRT: Read protection, в котором содержится статус защиты RDP.

Необходимый момент проведения атаки – отработка инструкции LDR (загрузки из памяти). Эта инструкция располагается между запросом на чтение прошивки (отправление байта 0x11 с контрольной суммой 0xEE ) и ответом ACK / NOACK МК по UART. Для того чтобы визуально зафиксировать этот момент, необходимо подключить осциллограф к UART1_RX (пин PA10) и UART1_TX (пин PA9), а затем отслеживать изменение напряжения по UART1. В результате осциллограмма атаки по питанию с подобранным значением scope.glitch.ext_offset должна выглядеть примерно так:




Выбор момента проведения атаки

Скрипт считывания прошивки

Теперь необходимо указать момент срабатывания триггера CW_TRIG в коде Python с целью перехвата момента передачи контрольной суммы по UART1_RX. У ChipWhisperer есть библиотека для общения с масочным загрузчиком МК STM32. В штатном режиме эта библиотека используется для загрузки на МК прошивок из руководств при помощи класса class STM32FSerial(object) , расположенного в файле programmer_stm32fserial.py по пути software/chipwhisperer/hardware/naeusb/ . Для активации срабатывания триггера необходимо скопировать этот класс в главный исполняемый скрипт, чтобы метод класса CmdGeneric(self, cmd) стал глобально доступным, и добавить команду scope.arm() до передачи контрольной суммы (0xEE) запроса на считывание сектора памяти. Итоговый класс приведен в спойлере ниже.

Следует обратить внимание на то, что масочный загрузчик STM32F1хх позволяет считывать за один запрос не более 256 байт прошивки из указанного сектора флеш-памяти. Поэтому при считывании всей прошивки МК необходимо в ходе Vcc-glitch-атаки выполнить несколько запросов на чтение. Затем полученные 256 байт следует разбить на восемь 32-байтных массивов и сформировать из них файл формата HEX.

Настройка параметров ChipWhisperer завершена. Итоговый скрипт на считывание прошивки выглядит следующим образом:

Результаты считывания

На видео продемонстрирована загрузка прошивки на МК через программатор ST-LINK, перевод RDP в состояние защиты и последующее считывание прошивки:

Успешному проведению Vcc-glitch-атаки могут помешать следующие ошибки:

• считывание неверного сектора памяти;

• самопроизвольное удаление прошивки.

Избежать подобных ошибок поможет точный выбор момента атаки путем увеличения частоты работы ChipWhisperer.

После разработки и отладки алгоритма считывания защищенной прошивки мы провели тестовое считывание прошивки программатора ST-LINK-V2.1, который работает на МК STM32F103CBT6. Считанную прошивку мы зашили на «чистый» МК STM32F103CBT6 и установили его вместо заводского. В результате ST-LINK-V2.1 с замененным МК работал в нормальном режиме, будто подмены не было.

Также мы попробовали провести серию атак на STM32F303RCT7. Этот МК в ходе атаки вел себя идентично STM32F103RBT6, но ответ на запрос чтения памяти содержал байт, равный 0х00, что не совпадало с ожидаемым нами результатом. Причина такой неудачи заключалась в более сложном и развитом принципе организации защиты этих МК.

В МК STM32F1xx существует два состояния защиты: защита выключена (Level 0) и включена (Level 1). В старших моделях предусмотрено три состояния защиты: защита отключена (Level 0, RDP = 0x55AA), защита флеш- и SRAM-памяти (Level 2, RDP = 0x33CC) и защита только флеш-памяти (Level 1, RDP принимает любые значения, отличные от 0x55AA и 0x33CC). Поскольку Level 1 может принимать множество значений RDP, установить Level 0 достаточно тяжело. С другой стороны, существует возможность понижения уровня защиты с Level 2 на Level 1 сбиванием одного бита в байте RDP (показано на рисунке ниже), что открывает доступ к SRAM-памяти.




Сравнение значений RDP для разных уровней защиты прошивки

Остается только понять, как этим может воспользоваться злоумышленник. Например, с помощью метода CBS (Cold-Boot Stepping), описанного в этой статье. Этот метод основан на поэтапном снимке состояния SRAM-памяти (периодичность выполнения каждого снимка была в районе микросекунды) после загрузки МК с целью получения ключей шифрования, скрытых паролей или любой другой ценной информации. Авторы предполагают, что метод CBS сработает на всех сериях МК STM32.

Выводы

Подведем итоги наших экспериментов. Выполнение Vcc-glitch-атаки с использованием данных, полученных в результате предыдущего исследования (о котором можно прочитать здесь), заняло у нас несколько дней. А значит, научиться проводить подобные атаки достаточно легко.

Vcc-glitch-атаки опасны тем, что от них сложно защититься. Для уменьшения вероятности успешного проведения подобных атак предлагается использовать МК с более высоким уровнем защиты.


Raccoon Security – специальная команда экспертов НТЦ «Вулкан» в области практической информационной безопасности, криптографии, схемотехники, обратной разработки и создания низкоуровневого программного обеспечения.

STM32F1xx:

1. Защита:

Зернистость защиты от записи:

● четыре страницы для устройств с низкой и средней плотностью

● две страницы для устройств с высокой плотностью и связностью.

1.1 Защита от чтения:

Защита чтения активируется путем установки байт опций RDP, а затем, применяя системный сброс для перезагрузки нового байта опций RDP.

Прим.: Если защита чтения установлена, когда отладчик все еще подключен через JTAG / SWD, примените POR (сброс при включении) вместо сброса системы (без подключения отладчика).

После того как запрограммирован защитный байт:

● Основной доступ к памяти для чтения флэш-памяти не допускается, за исключением кода пользователя (при загрузке основной флэш-памяти с отключенным режимом отладки).

● Все функции, связанные с загрузкой кода и выполнением кода из встроенного SRAM, по-прежнему активны (JTAG / SWD и загрузка из встроенного SRAM), и это можно использовать для отключения защиты чтения. Когда байт опции защиты чтения изменяется на значение защиты памяти, выполняется массовое стирание.

● Доступ к основной флэш-памяти через код, выполняемый с SRAM или FSMC, и доступ к Flash через чтение данных с использованием DMA1, DMA2, JTAG, SWV (просмотрщик последовательного канала), SWD (отладка последовательного интерфейса), ETM и сканирование границ не допускаются.

Состояние защиты от флэш-памяти:

Прим.: Удаление байта опции не приведет к стиранию массы, поскольку стертое значение (0xFF) соответствует защищенному значению.

Снятие защиты:

Чтобы отключить защиту чтения от встроенной SRAM:

● Удалите всю область байта опций. В результате код защиты чтения (RDP) будет равен 0xFF. На этом этапе защита чтения по-прежнему включена.

● Запрограммируйте правильный код RDP 0x00A5 для снятия защиты с памяти. Эта операция сначала вынуждает Mass Erase основной флэш-памяти.

● Сбросьте устройство (POR Reset), чтобы перезагрузить байты опций (и новый код RDP) и отключить защиту чтения.

Прим.: Защита чтения может быть отключена с помощью загрузчика (в этом случае для перезагрузки байтов опций требуется только системный сброс).

1.2 Защита от записи:

В высокой плотности и устройств подключения линии, начиная со страницы 0 до 61, защита от записи осуществляется с зернистостью двух страниц одновременно. Оставшийся блок памяти (со страницы 62 на стр. 255 в устройствах с высокой плотностью и со стр. 62 на стр. 127 в устройствах линии связи) сразу защищен от записи.

В устройствах с низкой и средней плотностью защита от записи реализуется с гранулярностью по четыре страницы за раз.

Если на защищенной странице выполняется программа или операция стирания, флэш-память возвращает флаг ошибки защиты в регистре состояния флэш-памяти (FLASH_SR).

Защита записи активируется путем настройки байтов опции WRP [3:0], а затем применяя системный сброс для перезагрузки новых байтов опций WRPx.

Снятие защиты:

Чтобы отключить защиту от записи, предусмотрены два случая применения:

● Случай 1: защита чтения отключена после защиты от записи:

– Удалите всю область байтов опций, используя бит OPTER во флэш-памяти контрольный регистр (FLASH_CR)

– Запрограммируйте правильный код RDP 0x00A5 для снятия защиты с памяти. Эта операция сначала сделает общий сброс основной флэш-памяти.

– Сбросьте устройство (сброс системы), чтобы перезагрузить байты опций (и новый WRP [3:0] байт) и отключить защиту от записи

● Случай 2: защита чтения поддерживается активной после защиты от записи, полезная для программирования приложений с помощью пользовательского загрузчика:

– Удалите всю область байтов опций, используя бит OPTER во флэш-памяти контрольный регистр (FLASH_CR)

– Сбросьте устройство (сброс системы), чтобы перезагрузить байты опций (и новый WRP [3:0] байт) и отключить защиту от записи.

1.3 Опция защиты от записи блока:

Байты опций всегда доступны для чтения и защищаются от записи по умолчанию. Для того, чтобы получить доступ на запись (Программа / Erase) для опционных байтов, последовательность ключей (такой же, как для блокировки) должен быть записан в OPTKEYR. Правильная последовательность ключей дает доступ на запись к байтам опций, и это указывается OPTWRE в установленном регистре FLASH_CR. Доступ к записи может быть отключен путем сброса бит через программное обеспечение.

2 Описание байта опций:

Существует восемь опциональных байтов. Они настраиваются конечным пользователем в зависимости от требований приложения. В качестве примера конфигурации сторожевой таймер может быть выбран в аппаратном или программном режиме.

32-битное слово разделяется следующим образом в байтах опций.

Формат байта опций:

Организация этих байтов внутри информационного блока приведена в следующей таблице.

Байты опций могут быть считаны из мест памяти, перечисленных в следующей таблице, или из регистра байта Option (FLASH_OBR).

Прим.: Новые запрограммированные байты опций (пользователь, защита чтения / записи) загружаются после сброса системы.

Организация байт опций:

3 Уникальный идентификатор устройства (96 бит):

Уникальный идентификатор устройства идеально подходит:

● для использования в качестве серийных номеров (например, серийные номера USB-шнуров или другие конечные приложения)

● для использования в качестве ключей безопасности для повышения безопасности кода во флэш-памяти при использовании и объединении этого уникального идентификатора с программными криптографическими примитивами и протоколами перед программированием внутренней флэш-памяти

● активировать безопасные процессы загрузки и т. д.

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

Читайте также: