Этот ценник, но чёрно-белый, без красного цвета Одному из членов нашего сообщества удалось приобрести на eBay несколько дисплеев e-ink. Эти дисплеи используют в магазинах, где на них указывается цена товаров, которые можно купить. По сравнению с бумажными ценниками такой дисплей имеет два ключевых преимущества: текст на e-ink дисплеях может обновляться автоматически и может иметь более замысловатую графику. От обычных ЖК-экранов e-ink отличается тем, что энергия расходуется только при изменении содержимого. Это позволяет оснастить ценники батареей небольшой ёмкости и работать без замены батареи несколько лет. Человек, который купил эти ценники, хотел использовать их в проекте, но не нашёл никакой документации о том, как общаться с ними, чтобы выводить что-либо на экран. Они подарили три устройства Zeus с условием наладить связь и изобразить что-либо на экране. Согласно книге Эндрю Хуана The Hardware Hacker, это идеальное количество устройств.1: После аккуратной разборки корпуса печатную плату удалось рассмотреть поближе. На этой печатной плате находились экран e-ink и аккумулятор, подключённый к ней. Батарея была немедленно отсоединена (в качестве меры предосторожности, чтобы ничего не замкнуть). Затем были сделаны фотографии передней и задней частей печатной платы, пояснения по элементной базе. 
Передняя сторона платы 
Задняя сторона платы Это SES-imagotag G1 2.7 BW NFC, код продукта — B27N02003. На плате есть текст: RFRTx002D и KIM 1514 (наверное, это обозначения элементов внутри платы), а также (скорее всего) кодовое обозначение даты: 09 17 (сентябрь 2017). Сама печатная плата имеет очень профессиональную конструкцию с большим количеством тестовых точек и площадок для программатора. К экрану прикреплена NFC-метка, содержащая идентификатор платы. На плате установлен микроконтроллер CC2510. Он может обмениваться данными на частоте 2,4 ГГц, и очевидно, что эта функция в продукте используется: на плате присутствует контур антенны. Вполне вероятно, что обновление изображения происходит по беспроводной связи через эту антенну. Остается только выяснить, как выглядит протокол связи. К сожалению, у нас нет сопутствующего устройства, которое выводит изображение на экран, поэтому перехват беспроводной связи невозможен. Но возможно прочитать код микроконтроллера и посмотреть, чего он ожидает. Изображения печатной платы были преобразованы и наложены друг на друга в GIMP. Передний и задний слои печатной платы были помещены в разные слои GIMP, чтобы можно было легко переключаться между разными видами без потери позиционирования. При маршрутизации сигналов между участками платы разработчикам печатных плат иногда приходится использовать так называемые сквозные межуровневые контакты (vias) с передней на заднюю сторону платы. Из маркировки «1 TOP» и «4 BOT» становится ясно, что плата — четырёхслойная. «Слоёный пирог» включает два видимых уровня разводки и ещё два между ними. К счастью для меня, кто-то другой уже протравил и сошлифовал плату до скрытых уровней. Это, правда, была немного другая версия, но бо́льшая часть элементной базы находится более или менее на тех же местах. Прочитав техописание (datasheet) CC2510, я уяснил, что это интерфейс отладки. С помощью такого отладчика можно передавать код на плату, прогонять код пошагово при отладке.и даже выводить код. У отладчика два сигнальных вывода: для того, чтобы задать тайминг хоста с микроконтроллера, и для двустороннего обмена данными. При запуске отладчика на таймер подаётся два импульсных сигнала при низком логическом состоянии вывода сброса. То есть в общей сложности к плате нужно подключить 5 проводов: тайминг отладки (debug clock), данные для отладки (debug data), сброс (reset), а затем заземление и питание 3,3 В для запитки самой платы. 
Плата на держателе, распечатанном на 3D-принтере, отладочные выводы подключены к плате Pi Pico. Батарея на заднем плане отключена. В микроконтроллере CC2510 стоит 8051-е процессорное ядро. Оно имеет довольно-таки старый 8-битный набор инструкций, изначально созданный Intel, но используемый во многих встроенных схемах. Большинство функций в этом отладчике реализовано довольно нетривиально 
Таблица 45 — Команды отладки Мы подключили выводы CC2510 к микроконтроллеру Raspberry Pi Pico и написали небольшую программку на базе ESP_CC_Flasher для сообщения с отладчиком микроконтроллера. Но вскоре открылось одно досадное обстоятельство: микросхема имела алгоритм блокировки отладки (debug lock): по замыслу производителя после программирования прошивки микроконтроллера интерфейс отладки отключался. Таким образом, активной осталась лишь очень малая часть инструкций отладки. Работали только READ_STATUS (по которой мы, как и все остальные, могли увидеть, что микросхема заблокирована), GET_CHIP_ID (по которой мы могли узнать тип микросхемы) и CHIP_ERASE (для стирания разрядов защиты от отладки и всего остального кода). Никаких функций о том, как можно прочитать плату, мы не нашли. Тогда мы задались новой целью — обойти защиту от считывания кода. Изначально мы хотели дать команду CHIP_ERASE и тут же отключить питание платы в надежде, что биты блокировки отладки будут сброшены раньше, чем сотрётся вся flash-память. Увы, это не сработало. Подозреваю, что после подачи команды CHIP_ERASE во flash записывается бит, который указывает, что подан запрос на стирание. Этот бит, как я понимаю, проверяется где-то в процедуре запуска, после чего вся прошивка стирается до тех пор, пока не сотрётся этот злополучный бит. Я, конечно, слегка расстроился, что стёр плату и превратил её в бесполезный кирпич. Но потом вспомнил совет Эндрю о том, что нужно иметь под рукой заведомо неработающее устройство. Эта стёртая плата ещё пригодилась мне, чтобы протестировать другие эксплойты, не боясь случайно стереть или сломать её, ведь она уже была стёрта. После первой неудачи мы попробовали другой способ — «заглючить» схему скачками напряжения. Это эксплойт, при котором вы на очень короткое время меняете напряжение микросхемы. Иногда это приводит к неожиданному поведению, например пропуску определённых инструкций в программе или загрузке из памяти другого значения. Мы надеялись, что, поменяв напряжение в нужный момент, сможем обойти защиту и при этом выполнить инструкцию отладки, которая блокируется. Для разработки такого эксплойта обязательно внимательно изучить техописание микросхемы, ведь иногда там можно найти подсказки о том, что делать дальше. В данном случае мы нашли несколько интересных моментов: Это означает, что для каждой «интересной» отладочной инструкции микросхема, вероятно, сначала извлекает из flash-памяти бит блокировки, а затем проверяет, разрешена ли такая команда. Для READ_STATUS используется значение последней инструкции отладки. Это очень полезно: если мы «глючим» инструкцию отладки, то сможем вызвать команду READ_STATUS и посмотреть, всё ли у нас получилось. Если эта команда покажет, что микросхема разблокирована, мы будем знать, что предыдущая инструкция выполнена успешно. К сожалению, это означает для нас и то, что для каждой инструкции отладки нужно успешно «глючить» плату. Это усложняет задачу, ведь велик риск перезагрузить этими скачками напряжения микроконтроллер, что сведёт к нулю весь прогресс в играх с напряжением. Таким образом, нам пришлось сосредоточиться на считывании данных наименьшим числом последовательных инструкций, и все они должны сработать успешно. 
Цоколёвка CC2510 На схеме цоколёвки обращает на себя внимание один конкретный вывод, DCOUPL: Микросхема запитывается от 3,3 В. Ни у одного внешнего вывода нет логических уровней, соответствующих 1,8 В. Поэтому на первый взгляд кажется странным, что у этой схемы есть питание на 1,8 В. На самом же деле это довольно частое явление: 1,8 В, скорее всего, нужны узлам внутренней логической схемы микроконтроллера (ЦП, RAM, flash и др.) Для сглаживания внешнего питания 1,8 В вывод DCOUPL должен быть подключён к наружному конденсатору. То есть у нас есть прямое подключение к внутреннему источнику питания, что очень удобно. Чтобы «заглючить» микроконтроллер, понадобятся умения ювелира: мы выпаяем развязывающий конденсатор и подключим «быстрый» полевой МОП-транзистор (в качестве цифрового ключа) к выводам DCOUPL и заземления. При включении МОП питание 1,8 В «закоротится на землю» и чип «заглючит». Успешный «глитч» становится вопросом точной синхронизации скачка напряжения и включения МОП-транзистора на нужное время. Синхронизация должна быть очень точной, вплоть до наносекунд. По сути, внутри последовательности отладки нам нужно на очень короткое время подтянуть вывод в высокое логическое состояние. 
Микроконтроллер крупным планом. Конденсатор DCOUPL, который нужно выпаять, отмечен оранжевым. 
Микроконтроллер крупным планом после подключения МОП-транзистора к выводу DCOUPL До этого мы использовали для сообщения с платой Raspberry Pi Pico. Для синхронизации скачков напряжения используем свойство PIO (programmable IO) микросхемы Pi Pico RP2040. Эта крутая микроконтроллерная плата позволяет задавать выводам тактовую частоту микросхемы. То есть мы можем получить сигнал с частотой 125 МГц. Мы можем подать сигнал на периферию PIO при помощи прямого доступа к памяти (DMA). Так можно делать что-то другое в тот момент, когда фоном будет подаваться наш глитч-сигнал. При этом весь буфер вывода, на который мы его подаём, за исключением позиции с парой последовательных единиц, заполняется нулями. Для большей эффективности взлома идею пришлось слегка доработать: Теперь нужно составить набор отладочных инструкций так, чтобы «запрещённых» инструкций было как можно меньше, ведь каждая из них связана с риском перезагрузки платы. Это сводилось к изучению набора инструкций для 8051-го ядра и поиску наборов инструкций, которые загружают данные с определённого адреса в накопительный регистр (который возвращал данные после каждой инструкции). В конечном счёте задача была сведена к двум инструкциям: MOV DPTR,#data16 (загружает 16-битную постоянную по адресу DPTR/указателя данных) MOVX A,@DPTR (загружает из памяти DPTR в накопительный регистр) Тогда полная побайтная последовательность отладки будет выглядеть так: 
Вид последовательности отладки в логическом анализаторе. Инструкции отладки разделены оранжевыми линиями, время подачи глитч-сигнала показано красными линиями. Развёртка параметров по всей временной шкале последовательности отладки и по длительности глитча помогла нам найти уязвимость DEBUG_INSTR: если подать питание сразу после DEBUG_INSTR, иногда блокировка отладки обходится, что приводит к выполнению DEBUG_INSTR и «правильному» ответу накопительного регистра. Последующая инструкция READ_STATUS показывает, что блокировка снята. Однако, если мы дадим ещё одну DEBUG_INSTR, микроконтроллер снова будет заблокирован и эта инструкция не пройдёт. Таким образом, для считывания одного байта данных нам нужно два успешных глитча, а по ответам READ_STATUS мы узнаем, сработал ли наш взлом. Чтобы увеличить шансы на успех такой атаки, нужно точно настроить параметры. Эта настройка очень чувствительна к паразитным эффектам Если слегка коснуться платы или чуть сдвинуть её с места, настройка параметров сбивается и калибровку параметра глитча приходится начинать заново. Лучший процент успешных попыток на один глитч, которого нам удалось достичь, это около 5%, но после длительной работы он стремительно падает, вероятно, из-за нагрева. Для успешного чтения байта нужно два успешных глитч-сигнала, поэтому процент успешных попыток чтения будет всего 5% * 5% = 0,25% (если считать попытки глитча взаимонезависимыми). В секунду можно провести 35 попыток, таким образом, за каждые 20 секунд можно прочитать 1 байт. На считывание всего объёма данных flash-памяти 32 Kб уйдёт около 4 дней. Атака разрабатывалась и тестировалась на стёртой плате. При этом было подтверждено, что считываются корректные данные. 
Гистограмма количества успешных глитчей на 10000 попыток. По оси X отложено смещение глитча по времени, длительность глитча составляет 8. Чтобы атака была более практичной, скрипты были перенесены на сервер в подвале здания Zeus WPI. Запуск глитч-скриптов осуществлялся в рамках сессии tmux, поэтому атака могла проходить в фоновом режиме, а мы наблюдали за ней. Через пару дней скорость считывания данных значительно снизилась, и потребовалась повторная настройка параметров. Считывание данных с микросхемы проходит довольно медленно. Это связано с нашими приоритетами: во-первых, экономия (общая цена всего «железа» составляет всего 10 евро), а во-вторых, простота и воспроизводимость. Процент успешных попыток можно повысить несколькими способами: Некоторые другие РЧ-микросхемы Texas Instruments используют тот же протокол отладки (ChipCon) и встроенное 8051-е процессорное ядро. Их шифр (part number) имеет вид CCxxxx. Эти микросхемы, вероятно, уязвимы к тем же атакам. Вот их неполный список: Компании Texas Instruments об этой уязвимости не сообщалось, поскольку у них уже есть инструкция по безопасности (security advisory), где учтены атаки методом внесения неисправностей (fault injection attacks) во все микросхемы: она находится по адресу TI-PSIRT-2021-100116, озаглавлена Physical Security Attacks Against Silicon Devices и опубликована 31 января 2022. Там есть раздел Affected products and versions: Когда они говорят, что каждое устройство уязвимо, если нет заявлений об обратном, и что они даже не обязаны писать о неустранённых уязвимостях в техописаниях и в инструкциях по безопасности, это звучит неубедительно. Поскольку маловероятно, что против рассматриваемой аппаратной атаки есть какая-то защита, кроме изменения топологии, едва ли Texas Instruments выпустит хотя бы инструкцию по безопасности по этому поводу. На момент написания этой статьи удалось считать 30,19% от 32 Kб flash-памяти ценника e-ink. Эта память была загружена в Ghidra (фреймворк декомпиляции), с помощью которой мы подтвердили, что слитый нами код является корректным и значимым кодом 8051-го ядра. В следующей статье (надеюсь) будет подробнее написано об обратном проектировании протокола и о том, как общаться с ценниками e-ink. Весь хакерский код доступен в этом репозитории. Спасибо pcy за ответы на многие вопросы и опасения по поводу глитч-атак. Если у вас остались вопросы, комментарии или неясности, пишите мне на почту (j@zeus.ugent.be).  Data Science и Machine Learning Python, веб-разработка Мобильная разработка Java и C# От основ — в глубину А также