
Доклад о том, как взломали Xbox One
Первый в истории взлом Xbox One: Маркус Скотт рассказывает, как после 10 лет исследований ему удалось взломать загрузочное ПЗУ консоли, получив абсолютный, не поддающийся патчам контроль над системой.
Мнение автора
Я помню эпоху Xbox 360, когда каждая новая ревизия консоли была вызовом для сцены. Но то, что сделал Маркус — это даже не следующий уровень, это другая вселенная. Microsoft настолько закопала голову в песок, встроив рандомизированные задержки прямо в кремний, что сообщество просто сдалось. И вот появляется парень, который говорит: "А давайте выковыряем этот кремний и посмотрим, как он дышит".
Самое гениальное в его подходе — это даже не сами глитчи, а то, как он построил интроспекцию там, где её быть не могло. Превратить аналоговые провалы питания в цифровые сигналы, чтобы подсмотреть, как чип читает собственные перемычки — это чистая магия. Теперь у нас есть консоль, которую можно чинить, сохранять игры и не бояться, что сервера Microsoft когда-нибудь отключат вашу библиотеку. Это победа инженерной мысли над корпоративной паранойей.
(видео с титрами на русском языке)
Оглавление
ToggleВзлом Xbox One (обзор)
На конференции был представлен сенсационный доклад о первом в истории взломе Xbox One. С момента выхода в 2013 году консоль считалась одной из самых защищённых: Microsoft внедрила многоуровневую систему безопасности с аппаратной изоляцией, рандомизированными задержками, отключёнными пост-кодами и невозможностью замедлить тактовую частоту. Главная цель атаки — неизменяемое загрузочное ПЗУ (boot ROM), компрометация которого открывает доступ ко всей системе.
Исследователь Маркус Скотт, ранее уже выступавший с темой по оригинальной Xbox, решил вернуться к «неберущейся» консоли. Работа началась с полного отсутствия инструментов отладки: нет UART, JTAG, даташитов. Единственным источником информации стали аппаратные сигналы.
С помощью шунтирующих резисторов и осциллографа Скотт научился снимать трассировку питания и анализировать поведение чипа. Выяснилось, что Microsoft встроила в boot ROM 37 случайных задержек (рандомизированных «зависаний»), чтобы затруднить синхронизацию глитч-атак. Однако удалось обнаружить несколько устойчивых сигналов, которые можно использовать для привязки глитчей: линия DAT0, инициализация GPIO и, позднее, чтение eFuse.
Первый прорыв произошёл после переключения на линию питания северного моста. Удалось вызвать сбой, в результате которого включились аппаратные пост-коды (раньше они были отключены перемычками). Это позволило в реальном времени отслеживать ход выполнения кода и локализовать уязвимые места.
Следующим шагом стала атака на функцию копирования памяти (memcpy) при загрузке заголовка следующего загрузчика (SP1). Подбирая момент глитча, исследователь смог пропустить одну инструкцию в конце memcpy, что привело к тому, что регистры не восстановились, а значение счётчика команд (PC) было заменено на данные, записанные во флеш-память (паттерн 0x58585858). Так был получен произвольный контроль над PC, но из-за включённого блока защиты памяти (MPU) дальнейшие действия были ограничены.
Чтобы обойти MPU, потребовалось разработать второй глитч — на этапе инициализации MPU. Анализ трассировок питания и чтений eFuse позволил точно синхронизировать момент сбоя. В результате удалось пропустить включение MPU, и система осталась с полностью открытой памятью.
Объединение двух глитчей (сначала на MPU, затем на memcpy) дало полный контроль над процессором безопасности (PSP) на самой ранней стадии загрузки — ещё до проверки подписей, расшифровки ключей и проверок отзыва. В итоге были извлечены все eFuse, расшифрованы все последующие загрузчики (SP1, SP2, прошивки), и появилась возможность выполнять неподписанный код на любом уровне — от PSP до гипервизора и игровой ОС.
Этот взлом носит аппаратный характер и не может быть исправлен программным обновлением. Он позволяет восстанавливать «кирпичные» консоли (например, заменять вышедшие из строя приводы или перепривязывать NAND), а также открывает путь для сохранения цифрового наследия Xbox One, так как теперь можно расшифровывать любые игры и обновления.
В заключение Маркус отметил, что для повторения атаки достаточно всего трёх проводов, а не той сложной лабораторной установки, которая использовалась для исследований. Он также подчеркнул, что вернулся к этой задаче не ради пиратства, а ради вызова — «потому что никто другой не смог».
Полный текст доклада Маркуса Скотта о взломе Xbox One
Доклад Маркуса Скотта о взломе Xbox One на конференции (расшифровка)
[Ведущий, Джордан]
Зал, наверное, должен заполниться ради этого. Это то, что вы не захотите пропустить. Это буквально мировая премьера, эксклюзивный разговор. Так что… это волнительно. Представители служб безопасности из нескольких компаний писали на электронную почту: «Подождите, это уже публичная уязвимость? О ней уже сообщили? Расскажите подробнее, пожалуйста. Я не хочу портить сюрприз». Если вы были здесь в прошлом году, или даже видели выступление онлайн, вы знаете, что это был наш самый высоко оцененный доклад в прошлом году — предыдущая версия этого доклада от Маркуса. И он стал только лучше. Вам не нужно много представлять. Это будет один из лучших докладов, если не самый лучший, который вы увидите в эти выходные, я обещаю. Пожалуйста, поприветствуйте Маркуса Гастеллана.
[Маркус Скотт]
Хорошо. Эм, привет всем. Меня зовут Маркус Скотт, и да, как сказал Джордан, вас ждет еще один очень особенный доклад в этом году. В прошлом году я выступал на Reverse с докладом об оригинальной Xbox 2001 года. Для меня тот доклад был скорее о страсти, чем об Xbox. Но если вы хотите узнать больше обо мне и моей истории, сначала посмотрите то выступление. Это прекрасная первая часть к этому докладу, и она поможет заполнить пробелы в том, как мы сюда попали.
Итак, в этом году мы поговорим о взломе Xbox One. Xbox One была третьей крупной игровой консолью Microsoft. Она была очень ожидаемым преемником Xbox 360, но её анонс на E3 в 2013 году был печально известен своей непопулярностью. Microsoft пыталась продвинуть модель с постоянным подключением к сети для DRM и позиционировала Xbox One в первую очередь как домашний медиацентр, а во вторую — как игровую консоль, оттолкнув свою основную аудиторию, и с тех пор бренд как бы истекает кровью.
Но Microsoft всё же сделала по крайней мере одну вещь правильно, потому что взлом игровых консолей и запуск произвольного кода — это своего рода обряд посвящения для каждого поколения. Но в 2013 году некий железный занавес опустился в сфере безопасности экосистемы Xbox. И Xbox One никогда не была взломана, как и ни одна из её преемниц. И даже совсем недавно, в 2020 году, через 7 лет после её запуска, Microsoft описала Xbox One как самый безопасный продукт, который Microsoft когда-либо производила, возможно, самый безопасный продукт из существующих. Не уверен, что я полностью с этим согласен, но они проделали отличную работу.
Итак, это консоль, которую я купил десять лет назад, когда ещё учился в колледже. И вот я спрашиваю себя 12 лет спустя, почему её так и не взломали? Что за чёрную магию Microsoft могла в неё вложить? Почему консоли Sony, PlayStation, Nintendo продолжают взламывать? Что делало Xbox One такой особенной?
Если вы хотите получить представление о комплексной стратегии, которую Microsoft применила для усиления платформы, я настоятельно рекомендую посмотреть выступление 2019 года Тони Чена, который помогал проектировать архитектуру безопасности Xbox One. Он в общих чертах описал стек безопасности Xbox One по уровням, в значительной степени опираясь на компартментализацию, виртуализацию и отзыв (revocation). И пока они усиливали каждый уровень против компрометации, Тони также подчеркнул, что вся цепочка доверия действительно зависит от их способности сохранять контроль над загрузочным ПЗУ (boot ROM). Он сказал: «Единственная программная ошибка, от которой мы не можем оправиться, — это ошибка в загрузочном ПЗУ».
И это забавная диаграмма, которую один из моих друзей сделал в 2024 году о нашем прогрессе во взломе Xbox One как сообщества. И в основном ничего не было достигнуто, но с этим докладом мы идём прямо на вершину. И я сказал: если я собираюсь вернуться, чтобы взломать Xbox One, я вернусь не за 30%. Я вернусь за всем. И этот доклад исследует, каково это — охотиться на драконов и взяться за задачу, которую многие считали невозможной. К концу доклада мы получим выполнение кода в загрузочном ПЗУ Xbox One. Это по сути аппаратный взлом с правами бога, который нельзя исправить патчем.
Итак, я буду быстро пролистывать материал, потому что у нас очень много слайдов, так что извините, если я буду щёлкать их немного быстро, но вы сможете посмотреть это позже, когда оно появится в сети. Эта работа датируется началом 2024 года, над которой я работал, но довольно внезапно остановился по личным причинам. Последние пару лет я в основном занимался ИИ. Но некоторые очень добрые и вдохновляющие люди убедили меня вернуться, немного покопаться в железе, завершить эту работу и прочитать этот доклад. Так что это первый раз, когда я публично говорю о технических деталях, лежащих в основе этого взлома. Я хотел представить его на конференции и в сообществе, которое мне дорого. Вот почему мы здесь.
И да, я не собираюсь говорить ни о чём, кроме загрузочного ПЗУ. У Xbox One много уровней. Меня интересует только загрузочное ПЗУ. Вот что я изучал. И если мы скомпрометируем загрузочное ПЗУ, мы скомпрометируем всё. Итак, пришло время разобрать консоль. Это довольно стандартная консоль для 2010-х: жёсткий диск, оптический привод. Это материнская плата, SOC, и это та самая микросхема, которую мы и пытаемся взломать. Это специализированный SOC, разработанный совместно Microsoft и AMD. Технология 28 нанометров. Это одновременно и CPU, и GPU. А также в нём есть целая подсистема безопасности. Мы будем в основном говорить о процессоре безопасности платформы (platform security processor). Но это снимок кристалла кремния, и вы можете видеть здесь всё это. И вот в правом нижнем углу находится PSP, но конкретно этот маленький белый прямоугольник — это загрузочное ПЗУ. И если вы увеличите это, этот маленький массив, по сути, содержит загрузочное ПЗУ. Там есть два загрузочных ПЗУ. Мы будем говорить только о загрузочном ПЗУ безопасного состояния (secure state boot ROM). Я не буду описывать процесс оптического извлечения загрузочного ПЗУ из кремния, потому что, честно говоря, у нас нет времени, и это наименее интересная часть этого доклада. И я также хочу прояснить, что это загрузчики Microsoft. Были исследования AMD и PSP в прошлом, но это в основном код AMD. И есть некоторая дезинформация, что я взломал какое-то оставшееся загрузочное ПЗУ AMD или код. Что не соответствует действительности. Они полностью написаны Microsoft. Тони Чен даже сказал это в своём выступлении в 2019 году. Его команда написала прошивку для процессора безопасности на Xbox One.
Итак, давайте поговорим о процессоре безопасности платформы. PSP — это аппаратный корень доверия для Xbox One. На самом деле это ARM Cortex R4, втиснутый в угол между всеми этими ядрами GPU и CPU. Он поддерживается, опять же, CCP и SCP, то есть крипто-процессором и потоковым крипто-процессором ядра безопасности. И у него есть этот MPU с 12 регионами, о котором мы поговорим чуть позже. Который он использует для аппаратно-обеспеченной изоляции памяти среди кучи других средств защиты, которые они туда впихнули.
Итак, мы будем говорить только о загрузочном ПЗУ. Есть и другие фазы выполнения процессора безопасности, но мы пытаемся атаковать неизменяемое загрузочное ПЗУ, потому что если мы пройдём через него, мы получим всё, что идёт после. Итак, это просто высокоуровневая диаграмма процесса загрузки Xbox One. Левая сторона — это, по сути, комплекс безопасности. Ядро ARM запускается первым до всего остального, и оно затем считывает более поздние этапы своей загрузки, а также расшифровывает сторону x86, помещает её безопасно в память x86 и сбрасывает x86. Опять же, нас интересует только атака на это. Мне не пришлось изучать всё остальное, потому что если мы сможем сломать это и средства защиты в нём, то мы получим всё, что идёт после.
Итак, код загрузочного ПЗУ Xbox One прост. Он линеен и очень хорошо проверен. Они его вычистили до чёртиков. Там нет программных ошибок. Но здесь важно провести различие: есть огромная разница между написанием кода без ошибок и проектированием безопасного, отказоустойчивого кода. Кое-что из того, что делала Microsoft в 2012-2013 годах при разработке этого, было, возможно, на десятилетие впереди того, о чём люди думали в отношении внесения сбоев (fault injection) и защиты от них. Так что нам придётся сразу перейти к аппаратным атакам.
Итак, это я впервые достаю материнскую плату, кладу её на свой стенд. Я никогда в жизни ничего не глитчевал до этого, и я выбрал для глитчевания ту самую вещь, которую никто не мог заглитчевать до этого, как свою первую цель. Итак, я возвращался к размышлениям о том, как исторически делался глитчинг на Xbox, просто из любопытства. Очевидно, я читал все статьи по глитчингу, внедрению по напряжению, внесению сбоев, EMFI и прочее. Xbox 360 в основном взламывали, используя эти три ключевые точки. Пост-коды помогали измерять прогресс во время загрузки. Они вставляли свой глитч на пин сброса (reset pin), что довольно интересно. Мы не будем много говорить об этом, потому что у нас нет времени. Так что мне нужно двигаться дальше.
Вот как примерно выглядела разводка на Xbox 360, когда люди её глитчевали. Глитчинг Xbox One. Microsoft усвоила урок. Они избавились от пост-кодов. В загрузочном ПЗУ и загрузчике первой стадии SP1 пост-коды скомпилированы, но они фактически отключены e-физами. E-физы — это однократно программируемые перемычки, погребённые в SOC, которые они могут программировать для каждого чипа, если захотят. Нет пина сброса. Microsoft решила: «Мы не позволим людям вносить сбои на этот пин сброса», что, я думаю, интересно и забавно. И нет способа замедлить тактовую частоту, что помогло бы с надёжностью.
Но у меня практически нет аппаратной интроспекции. У меня есть некоторое представление о том, что мы атакуем, потому что у нас есть оптическое извлечение загрузочного ПЗУ, но на этой штуке нет UART. Нет пост-кодов, нет отладки по J-TAG, нет datasheet, нет отладочных чипов, на которых я мог бы попытаться запустить свой код и понять, как ведёт себя чип, нет отладки, нет прототипов, ничего.
Итак, один из моих друзей сказал мне с самого начала: «Без трассировки питания мы глитчевали полностью вслепую», описывая, каково это — пытаться глитчевать цели, с которыми вы, возможно, не так знакомы. Трассировка питания даёт некоторое понимание фаз выполнения чипа, на который вы смотрите. Здесь можно видеть, как трассировка питания немного меняется. Это как побочный канал, чтобы понять, сколько энергии потребляет чип. Итак, я перечислил все линии питания SOC. Их на самом деле много. Я точно не знаю, что ищу. Понятия не имею, на какой линии может работать процессор безопасности. Поэтому я выбрал линию 1.8 вольт, думая, может, она стабилизируется от неё. Я не совсем уверен. И я начал пытаться собирать трассировки питания. Но я никогда раньше не занимался побочными каналами питания. Я не знаю, что выглядит хорошо или плохо, но я начал немного лучше в этом разбираться. Это просто очень простая реализация побочного канала питания, по сути, с использованием шунтирующего резистора. Есть несколько способов делать дифференциальный анализ питания, но я выбрал этот. Он дешёвый и эффективный.
Но, по сути, я начал получать трассировки питания. Они стали выглядеть немного лучше. Можно начать видеть некую структуру. Этот синий сигнал — то, что я использовал для примерного анализа загрузки процессора безопасности или всего APU, я полагаю. Это сигнал Power OK, а зелёный — это трассировка питания. Но я продолжал смотреть на эти трассировки питания. Я продолжал возиться с установкой, пытаясь изменить шум, пытаясь посмотреть на разные доступные мне фильтры. И я просто… я не мог понять ничего. Я видел некоторую структуру, но она не совсем соответствовала тому, что я ожидал, исходя из проделанной мной обратной разработки загрузочного ПЗУ. И тогда я начал охотиться за другими сигналами. Это моя плата, я просто маркирую вещи, пытаюсь прощупать контакты. И я нашёл этот другой сигнал, который является сигналом прерывания, который PSP отправляет в южный мост (south bridge) или SMC. И я начал смотреть на это. Я такой: «Окей, у нас есть новый сигнал на ранней стадии загрузки». Вы можете видеть некоторую корреляцию на трассировке питания. Возможно, здесь это трудно разглядеть. Но эта нижняя синяя штука. Однако, когда я продолжал снимать эти трассы, я заметил, что она менялась при каждой загрузке. И я такой: «Ой-ой».
По сути, то, что мы видим, — Microsoft вставила рандомизированные задержки (stalls) в загрузочное ПЗУ Xbox One. Я провёл много анализа данных, чтобы понять их. Мне удалось использовать разные сигналы, чтобы изолировать некоторые из задержек, так что я мог видеть одну задержку, а также область с двумя и множественными задержками. Но в итоге я понял, что во всём загрузочном ПЗУ есть 37 случайных задержек. Жутко раздражает, потому что по сути это как ASLR для таймингов глитчей. Мы не можем просто жёстко задать глитч на 1.3872 миллисекунды и так далее, потому что каждая задержка происходит в случайное время и может длиться случайное количество времени. Нам нужно найти способы надёжно привязывать наши глитчи внутри загрузочного ПЗУ. Здесь, наверху, это, вероятно, трудно увидеть, но это просто маленькая забавная вещь, которую я сделал, чтобы визуализировать выполнение SP0. Все эти оранжевые полосы на самом деле являются случайными задержками. Загрузочное ПЗУ выполняет около 300 000 инструкций в среднем. И почти около 150 000 из них будут в рандомизированных циклах ожидания, делая абсолютно ничего.
Следующее, к чему я перешёл, был трафик I2C. I2C — это простая двухпроводная последовательная шина для чипов. Вот где я подключился. Слева вы можете видеть некоторые другие сигналы, которые я подключил до сих пор. Это скриншот с моего логического анализатора разных сигналов, на которые я смотрю, чтобы попытаться изучить загрузку. Вы можете видеть эту вспышку данных, исходящую по шине I2C, и это какие-то диагностические данные при загрузке, которые выходят при каждой загрузке. Там есть ID вашего SOC, биты мониторинга напряжения, температуры и тактовой частоты как побочный канал, биты нарушений памяти и внутренней шины. Там много действительно интересных вещей. TL;DR, это не сыграло слишком большой роли в этом взломе. Но несколько других вещей могут появиться на шине I2C. Если включены, пост-коды прогресса будут выходить на эту шину, но они фактически отключены перемычками. А коды фатальных ошибок включены. Но они будут выданы, только если консоль крэшнется во время загрузки, и это даёт нам намёк на то, куда мы движемся.
Но я решил: «Ладно, я получаю некоторое понимание происходящего. Давайте попробуем глитчевать, чтобы увидеть, изменятся ли данные I2C». Итак, мы собираемся делать глитчинг по напряжению методом «crowbar». Глитчинг по напряжению, конкретно crowbar-глитчинг, — это просто дешёвая и эффективная техника внесения сбоев, когда вы пытаетесь обрушить линию питания в очень точный момент. Это может дестабилизировать ядро и вызвать странные вещи, такие как повреждение инструкций. Это я. Этот зелёный провод — это то, чем я буду заземлять линию. Мои первые глитчи были абсолютно ужасны. Они совсем не похожи на осмысленные глитчи. Лучший глитч выглядел бы примерно так. Я усвоил несколько уроков и начал создавать некоторую автоматизацию для управления платой, чтобы я мог перезагружать её сотни или тысячи раз. У меня есть небольшая настройка для управления этой атакой в автоматическом режиме и, возможно, запуска глитчей. Вот как это начало выглядеть. Вы видите трассы питания. Система очевидно перезагружается. Она просто работает в цикле. Затем я пытаюсь сделать глитч, но ничего полезного не происходит. Я начал, но у меня появилась некоторая аппаратная интроспекция. Я начинаю наслаивать сигналы друг на друга, и я создал базовую автоматизацию, чтобы запускать множество попыток. Я просто не получаю фатальных ошибок или изменений, которые я ожидал увидеть от системы. Частично это было потому, что я глитчевал неправильную линию питания, потому что, опять же, я никогда в жизни ничего не глитчевал.
Итак, я двинулся дальше. Я снова посмотрел на список и попытался изолировать те, про которые я подумал: «Не думаю, что мне стоит на них глитчевать». И я остановился на линии питания ядра северного моста (north bridge core rail). Я не буду слишком подробно объяснять про северный мост, но по сути северный мост — это что-то вроде фабрики чипа, но он также может содержать такие вещи, как подсистемы управления системой. Вещи, которые могут выполняться до загрузки или соединять разные ядра. Но я начал удалять SMD-конденсаторы с линии питания ядра северного моста под APU, что является распространённой техникой при глитчинге по напряжению. Я изолировал линию питания ядра северного моста, удалил с неё все конденсаторы и поставил свой собственный шунтирующий резистор, чтобы можно было делать этот побочный канал по питанию, и я ввёл своё собственное малошумящее питание в неё, и я действительно начал видеть некоторую структуру. Увеличивая масштаб, я особенно начал видеть некоторую структуру вокруг сброса. Эта точка особенно привлекла моё внимание, потому что мои трассировки питания теперь, когда я немного отдалился, всегда продолжали меняться после этой точки. И я подумал: «Что происходит с этой точкой?» Но если немного прищуриться, можно начать видеть эти маленькие вещи здесь. Я такой: «Это задержки, возможно?» И я продолжал их видеть, но они не имели смысла. Они были не там, где я ожидал увидеть задержки. А это на самом деле сбор энтропии от кольцевых генераторов для аппаратного ГПСЧ каждую 1 миллисекунду. Мне потребовалось две недели вглядывания в эти чайные листья, чтобы это понять. Но это заставило меня осознать, что именно здесь крипто-процессор и ГПСЧ инициализируются загрузочным ПЗУ. Теперь у меня есть такой ориентир, который я понимаю. И, исходя из моего анализа задержек, я примерно знаю, с какой скоростью работает этот процессор — 100 МГц. И я смог вычислить: «Ладно, подождите, это примерно там, где должно начинаться выполнение загрузочного ПЗУ». Всё, что до этого, — это предзагрузка, что тоже интересно.
Но у нас есть некоторые обновления. Наша аппаратная интроспекция улучшается. Мы довольно уверены, что нашли правильную линию питания для PSP. Она на ядре северного моста. Но одна из больших проблем в том, что мы всё ещё не можем отличить рандомизированные задержки от выполнения. Там происходит много всего другого. Опять же, извините, если я быстро перелистываю слайды. Люди смогут посмотреть это позже. Но пришло время перейти к пост-кодам. Пост-коды — это довольно стандарт в вычислениях. У вас, вероятно, есть пост-коды в вашем телефоне, в вашем компьютере. Это стандартный способ попытаться измерить индикаторы загрузки, например, правильно ли ваш компьютер запускается с аппаратного обеспечения? Некоторые примеры пост-кодов с Xbox One. Думайте о них просто как о байте, который выходит. Это просто индикаторы состояния. Они увеличиваются и как бы документируют ваш путь через загрузку.
На Xbox One, опять же, они отключили пост-коды перемычками. И я знаю это, потому что если бы они были включены, мы бы видели трафик от них на шине I2C. И Microsoft приложила огромные усилия, чтобы эти пост-коды нельзя было включить через повреждение перемычек и тому подобное. Но примерно через 2000 инструкций после сброса, то есть мы сейчас смотрим на ПЗУ, они инициализируют пины GPIO на случай, если пост-коды включены. И пост-коды, если включены, будут выходить на эти немаркированные, совершенно немаркированные контактные площадки GPIO, которые я там для вас раскрасил. И я такой: «Ладно, давайте просто подключу их и посмотрю, есть ли что-нибудь». И, конечно же, Microsoft сделала свою работу. Там нет пост-кодов. Вы можете видеть пост-коды, начинающие появляться на этих линиях в SB2, в более поздних загрузочных ПЗУ, загрузчиках. Они знают, что могут отозвать их (revoke), так что их не так сильно волнует безопасность этих, возможно. Но есть кое-что, что мы видим. Вы видите, когда они инициализируют GPIO… [пауза]
И я был очень взволнован этим. И я снова подключил это к своему осциллографу. Мы снова накладываем наши сигналы здесь. И теперь мы можем видеть, буквально где некоторые инструкции загрузочного ПЗУ соотносятся с трассировкой питания, с цифровыми сигналами и прочим. И сразу после GPIOInit они делают всю эту сумасшедшую логику, чтобы определить, включать ли пост-коды. Там куча ветвлений, куча рассуждений. И я такой: «Ладно, это выглядит очень глитчабельно. Если мы сможем попасть куда-нибудь сюда, пост-коды могут просто волшебным образом появиться». И поэтому, со всем, чему я научился, застряв на другой линии, я припаял свой MOSFET для глитчинга. У меня есть маленький монитор сбоку здесь, чтобы смотреть на него на осциллографе.
Впервые мы действительно получаем глитчи. Ой. Впервые мы действительно глитчуем ядро и что-то делаем. И эти маленькие жёлтые линии, которые вы видите колеблющимися, — это пост-коды, которые были включены. В норме эта линия должна всё время оставаться плоской. Вы видите, как я приближаю свой глитч по напряжению. И вскоре после этого вы видите, как пост-коды начинают появляться. Я загружаю систему сотни раз прямо сейчас. И это был действительно критический момент, потому что… мы застряли. Это был действительно критический момент, потому что он заставил меня осознать, что это ядро можно взломать. Я впервые реально влияю на него. Мне удалось продемонстрировать некоторое аппаратное влияние на него. Это просто увеличение моего глитча. Опять же, линия напряжения, а также GPIO на нём. И если глитч сработал, вы видите первый пост-код вскоре после. Это увеличено, чтобы вы могли видеть примерную форму моего глитча. Не то чтобы я сильно его настраивал, но он около 100 наносекунд или около того. 100-200 наносекунд. И да, это результат. Мы действительно начинаем видеть, как появляются пост-коды. Вот чего и следовало ожидать. Пост-коды отключены перемычками. Но когда мы их глитчем и включаем, у нас появляется вся эта новая активность, и мы можем начать изучать загрузку осмысленным образом. Я просто подключаю все линии пост-кодов к преобразователю уровня, чтобы с ними было легче работать на TNC и моём логическом анализаторе. Вот примерно как выглядит моя установка на этом этапе.
И да, вот наши обновления прогресса на данный момент. Мы продемонстрировали первые в истории осмысленные глитчи на Xbox One. Никто никогда этого не делал. Это действительно разрушило иллюзию, что этот чип невзламываем. Что даже боги могут истекать кровью, спустя всё это время.
Теперь мы поговорим о загрузочном ПЗУ на более техническом уровне. Это 64-килобайтное неизменяемое ПЗУ. Но только около 19 килобайт из этого — реальный код. В основном это Thumb-2. Опять же, это прямолинейный, одноразовый код, никакой сложной среды выполнения. И каждая инструкция извлекается из кремния каждый раз с проверкой ECC. Microsoft буквально встроила ECC-биты в кремний, что, я думаю, просто описывает те огромные усилия, которые они приложили для защиты этой штуки.
Но на высоком уровне обзора всех действий, которые он предпринимает и выполняет… Вы можете посмотреть на это позже. Опять же, одна из вещей, которая меня очень рассмешила, — это то, что там фактически двойные подписи, когда они пытаются загрузить и проверить следующую стадию. У них есть и RSA, и подпись на эллиптических кривых в заголовке на случай, если RSA взломают, не дай бог. Загрузочная цепочка Xbox One всё равно будет безопасной. Конечно, остальной мир будет гореть.
Многие люди, кроме меня, смотрели на это и говорили: «Никто не сможет сделать восемь глитчей подряд. Это невозможно». И да, они, вероятно, правы. Я такой: «Ладно, я собираюсь глитчевать что-то ещё». А именно, я глитчевал то место, где они пытаются получить заголовок следующей стадии. Итак, чтение заголовка SP1. Загрузчик SP1 — это, по сути, первый внешний загрузчик. Это 32-килобайтное ПЗУ. И загрузочное ПЗУ будет скрупулёзно проверять и проверять подпись этой штуки. Они выкладываются по полной. Это безумие. Просто изображая путь, который он проходит. Вот где находится первое внешнее загрузочное ПЗУ или загрузчик. Он находится во флэш-памяти NAND. Он проходит по двум шинам. Стандартная шина MMC/SDIO и более быстрая шина PCI через южный мост к PSP. Если мы посмотрим на код загрузочного ПЗУ, он извлечёт заголовок SP1 из флэш-памяти по PCI пакетами по 64 байта. По сути, это красная шина, которую вы видите. Это логика, взаимодействующая с этой красной шиной с правой стороны. Но я подумал: «Ладно, давайте посмотрим поближе на медленную шину». Потому что это то, что мы можем реально пощупать. Это около 25 мегагерц против, возможно, гигагерц на шине PCI. Если мы подключимся к одному из сигналов флэш-памяти, мы сможем увидеть, где загрузочное ПЗУ на самом деле читает следующие стадии. Итак, мы получаем ещё немного интроспекции. Мы наращиваем все наши сигналы. И затем вы можете видеть, где они читают заголовок следующей стадии, а затем 80 миллисекунд они делают все эти вещи, просто чтобы быть раздражающими. Они пытаются впихнуть туда всё. Они делают самотесты, пытаются проверить заголовок, делают проверки отзыва (revocation), много задержек, делают обёртывание ключей для расшифровки. И наконец, они начинают читать тело, а затем позже будут расшифровывать тело и всё такое.
Но нам нужно увеличить масштаб. Заголовок SP1 на самом деле читается двумя разными пакетами, потому что он почти 900 байт. Если вы знаете о дисках и MMC, секторы обычно 512 байт. Вы можете видеть, где шина MMC читает его, а затем где, по нашему предположению, должна происходить передача по PCI. Снова наша зелёная шина и наша красная шина. Мы не можем, опять же, мы не щупали красную шину, но можем предположить на основе таймингов, что происходит именно это. И затем это происходит снова. Опять два пакета, потому что они пытаются считать весь этот заголовок, потому что он такой большой, потому что они хотели поместить туда две подписи и все эти проверки. Наша цель — увидеть, сможем ли мы заглитчевать одну из этих PCI-передач.
Итак, что мы будем атаковать, так это memcpy. В частности, за последнее десятилетие memcpy в отношении внесения сбоев стала чрезвычайно привлекательной целью, потому что состояния выполнения внутри memcpy сильно загрязнены данными, контролируемыми атакующим. Дело не в том, что memcpy небезопасна или в ней есть ошибка. Дело в том, что если что-то пойдёт не так внутри memcpy, есть более высокий шанс, что всё пойдёт не так в вашу пользу. Думайте о memcpy как о трубе, через которую часто проходят данные, контролируемые атакующим. Но если вы ударите по этой трубе большим молотком, вода просто начнёт вытекать, верно? Могут произойти странные вещи. Глитч может повредить декодирование инструкции внутри memcpy, и все эти регистры, содержащие данные под контролем атакующего, могут превратиться в произвольную запись или захват PC.
Итак, что я сделал, я записал паттерновые данные, которые я контролировал, в eMMC или флэш-память, как любой хороший CTF-игрок, байты, которые я мог бы распознать. И я, по сути, перепрошивал NAND-чип на плате. И я сказал: «Ладно, давай ударим по этой трубе молотком».
Мне нужно поговорить о кодах фатальных ошибок, потому что я знал, что ожидал потенциально увидеть от системы, если мои глитчи сработают. В загрузочном ПЗУ они подключили режимы аварийного завершения ARM к выводу кода фатальной ошибки, если происходит какая-то проблема с сегментацией памяти или сбой. В частности, abort prefetch — это если PC пытается прыгнуть куда-то, где не существует, или abort data — если вы пытались читать или писать данные или адрес, к которому у вас не было доступа. Они пытаются упаковать IFAR и IFSR, то есть регистр состояния сбоя и регистр адреса сбоя, которые являются ARM-регистрами, в одно двойное слово, потому что пост-коды — это только двойное слово, поэтому они выдадут это на шину как диагностику, может быть, консоль вернётся на фабрику, или они пытаются понять, почему она сломана для ремонта. Это может дать некоторую подсказку, но это мы, например, пример 32-битного кода сбоя, который потенциально может появиться, и как биты разбиваются на что-то. Идея в том, что если мы вызовем сбой сегментации, если мы заглитчуем ядро и вызовем какой-то сбой сегментации, я ожидаю увидеть фатальное двойное слово, выходящее по шине I2C. И оно может выглядеть примерно так.
Итак, во время глитчевания той области, которую я вам показывал, трубы, той красной области, где, как я ожидаю, происходят PCI-передачи, я получаю около 100 уникальных фатальных кодов, прочёсывая эту область своим глитчем, пробуя разные смещения и длительности примерно за 100 000 запусков. Но то, что я ищу в уме, я смотрю на этот верхний байт, потому что этот верхний байт на самом деле должен содержать верхние семь битов адреса, по которому произошёл сбой. Итак, если мы прыгнули куда-то, если мы попытались прочитать недопустимый адрес или записать в недопустимый адрес, я ищу свой паттерн. И это не лучшая визуализация. У меня была куча данных, но основная идея: у меня были сотни этих сбоев, и я отфильтровал их до тех, которые содержали некоторые из моих паттерновых байтов. В частности, я смотрел на pre-fetch в этом примере, но я мог видеть, что с некоторой регулярностью мои разные байты выскакивали. И опять же, эти пакеты по 64 байта — вот о чём я думаю. Когда вы декодируете один из этих пост-кодов, вы можете видеть, что это декодируется как «PC прыгнул на 58 58 что-то». Мы не видим остальную часть адреса, потому что они сжали его в этот маленький пост-код, но мы знаем, что это был сбой прав доступа и конкретно предвыборка инструкции (prefetch). PC пытался уйти куда-то.
После ещё большего анализа можно снова разбить: маленькие контуры — это, по сути, 6, вы можете представить 64-байтовые пакеты, которые будут переданы через MMIO. Но если я менял только эти синие маленькие прямоугольники и глитчевал, то я видел, что я, по сути, получал контроль над PC. И, судя по тому, что я понимаю, глядя на код и размышляя о нём долгое время, мы пропускаем инструкцию pop в самом конце процедуры memcpy или что-то в этом роде. Декодирование инструкции идёт неправильно. Что-то происходит, и этот pop не выполняется. Итак, регистры, когда memcopy пытается вернуться к родителю, никогда не восстанавливаются. И опять же, они сильно загрязнены данными под контролем атакующего, потому что memcopy всегда супер оптимизирована, пытается использовать все регистры, которые может, для копирования данных. Итак, вот состояние, когда происходит фатальный prefetch. Этот пропущенный pop оставил все эти красные регистры загрязнёнными данными, которые я полностью контролирую, и мы просто прыгаем на 58 58 58 58. Восстановление регистров не удалось, и мы можем прыгнуть куда угодно в загрузочном ПЗУ.
Что удивительно, потребовалась всего около недели от глитчевого включения пост-кодов до получения произвольного контроля над счётчиком команд. И глитч привязан к сигналу DAT0 между двумя рандомизированными задержками. Мы обходим рандомизированные задержки в этом отношении, но у нас всё ещё есть проблема: MPU включён. Мы поговорим об этом через пару минут, но у вас есть контроль над счётчиком команд. Нет памяти RX. Как они обычно переходят к следующей стадии? Может быть, мы можем прыгнуть туда. Я думаю, они бы… может быть, мы можем прыгнуть туда, где они отключают MPU, а затем передать управление следующей стадии, но нас убивает контрольно-пропускной пункт безопасности. Контрольно-пропускные пункты безопасности, их около 13, разбросаны по всему загрузочному ПЗУ. Они выдают пост-код прогресса. Они также поддерживают этот вычисляемый хеш, что действительно интересно: если любой контрольный пункт выполняется не по порядку, система сбросится. Также во время этих контрольных пунктов они проверяют ошибки ECC. Они проверяют все эти MMIO-регистры, проверяют, есть ли в их областях SRAM, eFuse, или в ПЗУ какие-либо ошибки ECC, произошедшие во время выполнения, и если да, то сбросятся. Каждый контрольный пункт также заканчивается рандомизированной задержкой, и я думаю, что основная цель — попытаться защититься от больших логических пропусков и прочего.
Но есть ещё одна вещь, которая нас убивает, это user jail’ы. Microsoft реализовала по сути эти непривилегированные user jail’ы для изоляции некоторой действительно рискованной логики загрузочного ПЗУ. Они используют супервизорный режим ARM и MPU, чтобы создать эти маленькие user jail’ы. У каждого из этих jail’ов есть отдельная страница кода, предназначенная только для логики, которая должна выполняться в рамках этого конкретного user jail’а. И они пытаются отгородить всю остальную память, потому что они пытаются изолировать вас, минимизировать количество гаджетов, которые вы потенциально можете использовать, куда вы можете прыгнуть и так далее. И мы застряли в одном из них. Есть четыре разных user jail’а, используемых 14 раз в разных местах. И мы застряли в jail’е с правами, способном копировать данные из флэш-памяти в SRAM. И это ещё одна визуализация выполнения SP0. Выполнения загрузочного ПЗУ. Мы смотрим на несколько разных вещей здесь. Все зелёные биты, которые вы можете видеть, знаю, здесь трудно разглядеть, но мы визуализируем инструкции, выполняемые с течением времени, по их адресам. Все зелёные биты — это выполнение в режиме супервизора (supervisor mode). А все эти красные полосы и красные линии — это выполнение в пользовательском режиме (user mode), а оранжевое — это задержки. Это было очень раздражающе. Я мог выполнять ROP в одном из этих user jail’ов. Я начал играть с ROP немного, просто чтобы продемонстрировать некоторый контроль над системой, и я написал небольшую цепочку. Мне удалось найти достаточно гаджетов в моём ограниченном jail’е, чтобы создать произвольный ROP, и мне удалось вывести свой собственный произвольный пост-код. Я получил 0x41414141, выходящий из шины I2C.
Мы установили наш первый глитч. Этот глитч даёт нам произвольный контроль над счётчиком команд. Мы даже можем превратить это в произвольный ROP. Мы привязываем тайминг глитча к тому самому сигналу DAT0, который в некоторой степени находится вне рандомизированных задержек, но мы ограничены этим user jail’ом, у нас нет полного доступа к процессору безопасности платформы или его памяти и его MMIO-регистрам.
Следующий этап — нам нужно атаковать MPU. Если мы вернёмся к этой диаграмме, мы смотрим на то место, когда мы пытались включить пост-коды глитчем, как раз перед тем, как мы включили пост-коды глитчем, они инициализируют MPU. Это происходит очень рано в загрузке. MPU — это блок защиты памяти. И это то, что они используют для изоляции пользовательского режима, режима супервизора и этих jail’ов. Режим супервизора — это то, что управляет и программирует MPU на лету. Это что-то вроде самодельной TrustZone, потому что это ARMv7, это не ARMv8 и не то время, когда у них появились расширения EL и всё такое.
Я подумал, если мы сможем пропустить включение MPU, jail’ы рухнут, и мы сможем вмешаться в память супервизора. Итак, глядя на то, как работает инициализация MPU, на этой платформе разрешено 12 регионов MPU. И они проходят через этот цикл, настраивая 12 регионов с разными jail’ами, параметрами и областями. И в самом конце они собираются включить MPU. Если мы вернёмся к трассировке питания, мы знаем, что у нас есть жёлтая линия, где должна происходить инициализация GPIO, или мы можем видеть, где происходит GPIO, и мы знаем, что MPU, согласно загрузочному ПЗУ, должен инициализироваться как раз перед этим сигналом. Нам нужно найти способ привязать глитч MPU. Ближайшие сигналы, которые у нас есть, — это инициализация GPIO. Это самый ранний цифровой сигнал, который у нас есть. Но он происходит после логики инициализации MPU. Это полезно, но не самое лучшее. И есть сигнал Power OK, который мы до сих пор использовали, чтобы примерно понять, когда процессор безопасности, когда APU должен загружаться. Но там много дрожания (jitter), которое может варьироваться почти на миллисекунду, прежде чем мы увидим инициализацию GPIO. Оно может сильно варьироваться. Так что это не так полезно. И у нас есть трассировка питания на линии ядра северного моста. Но аналоговые сигналы очень раздражающи для создания триггеров, особенно если я хочу, чтобы другие люди потенциально могли повторить мою работу.
Нам нужно найти лучший цифровой сигнал до инициализации GPIO. Я вернулся к списку линий питания SOC. Я искал много вещей, но в итоге я посмотрел на эти линии питания, которые используются для считывания и пережигания eFuse внутри APU. И я заметил, что на нижней стороне платы была идеальная маленькая дорожка, которую я мог перерезать и вставить шунтирующий резистор. Так что я мог построить побочный канал, чтобы начать отслеживать чтения eFuse. Что интересно, мы построили маленький аналоговый побочный канал. Мы построили маленький зашунтированный побочный канал, чтобы видеть потребление энергии, которое происходит, когда они читают eFuse. Вы можете видеть, что глубина этих импульсов на самом деле зависит от того, сколько битов пережжено в линии eFuse. И я начинаю видеть новые вещи во время загрузки. Мы можем видеть, где они читают линии eFuse, содержащие серийный номер SOC. Мы даже можем видеть, когда они читают eFuse всего криптографического ключевого материала. Что действительно забавно, знаю, на экране это трудно разглядеть, но мы буквально визуализируем вес Хэмминга. Мы можем видеть, сколько битов пережжено в этих отдельных линиях, содержащих ключи и прочее. Это был такой забавный, красивый момент этого проекта.
Но я модернизировал свою установку от простого аналогового побочного канала до цифрового. Я начал пытаться преобразовать эти маленькие провалы, эти маленькие аналоговые провалы, в эти красивые сильные цифровые импульсы 3.3 вольта, которые я мог использовать для анализа. Вот я пытаюсь это настроить, потому что это очень тонкая настройка — эти аналоговые провалы всего около 50 милливольт. Это почти ничего. Это просто крошечные маленькие аналоговые импульсы. Но в конце концов я настраиваюсь. Вы можете игнорировать грязный звон. Но мы сделали так: каждый раз, когда мы видим маленький провал на линии напряжения eFuse, мы теперь получаем эти красивые большие сильные импульсы. И я могу смотреть на это на своём Tinsi. Я могу смотреть на это на логическом анализаторе. Это легче увидеть и удержать на осциллографе.
Теперь мы можем начать видеть чтения eFuse во время SP0 и SP1, а также, я полагаю, во время работы системы. Но теперь мы можем видеть разные вещи. Когда они считывают криптографические ключи, мы можем видеть, когда они делают проверки отзыва для загрузчиков более поздних стадий. И я такой: «Вау, посмотрите на всю эту интроспекцию, которую мы построили». Мы прошли путь от ничего до фактического начала сочетания нашего понимания кода загрузочного ПЗУ в IDA с тем, как это выглядит на аппаратном уровне.
Если мы начнём приближать чтения eFuse, мы можем увидеть, вот как эта область выглядит в развёрнутом виде. И если мы увеличим немного дальше, мы приближаемся к области вектора сброса, где мы в основном и смотрели. Вы можете видеть, где происходит инициализация GPIO справа. А слева, в верхнем левом углу, вы можете видеть три маленьких розовых импульса eFuse. Если мы ещё больше сузим наш обзор, есть три чтения eFuse перед загрузкой, что довольно интересно. Потому что даже если у вас есть ПЗУ, у вас нет точного понимания, что именно здесь читается, но мы можем сделать некоторые предположения. Вероятно, они читают первые три линии eFuse, потому что мы не видим их считывания на протяжении всего загрузочного ПЗУ. Но первая линия eFuse содержит состояние блокировки (lockdown state). А затем вторая и третья линии eFuse содержат специфические для чипа права (entitlements). Можно пережечь специфические для чипа функции, например, включить пост-коды или включить JTAG в самом чипе, а не в каких-то более поздних стадиях.
Но, думаю, более важный вывод здесь в том, что мы нашли важный новый ориентир, который мы можем использовать для синхронизации наших глитчей вокруг вектора сброса. Это намного более стабильный тайминг, чем смотреть на сигнал Power OK, потому что, опять же, захват PLL или что-то ещё вызывает много дрожания. Итак, у нас есть инициализация GPIO. У нас есть трассировка питания. Теперь в верхнем левом углу вы можете видеть наши чтения eFuse перед загрузкой. Этот розовый — это наш построенный побочный канал eFuse. Если измерить промежуток между чтениями eFuse перед загрузкой и инициализацией GPIO, это всего около 268 микросекунд и всего 175 наносекунд дрожания. Не идеально, но намного лучше, чем миллисекунда. Миллисекунда — это неработоспособно и, судя по моим измерениям, сильно варьируется от платы к плате.
Мы знаем, что инициализация MPU должна произойти как раз перед инициализацией GPIO. Примерно в этой области, и теперь у нас есть этот временной ориентир, от которого мы можем отмерять, чтобы точно определить время глитча. Когда я всё это пропустил через свою установку и запустил кампании глитчевания, вот что я начал видеть. Все эти разные цвета — это разные типы сбоев, происходящих в разных точках загрузки, потому что мы, по сути, повреждаем разные итерации того, где они настраивают разные регионы MPU. Может быть, они настраивают стек супервизора в какой-то момент, или они могут настраивать регион GPIO, так что мы падаем на полпути через загрузочное ПЗУ, потому что регион GPIO больше не читается или что-то ещё. Все эти разные цвета как бы иллюстрируют это. Но затем есть этот действительно интересный карман сбоев вдоль нижней части здесь, где инициализация GPIO происходит рано. Верхняя линия, эта нисходящая линия, которую вы видите, — это я как бы прочёсываю смещение глитча всё ближе и ближе к инициализации GPIO. Чем дальше мы продвигаемся вправо, тем раньше мы ожидаем увидеть GPIO. Мы приближаемся к нему. Но когда мы внезапно падаем вниз, мы пропускаем какую-то логику. Инициализация GPIO каким-то образом произошла намного раньше, чем мы ожидали. Это указывает на то, что мы вырываемся из цикла MPU рано. Ясно, что мы вырываемся из этого цикла. Но вопрос: включаем ли мы всё ещё MPU? И мне потребовалось очень много времени, чтобы это проверить, потому что загрузочное ПЗУ вело себя намного страннее после этих глитчей выхода из цикла. Оно падало немного по-разному, почти молчаливо в некоторой степени, или казалось, что оно зависало. Я подумал про себя: если MPU будет включён, скажем, с одним или двумя включёнными регионами, если бы мы выпали из глитча в течение первой или двух итераций цикла, мы бы никогда не продвинулись так глубоко в загрузочное ПЗУ, если бы MPU был фактически включён, он был бы ужасно неправильно настроен. Это было очень странно, потому что, да, тестирование моих глитчей по отдельности работало нормально. Если я хотел попробовать пропустить MPU или этот выход из цикла, мы могли подтвердить это по ранней инициализации GPIO, и если я хотел протестировать мой угон PC, мы получали произвольный ROP, но если мы пытались объединить оба этих глитча в один запуск, угон PC просто не работал. Мне потребовалось много времени, чтобы оптимизировать, изучить и подтвердить эффекты этого глитча MPU. В конечном итоге я смог подтвердить, что MPU, когда мы вырываемся из этого цикла, мы также пропускаем ту ветвь, и MPU никогда не включается.
Объяснение того, почему это заняло так много времени, заключается в том, что с выключенным MPU операции проверки памяти, поскольку их больше нет, мы экономим некоторое время выполнения. Нет больше цикла или двух в конвейере выполнения. Также часть странности, которую я испытывал, связана с тем, что объединение записей, обычная функция в процессорах, с включённым MPU они обычно помечают некоторые области MMIO как память устройств так, чтобы не было объединения записей, и записи проходили немедленно. Но это могло вызвать неправильную настройку, если MPU выключен и объединение записей не сбрасывает данные в MMIO немедленно. Но главная проблема опять же в том, что когда мы выпали из этого цикла и пропустили включение MPU, параметры моего глитча для угона PC, того глитча заголовка SP1, изменились. Они изменились, и мне потребовалось много времени, чтобы это преодолеть, потому что нам нужно было заново прочесать в поисках новых параметров для второго глитча, глитча угона. Это было изнурительно. По сути, мы объединяем два глитча. Скажем, один шанс из 100 для пропуска MPU и один шанс из 100 для попадания в угон PC. Итак, получается около 10 000 загрузок на каждый тестируемый параметр глитча. Мне пришлось сделать миллионы загрузок, чтобы заново открыть параметры угона PC. Я делал так много загрузок, что буквально сжигал чипы eMMC, потому что SMC в южном мосту пытается поспеть и понять, что, чёрт возьми, я делаю с системой. Он пытается записывать журналы ошибок. Помните отзыв Tesla пару лет назад, когда они сжигали свои чипы NAND в eMMC в Tesla из-за постоянной записи журналов ошибок. Мне пришлось во время исследования заменить эти eMMC на промышленные, которые выдерживают гораздо больше записей, чтобы помочь с исследованием.
Но наконец-то мы дошли до того, что я называю «блаженство» (bliss). У меня есть видео. Это моя лаборатория, и мы транслируем первую в истории атаку. Что вы увидите: на экране осциллографа что-то появится. Я запустил глитч с правой стороны. Эта двойная глитч-установка, жуткая лаборатория, и глитч сработал, двойной глитч сработал, и мы дампили все eFuse. У нас было полное выполнение кода в загрузочном ПЗУ. Вот я просто прокручиваю загрузочное ПЗУ или перемычки. Вы увидите, что я начинаю дамп загрузочного ПЗУ в верхней части здесь. Небольшое сообщение для меня. Вы можете видеть строку копирайта Microsoft. Они сказали: «Не взламывайте незаконно, обходите, декомпилируйте или глитчуйте». И всё, что я прокручиваю, это то, как я управляю криптодвижком для расшифровки всех более поздних стадий. Мы можем расшифровать 1SP, 2SP, прошивку потокового криптопроцессора. У нас есть доступ ко всему. Мы можем пропатчить всё. Мы можем расшифровать всё. Мы можем загрузить что угодно, начиная с загрузочного ПЗУ. Это просто картинка на случай, если видео по какой-то причине не сработало. Это мой кликер.
Итак, квинтэссенция взлома «bliss» в том, что у нас есть два глитча, по крайней мере, в оригинальной версии. Два глитча. Один, чтобы пропустить включение MPU. Это позволит пользовательскому режиму вмешиваться в память супервизора. Это также даст нам свободно читаемую, записываемую и исполняемую память, что означает, что нам больше не нужно играться с ROP, как я делал с моим одиночным глитчем ранее. И затем у нас есть второй глитч, чтобы угнать счётчик команд в пользовательском режиме. Когда мы угоняем выполнение в пользовательском режиме, мы можем просто прыгнуть в заголовок SP1, который был частично считан в безопасную RAM. Это наш шелл-код. Мы можем просто выполнить его, потому что MPU выключен. Но, что более важно, мы можем повредить сохранённые регистры супервизора так, что мы сможем просто вернуться в режим супервизора и угнать его, что позволит нам делать всё что угодно. Нет более высоких привилегий во всей системе.
Это просто изображение с осциллографа, изображающее момент успеха. Возможно, это трудно разглядеть, но вы можете видеть этот маленький импульс, который я делаю на линии питания ядра северного моста. А это я просто переключаю несколько GPIO. Загрузочное ПЗУ никогда не должно так переключать GPIO. Так что это я демонстрирую контроль над пинами GPIO. Это просто диаграмма более высокого уровня, снова показывающая, где происходит чтение, примерно где я вставляю глитч этой молнией. И затем я демонстрирую контроль и создаю свой собственный UART на некоторых из этих пинов GPIO. Я перепрофилировал те пины пост-кодов, которые я подключил, в RXTX и тактовый сигнал, чтобы можно было отправлять полезные нагрузки и тестировать вещи.
Что так сокрушительно в этой атаке, так это то, что мы захватываем управление так рано, до того, как Microsoft проведёт свои необратимые преобразования ключей. Их архитектура ключей впечатляет во многих отношениях, и вы можете посмотреть выступление Тони Чена, где он более подробно рассказывает об их иерархии ключей и о том, как она приносит им пользу во многих разных аспектах. Но некоторые из последствий взлома «bliss» в том, что мы получаем выполнение кода в режиме супервизора в контексте загрузочного ПЗУ до того, как произойдут какие-либо значимые преобразования ключей и до того, как могут произойти какие-либо проверки отзыва кода или загрузчика. Этот уровень компрометации позволяет нам расшифровывать, загружать, патчить и выполнять неподписанный код на каждом уровне. В PSP, потоковом криптопроцессоре, гипервизоре, основной ОС, игровой ОС, системной ОС, каждый нижележащий уровень полностью скомпрометирован на данный момент. У нас есть оракульный доступ к криптопроцессору, позволяющий нам расшифровать все игры, прошивки, контент и обновления, прошлые, настоящие и будущие, что, на мой взгляд, действительно важно для сохранения (preservation). До сих пор практически не было возможности сохранить эту консоль, её историю и игры. Особенно если эти игры начнут уходить офлайн и сервера падут, если вы хотите быть частью этого, теперь есть некоторая возможность и некоторое окно, чтобы это сделать. Есть также потенциал для лучшей ремонтопригодности консолей. Теперь мы можем потенциально отвязывать NAND, а также отвязывать оптические приводы, которые часто выходят из строя спустя 12 лет.
Это аппаратная атака на загрузочное ПЗУ, основанное на кремнии. Следовательно, она также не подлежит исправлению патчем. Это наша загрузочная цепочка, и мы скомпрометировали загрузочное ПЗУ, поэтому всё, что после, — честная игра.
Влияние на продукт: это затрагивает оригинальную Xbox One 2013 года. Я подумал: если никто не взломал более поздние консоли, я не буду на них замахиваться. Я хочу учиться на прошлом и строить постепенно. Но есть оговорка: в выступлении Тони у него была диаграмма, описывающая архитектуру безопасности Xbox One внутри SOC. И есть кое-что, что Microsoft пыталась внедрить к запуску, но не смогли сделать достаточно стабильным. Я знал, что это было отключено перемычками для запуска, потому что было нестабильно. Они не смогли это донастроить. Они пытались встроить мониторы побочных каналов для отслеживания разных линий напряжения внутри чипа, чтобы обнаружить потенциальное влияние на ядро северного моста, линии памяти, тактовую частоту. В SOC первого года выпуска эти анти-глитч мониторы были отключены перемычками, и к концу 2014 года, с ревизией первого года, они смогли их включить, насколько я понимаю, но я твердо верю, что эту работу можно перенести на все оригинальные консоли, потому что, глядя на логику, где они рассуждают о включении монитора, я думаю, можно заглитчевать и это, даже если мониторы сами по себе эффективны в обнаружении этих глитчей.
Xbox One S и One X, я немного на них смотрел. Не знаю, буду ли я продолжать их изучать, но загрузка продолжала развиваться. Она была усилена ещё больше. Теперь там два ядра: процессор сброса и процессор безопасности. Интрига нарастает. Но я думаю, что описанные мной техники будут иметь отношение к атаке на эти системы. Я думаю, вы сможете потенциально атаковать процессор безопасности, используя кое-что из описанного мной, предполагая, что вас не убьют подобные глитч-мониторы. Xbox Series S и Series X. Я вообще на них не смотрел. Ничего не могу сказать о них.
Но возможна ли мод-плата? Это все будут спрашивать. Я видел, кто-то шутил в Твиттере: «Если вот это нужно делать, глядя на все эти провода, чтобы взломать Xbox One, я думаю, Microsoft победила». Но реальность такова, что почти всё это было исключительно для построения интроспекции. Это была моя отладочная плата, моя исследовательская плата. Вам, возможно, понадобится только три провода для создания побочного канала eFuse, подключения к пину GPIO и линии DAT0. Это ориентиры, необходимые для синхронизации этих глитчей. Для линии питания ядра северного моста я показывал вам всю мою установку с инжекцией и побочным каналом по питанию — это было совершенно необязательно. Это, опять же, для моей собственной отладки и интроспекции для той демонстрации. Я глитчевал на стандартном напряжении. Я удалил лишь несколько конденсаторов под платой, чтобы разместить MOSFET. Но это, возможно, даже не обязательно.
Люди спрашивают, и я уверен, многие будут смотреть это выступление позже на YouTube и говорить: «О, славные дни Xbox возвращаются. Мы снова будем модифицировать игры и всё такое». Я думаю, уже слишком поздно, на 12 лет. Я думаю, золотой век, извините, закончился, ребята. Простите. Но мне было бы любопытно, сможет ли кто-то на самом деле пройти и повторить мою работу и воплотить что-то из этого. Это буду не я. Я не играл в игры годами, и я вернулся на сцену не для того, чтобы взломать Xbox One и пиратить несколько игр. Я сделал это только потому, что никто другой не мог.
Вот такой вывод. Опять же, очень похожие выводы были в моём прошлогоднем выступлении. Нужно быть амбициозным. Знаете, незнание — сила. Проглотите дракона и беритесь за действительно сложные проблемы.
Особая благодарность моему хорошему другу Grim, а также 404, Puloid и Lockbox. Джордан, вы, надеюсь, видели его выступление вчера, потому что они из тех людей, которые вдохновили меня вернуться и прочитать этот доклад. Есть дополнительные слайды, но мы, наверное, остановимся здесь, чтобы не выходить за рамки времени. Итак, ДА.
[Вопросы из зала]
Ведущий: Эй, Маркус, отличный доклад, чувак. Я хотел спросить о тех классных графиках, которые помогли описать все эти вещи. Ты сделал кучу самодельных инструментов, чтобы собрать это, или были готовые инструменты?
Маркус: О, боже. Хороший вопрос. Если бы у меня был ещё один час, я бы рассказал о всём том ИИ, которым я занимался последние 2-3 года. И на самом деле ИИ помог мне создать эмулятор для загрузочного ПЗУ, чтобы помочь мне в его изучении. Он помог эмулировать периферийный ввод-вывод, MMIO, все эти вещи. Эти визуализации инструкций, измерения и мои попытки симулировать сбои — всё это из эмулятора, который я построил с помощью ИИ. И он также сгенерировал эти красивые визуализации для вас, ребята, и сообщества, чтобы смотреть на них, анализировать и веселиться. Так что да.
Вопрос из зала: Привет, Маркус. Очень хороший доклад. Мой вопрос: сколько консолей ты сжёг?
Маркус: Ага. Да. Хороший вопрос. Я хотел вставить картинку. Извини, Питер. Я хотел вставить картинку моего шкафа, у меня там полный шкаф. Может быть, в финальной версии слайдов я добавлю картинку. Я убил, честно говоря, только около четырёх или пяти плат. И я понял, что убивал платы не глитчами, а убивал eMMC. Поначалу я этого не осознавал, пока не начал думать: «Мне нужно разобраться, потому что я не могу проводить эти долгие глитч-кампании неделями, а плата просто перестаёт работать». Думаю, около пяти плат. У меня сейчас около пяти плат в коробке с запчастями. Да.
Вопрос из зала: Хорошо, ещё один вопрос: сколько попыток, в каком масштабе ты реально пробовал? Сколько раз, если можно назвать цифру?
Маркус: Ты имеешь в виду, в плане глитч-кампаний, как долго они длились? Окей. Это зависит. Иногда при прочёсывании я тестировал, может быть, 100 000 параметров. Но это могло быть на протяжении миллиона загрузок, потому что я попадаю в эти глитчи только с определённой частотой, и иногда, если я не попадаю в первый глитч, я сбрасываюсь. Мне трудно это подсчитать. Но да, у меня были глитч-кампании, которые длились день или два. Но много раз я что-то настраивал и пытался понять.
Вопрос из зала: То есть эксплойт срабатывает один раз на миллион попыток?
Маркус: Ну, дело в том, что глитч, который я демонстрировал, сработал за минуту, и это было реально, и я особо не оптимизировал свою установку. Это было для исследования, для себя. Я думаю, если всё правильно отшлифовать и доработать, можно заглитчевать консоль за секунду. Я думаю, что в целом за несколько секунд можно попасть в оба глитча. Я могу попадать в них от минуты до 30 минут. Это может варьироваться. Иначе я бы сделал живую демонстрацию. У меня сейчас идёт стрим из моей квартиры. Я бы включил его, если бы думал, что он может сработать в течение минуты или двух. Но да.
Вопросы и ответы
Microsoft применила комплексный подход: отключила все отладочные интерфейсы (UART, JTAG), встроила 37 рандомизированных задержек в код загрузочного ПЗУ, чтобы сбить тайминги глитчей, использовала ECC-память для защиты инструкций и изолировала критически важный код в "user jail'ах" с помощью MPU. Фактически, они подготовились ко всем известным программным атакам.
Это "god mode". Поскольку загрузочное ПЗУ — корень доверия, его компрометация позволяет расшифровать любые ключи и прошивки (PSP, гипервизор, ОС), выполнять неподписанный код на любом уровне и получать доступ ко всем данным. Главное преимущество — неустранимость: Microsoft не может выпустить патч для исправления кода, "зашитого" в кремний.
Да, и это одно из важнейших практических применений. Сейчас можно "отвязывать" вышедшие из строя оптические приводы и NAND-чипы, которые привязаны к конкретной материнской плате. Раньше такая поломка превращала консоль в "кирпич", теперь её можно починить, что критически важно для сохранения игровой истории.
Маркус — исследователь безопасности, который в прошлом уже выступал с докладом о взломе оригинальной Xbox. К задаче он вернулся не ради пиратства, а ради вызова: "потому что никто другой не смог". Работа была начата ещё в 2024, но прервана. Лишь поддержка коллег вдохновила его завершить исследование и представить миру этот прорыв.
This response is AI-generated, for reference only.
Евгений Делиев

Он там, где биты данных обретают ритм ката. Где железо и софт проходят проверку на стойкость, а каждый алгоритм должен быть отточен, как боевая техника. Его контент — это не просто обзоры гаджетов. Это поиск гармонии между несгибаемой дисциплиной боевых искусств и безграничной свободой цифрового мира. Он помогает выработать точность не только в выборе процессора, но и в жизненных решениях. У него нет абстрактных советов. Только конкретика, выверенная до миллиметра и такта.





