Продолжаем разговор о безопасности UEFI.
На этот раз речь пойдет об опубликованной в конце 2014 года серьезной уязвимости в реализации ACPI S3 (Sleep Mode), ее эксплуатации и последствиях. Основная «фишка» этой уязвимости в том, что она вскрыла целый класс проблем безопасности UEFI, вообще не считавшихся до этого проблемами, и потому и заслуживает отдельной статьи.
Тем, кто не читал предыдущие статьи цикла — раз и два, предлагаю прочесть сначала их, остальных жду под катом.

Часть третья. ACPI S3


Еще немножечко ликбеза
В отличие от SMM, о котором обычный пользователь чаще всего даже не подозревает, про ACPI S3, т.е. режим сна, знает любой обладатель ноутбука или ПК, выпущенного в последние 10 лет.
Стандарт ACPI, об изменениях в последней версии которого я недавно писал, определяет набор т.н. состояний сна, в одном из которых может находиться система, следующим образом:
  • S0 — Working, т.е. обычная работа, все устройства включены. Внутри этого состояния производители систем имеют право определять кучу других состояний: P-states, C-states, T-states и т.п., расскажу о них как-нибудь в другой раз.
  • S1 — Sleeping with Processor Context Maintained, оно же Power on Suspend, т.е. все ядра процессора выполнили команду HLT и стоят, но все кэши и RAM валидны и обновляются, питание со всех все линий S0-only снято. Возврат из этого состояния занимает приблизительно 10 мс, из которых ~90% — ожидание установившихся режимов после подачи питания на линии S0-only. Никакие регистры ни у CPU, ни у чипсета, ни у устройств в этом состоянии не сбрасываются, так что нас в этой статье оно интересовать не будет.
  • S2/S3 — Suspend to RAM, т.е. содержимое памяти остается валидным и обновляется, а процессор и часть чипсета отключаются полностью с потерей контекста и содержимого практически всех регистров. Разница между S2 и S3 минимальная, и чаще всего S2 вообще не выделяют в отдельное состояние. После пробуждения из S3 процессор начинает выполнять код с ResetVector'а, т.е. чтобы правильно «проснуться», ему нужно восстановить весь контекст для себя и чипсета. Вот на этом этапе разработчиков прошивки и подстерегает несколько подводных граблей, о которых мы и поговорим в этой статье.
  • S4 — Suspend to Disk, т.е. содержимое памяти сбрасывается на диск и система отключает все устройства и подачу питания. После включения система стартует как обычно, и с точки зрения UEFI между S4 и S5 разницы практически нет (а если отключить FastBoot, то совсем нет).
  • S5 — Soft-Off, т.е. система отключена, но дежурное питание присутствует. Из S4/S5 система может быть выведена по сигналу RTC, либо по Wake-сигналу от устройства, либо по нажатию кнопки питания.

Как реализован S3 в UEFI
Чтобы восстановить контекст при «просыпании», сначала его нужно где-то сохранить. При этом желательно не слишком привязываться к конкретным особенностям архитектуры процессора и чипсета, а таже сделать хранение и восстановление контекста максимально прозрачным, чтобы не умереть потом в отладке. Т.к. работоспособность S3 — очень важная характеристика практически любого современного ПК, за исключением серверов с годами аптайма, то технология сохранения и восстановления контекста была разработана инженерами Intel очень рано, в 2004 году, и получила название EFI S3 BootScript. С тех пор спецификация многократно дорабатывалась, последняя версия теперь находится в томе 6 спецификации UEFI PI.
Суть ее такова: после исполнения фазы PEI, в которой происходит инициализация базовых устройств, т.е. процессора, кэшей и оперативной памяти, система определяет текущий режим загрузки.
1. Если этот режим отличается от S3 Resume, загрузка продолжается как обычно, PEI заканчивается запуском диспетчера DXE, который создает новый пустой S3 BootScript и запускает все доступные DXE-драйверы. Каждый такой драйвер выполняет финальную инициализацию того устройства, за которое он отвечает, и затем добавляет в S3 BootScript команды, которые необходимо выполнить, чтобы повторить инициализацию устройства при возврате из S3. Команды могут быть примерно такими (список взят из спецификации PI 1.4, но в конкретных реализациях могут встречаются и нестандартные):
  • IO_WRITE — записать указанное значение в указанный CPU IO-порт
  • IO_READ_WRITE — изменить значение в указанном CPU IO-порту согласно указанной маске
  • IO_POLL — выполнять чтение из указанного IO-порта, пока не будет выполнено указанное условие, но не дольше указанного времени ожидания
  • MEM_WRITE — записать указанное значение по указанному физическому адресу
  • MEM_READ_WRITE — изменить значение по указанному физическому адресу согласно указанной маске
  • MEM_POLL — выполнять чтение по указанному адресу, пока не будет выполнено указанное условие, но не дольше указанного времени ожидания
  • PCI_CONFIG_WRITE — записать указанное значение по указанному адресу в конфигурационном пространстве указанного PCI-устройства
  • PCI_CONFIG_READ_WRITE — изменить значение по указанному адресу в конфигурационном пространстве указанного PCI-устройства согласно указанной маске
  • PCI_CONFIG_POLL — выполнять чтение по указанному адресу в конфигурационном пространстве указанного PCI-устройства, пока не будет выполнено указанное условие, но не дольше указанного времени ожидания
  • SMBUS_EXECUTE — передать указанную команду указанному устройству на шине SMBus
  • STALL — подождать указанное число микросекунд
  • DISPATCH — выполнить код по указанному адресу
Вышеуказанных команд вполне достаточно, чтобы повторно инициализировать любое устройство, особенно с учетом последней команды, просто передающей управление PEI-драйверу, который и выполняет всю инициализацию, но нужно это только для особо сложных случаев, когда остальными командами обойтись не получилось.
После окончания фазы DXE диспетчер сохраняет получившийся S3 BootScript в памяти типа AcpiNVS, в которой находятся ACPI-таблицы и другие данные, необходимые ОС для правильной работы ACPI в ней.
2. Если же при загрузке выяснилось, что система находится в S3 Resume, вместо диспетчера DXE запускается PEI-модуль с красивым именем BootScriptExecutor, который выполняет BootScript, бережно хранящийся в памяти со времен прошлой нормальной загрузки, а затем передает управление на ОС, которая успешно стартует и радует пользователя.
Словами, вроде бы, пояснил, теперь тоже самое — картинкой из спецификации:


Подводные грабли
Это все успешно работало около 10 лет, и практически никто не видел подвоха, пока в конце 2014 года широко известные в узких кругах товарищи Rafal Wojtczuk and Corey Kallenberg не представили атаку, которая оказалась одновременно очевидной и крайне опасной. Оказалось, что область памяти (типа AcpiNVS), которой хранится S3 BootScript, никак не защищена от модификации. Да, ОС воспринимает ее как служебную и не испортит содержимое самостоятельно, а вот атакующий с правами администратора — еще как.
Модификации могут быть весьма различными, но т.к. большая часть защитных механизмов, обеспечивающих защиту как от прошивки произвольно кода в микросхему SPI, так и от несанкционированного доступа в SMM, настраиваются через регистры процессора и чипсета, то для успешного обхода этих механизмов достаточно найти BootScript в памяти (это нетрудно), найти в нем нужный нам регистр (тоже никаких сложностей) и изменить его так, чтобы при следующем S3 Resume защита не смогла включиться. Меняем, засыпаем, просыпаемся — оп, а король-то голый! Чем грозит снятие защиты с микросхемы SPI и с SMM — я уже писал в прошлых частях, повторяться не буду, но ничем хорошим это определенно не закончится.
Интересно, что инженеры Intel предвидели эту атаку и заранее реализовали защиту от нее — т.н. SmmLockBox. Защита очень простая — после того, как составление скрипта закончится, он копируется целиком в SMRAM, при этом оригинальный BootScript не удаляется. При восстановлении из S3 вызывается обработчик SMI, который проверяет, что оригинальный BootScript совпадает с копией в SMRAM, а если нет — либо переписывает измененный BootScript копией, либо перезагружает машину (это безопаснее, но пользователь теряет все данные из RAM). Проблема оказалась в том, что SmmLockBox просто не успели вовремя внедрить, и когда Rafal и Corey тестировали найденную уязвимость, оказалось, что единственная неуязвимая к атаке плата — Intel'овский UEFI Development Kit.
После обнародования атаки IBV начали в спешке внедрять либо оригинальный SmmLockBox, либо свои аналоги, основанные на той же идее, но это внедрение часто буксовало по разным причинам. К примеру, на системах с процессором AMD инициализация SMM проводилась в фазе DXE, и потому вызов обработчика SMI из PEI при S3 Resume заканчивался неудачей и S3 переставал работать вообще.
Тем не менее, на данный момент все вендоры, слышавшие о безопасности хотя бы краем уха, уже решили эту проблему каким-либо способом, и если ваша прошивка новее июня 2015 года, а производитель вашей системы не мудак — скорее всего ваша система прямой атаке на изменение S3 BootScript'а уже не подвержена.

Свинья от производителей платформ
После того, как паника немного улеглась, и BootScript успешно затолкали в SMRAM (понятно, что теперь надо хранить его как зеницу ока, но я об этом уже в прошлой части писал), неожиданно выяснилось, что инженеры Intel и AMD, сами того не зная, подложили обладателям своих платформ порядочную свинью в лице нескольких PEI-модулей, которые а) копировались в память прямо рядом с BootScript'ом, б) вызывались из него командой DISPATCH десятки раз и в) были достаточно большими, чтобы в SMRAM на их копии места не хватало.
Таким образом, выполнение произвольного кода можно было организовать без модификации самого BootScript'а вообще, вместо этого модифицировав точку входа одного из таких модулей. Удалить такие модули без нарушения работы S3 не получалось, но решение нашлось — вместо копирования в память их перенесли на неупакованную часть DXE-тома, и исправили команды DISPATCH так, чтобы код вызывался прямо с микросхемы SPI. Это оказалось немного медленнее, чем из RAM, зато свинью удалось таки выгнать. Я не знаю, сколько сейчас систем, которые можно атаковать этим способом, но подозреваю, что очень много.

Господа забывчивые
Человек не застрахован от ошибок, и разработчики DXE-драйверов — тоже человеки, и иногда могут банально забыть написать добавление какого-нибудь важного регистра в BootScript, и после S3 в этом регистре окажется его оригинальное значение. Чаще всего такая забывчивость приводит только к мелким глюкам после S3, но законы Мерфи говорят нам, что если какой-либо важный регистр может быть забыт — он обязательно будет забыт, что и происходит. Последний громкий пример забывчивости — опубликованная в конце мая этого года уязвимость в прошивках ноутбуков Apple, где инженеры забыли добавить в S3 BootScript запись в PR-регистры, и после S3 защита микросхемы SPI от прошивки снималась самостоятельно. Очень удобно ведь, закрыл-открыл крышку — и можно доставать flashrom и писать свой код в BIOS, Apple вновь радует простой и юзабилити. Если вы думаете, что случай единичный — советую запустить на своем ПК утилиту Chipsec и сравнить отчеты, сделанные до и после S3. Заодно и сюрприз может получиться.

Отключу S3 и трава не расти
Примерно это, только более экспрессивно и немного более матом, я воскликнул, когда столкнулся с проблемой впервые. К сожалению, этот вариант не всегда возможен (хотя S4 на SSD мало отличается по скорости, зато сильно отличается по надежности, никаких танцев со скриптами и экзекуторами не нужно), более того, если вы не отключили S3 намертво путем модификации прошивки, атакующий, способный запустить на вашей системе UEFI Shell, банально включит S3 обратно. В следующей части я постараюсь рассказать, как избежать такой незавидной судьбы, но коротко — включайте и пользуйтесь SecureBoot, он вовсе не зло, если уметь его готовить.

Кризис доверия
Вся эта история с S3 BootScript вскрыла одну интересную проблему, которую после 10 беззаботных лет разработки в UEFI серьезно начали решать только сейчас. Проблема состоит в том, что «безопасная» прошивка не может доверять ничему, к чему имеет или имела доступ ОС. Устройства нужно сбросить и инициализировать самостоятельно, память очистить и ничего из нее не использовать (не дай рандом вызывать оттуда код!), свои же Runtime-сервисы после события ReadyToBoot компонентам прошивки использовать нельзя (их уже хукнул атакующий, иногда по нескольку раз), в общем, сплошное минное поле, чуть оступился — и вот у тебя уже полный BIOS чужого кода, бэкдор на бэкдоре, честным драйверам в SMRAM места нет. Поэтому производители платформ ищут спасения в аппаратных решениях, кто-то внедряет validated boot, кто-то хранит S3 BootScript в Security Coprocessor'е, кто-то разрабатывает свой собственный крипточип, кто-то просто забил и ждет, пока ему решение UEFI Forum сверху спустит.
Вот и Intel добавила в Skylake интересную технологию SGX, которую можно использовать для изоляции отдельных кусков кода и данных от всего остального в системе, такой себе аналог SMM, только всем и даром, чтобы никто не ушел обиженным. Технология выглядит достаточно вкусно, но, во-первых, сложна в программировании, а во-вторых — есть только у Intel и только на Skylake.
Со стороны «безопасной» ОС — такой же точно уровень недоверия к прошивке, и тут может пригодиться технология STM, о которой разговоры велись с 2009 года, но представили ее официально только недавно, и «в бою» она еще не опробована. Когда дойдут руки попробовать обе — постараюсь про это написать.

Заключение


Ну вот, проблемы с S3 BootScript позади, в следующей части поговорим об атаках на NVRAM и SecureBoot, а также о том, почему пароль на BIOS — от честных людей.
По доброй традиции, посоветую знатокам английского языка вот эту статью тов. d_olex на ту же тему. Там серьезность, глубина, код, и картинки, не то что мое словоблудие тут.
Спасибо тебе за внимание, читатель, безопасных тебе прошивок.

Комментарии (20)


  1. xiWera
    19.09.2015 16:27

    «но атакующий с правами администратора»… зачем ему такие сложности? :))


    1. CodeRush
      19.09.2015 16:38

      Ну как сказать… Записать свой код в прошивку, получив возможность переживать переустановку системы и смену всего оборудования, кроме материнской платы. Записать свой код в SMM и прятаться там от любых средств защиты уровня ОС, а самому творить с ними непотребное. Возможностей то масса, я их уже в предыдущих постах описывал.
      В общем, с незакрытыми уязвимостями в прошивке от LPE до греха — один шаг.


      1. icoz
        19.09.2015 20:18
        +2

        Переведу на русский. Вирус, заразивший машину, будет спокойно переживать переустановку, обходить антивирус и т.д.
        А права администратора — есть куча дыр в винде. Хоть раз пропустил — зараза надолго с вами… Никакие сервиспаки не помогут.


        1. CodeRush
          19.09.2015 20:35

          А я ведь в первой части предупреждал, что у меня язык после нескольких лет неиспользования слегка заржавел — вот и подтверждение.


          1. AllexIn
            19.09.2015 23:38

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


        1. egyp7
          21.09.2015 15:55

          Что касается вирусни — думаю стоит понимать, что хотя это и активный вектор для восстановления малвари(восстанавливается без участия пользователя), но все же не самый лучший и универсальный.
          Лучшим аналогом для закрепления на мой взгляд были и остаются файловые инфекторы(в основном для исполняемых файлов). Они хоть и пассивны(необходимо инициализация со стороны пользователя), но справляются с задачей намного лучше вплане персистенции вредоносного кода. Используя продвинутую технику EPO и тактично заражая исполняемые файлы на целевых машинах — можно держаться годами.
          К тому же, это менее трудоемко вплане ресерча и реализации, плюс не забываем про универсальность.


  1. mark_ablov
    19.09.2015 17:10
    +2

    О, cr4sh еще пишет, когда-то перестал следить за его постами, а оказывается много интересного написал ;)


    1. CodeRush
      19.09.2015 17:16
      +1

      Пишет, да, и хорошо пишет — толково, с картинками, с чувством, толком и расстановкой, поэтому и рекомендую. :)


  1. grossws
    19.09.2015 23:07

    С «правами администратора» — это какой уровень доступа подразумевается? С правами администратора/рута в userspace, с правами ядра ОС?


    1. d_olex
      19.09.2015 23:40
      +2

      Рут нужен главным образом для доступа к физической памяти, т.е., в случае с Linux при наличии /dev/mem доступ к ring0 не критичен.


  1. VBKesha
    20.09.2015 01:35
    +1

    Спасибо за статьи, очень интересно.


  1. Alexeyslav
    20.09.2015 11:30

    Уф… как все-таки раньше было просто. А сейчас сколько всего наворотили…
    Вот думаю… у большинства людей БИОС-ы не обновлялись со времён царя гороха, сколько же сейчас троянов в них засело и как они взаимодействуют с внешним миром?


    1. CodeRush
      20.09.2015 11:47
      +2

      Раньше было просто потому, что тему не затрагивали. Где-то был джампер Read-only, но в основном был полный доступ на запись прямо из ОС.
      Я не думаю, что у обычного пользователя уже засела куча троянов, т.к. технология относительно новая и в хакерской среде пока не очень популярная, но если ничего не делать, то трояны там обязательно засядут. Сначала они будут примитивные донельзя, как нашумевший недавно HT rkloader, но потом начнется гонка вооружений и атакующее прошивку ПО быстро вылезет из своей PoC-песочницы. Именно поэтому важно исправить обнаруженные уязвимости сейчас, а там, где нельзя исправить — сообщить об этом.
      Очень многие, в том числе и признанные специалисты по ИБ, сомневаются в опасности атак на UEFI, считая их слишком дорогими и слишком целевыми, чтобы быть сколько-нибудь опасными для обычного пользователя. То же самое в свое время говорили про любые новые классы атак, пока их не вепонизировали и не добавили в Metasploit. А для UEFI, ноги 80% которого растут из открытого кода проекта TianoCore, сделать это будет весьма несложно. Вот тут ребята из LegbaCore рассказывают подробнее.


      1. Alexeyslav
        20.09.2015 14:37

        Перемычка… раньше ПЗУ были с УФ стиранием.
        разве нельзя было сделать обновление прошивки из ОС с цифровой подписью, и прошивку БИОС выполнял бы чипсет, проверяя подпись а система не имела бы прямого доступа непосредственно к микросхеме памяти.
        Подставили ключ подписи — перепрошиваешь прошивкой со старым ключем которая предоставляет новый и делов, а если система уже заражена то через программатор.
        Я вот неоднократно слышал, что подобный механизм применяется для прошивки самого чипсета, там есть область памяти которую можно прошить только подписанной прошивкой.
        Эта тема возникала в связи с обнаружением в китайских платах троянца который заложен в закрытую часть прошивки чипсета и который через собственый гипервизор может делать с системой что угодно, и она этого не заметит, кроме как подсчётом тактов процессора на исполнение отдельных инструкций.
        В таком случае, любой код даже самый первый исполняемый байт прошивки БИОСа уже находится под контролем троянца.


        1. CodeRush
          20.09.2015 21:51

          Есть такая технология, называется verified boot, и работает она практически так, как вы описали, я о ней писал в первой статье этого цикла.
          Если китайцы умудрились подставить свой код в ME — снимаю перед ними шляпу. Да, в таком случае они имеют возможность выполнить любой код еще до ResetVector'а, и никакими защитами прошивки, кроме переписывания региона МЕ на заведомо чистый, от такого не защититься. Я пока не слышал об успешных атаках на последние версии МЕ, но это не значит, что их не было. Исследованием прошивок внутренних контролеров сейчас занимается буквально 2,5 человека (Игорь Скочинский из HexRays сразу на ум приходит, ребята из LegbaCore и Invisible things Lab, и все считай), поэтому идут они медленно и накопать каких-то адски серьезных уязвимостей пока не получилось.


          1. Alexeyslav
            20.09.2015 23:22

            А зачем им что-то подставлять? Они сами эти микросхемы производят и пишут под них прошивки(конфигурируют ПЛИС).
            История обнаружения была очень интересная — человек писал под отладочной платой гипервизор, на американских платах все работало безукоризненно, но когда пришла пора проверять на серийных образцах производимых на китайских фабриках его код давал сбои, после долгого расследования выяснилось что сбои происходят по причине что гипервизор выполнялся в другом гипервизоре… а так бы никто ничего не заметил, если бы китайский гипервизор не был бы глючный. Потом они исправились, и после этого единственный способ обнаружить его присутствие — это измерять длительность выполнения специфических команд процессора.
            Если учесть что сетевой контроллер завязан напрямую на чипсет — у такого троянца весь трафик перед глазами, получив специфический код извне в общем потоке трафика такой спящий троян в одно мгновение способен вывести из строя компьютерные системы вероятного противника.


            1. JerleShannara
              21.09.2015 04:31

              Подогрею вашу паранойю. Во времена зарождения ME на десктопных платах частенько натыкался в коде прошивок биоса (не UEFI, а самого того костыльно-древнего) на странные строчки AMT и кучу оных параметров, хотя производитель про наличие этого самого ME ничего не утверждал, да и ME там о себе никак не заявлял. Одна такая плата кстати при вырезании этого непонятного кода вообще отказалась заводиться. Вот и думай после этого о шпиЁнах цру и моссад-а. Да, было это во времена царствования 9хх серии чипсетов, где это ME ещё можно было пощупать руками.


            1. isden
              21.09.2015 10:27

              Я практически аналогичное слышал, но про партию мат.плат от Интел.


              1. CodeRush
                21.09.2015 10:42
                +1

                Про это однажды была статья в журнале Хакер, вот она. И речь в ней, как раз, об Intel'овских процессорах и китайских материнских платах для них с изменной прошивкой толи МЕ, толи BMC, толи EC — в общем, одного из набортных контролеров.
                Я вполне допуская ненулевую вероятность такой атаки, но стоить она будет весьма недешево, особенно с учетом того, что надо у Intel ключи стащить. Скорее всего, автор статьи зацепил краем глаза какую-то операцию спецслужб США.
                Если бояться подобного рода атак, то единственный вариант защиты — открытое железо. И то никто не гаратирует, что на фабрике в него не добавят еще какой-нибудь скрытый контролер, чтобы управлять всем, так что проще всего расслабиться и попытаться получить удовольствие.
                Цель ИБ — не предотвратить любые виды атак, а сделать так, чтобы стоимость атаки была выше стоимости обрабатываемой информации. Короче, если вы обрабатываете сверхсекретные сведения — делайте себе для этого процессоры сами. А если вы обрабатываете фотографии котиков — просто не парьтесь и все.


                1. Alexeyslav
                  22.09.2015 09:58

                  Нет, ну просто обидно будет если китай вдруг решит защищаться от нападения какой-то страны а у тебя комп потухнет навсегда только потому что тебе не посчастливилось получить материнку из нужной партии. Вдвойне будет обидней, если при этом 90% жителей твоего города будут иметь те же самые проблемы потому что не стали переплачивать за брендовые платы… цифровая жизнь вошла в нашу жизнь настолько плотно, что такой удар даже по некритичным сервисам будет довольно болезненным.
                  Уж молчу про китайские планшеты, с непонятного происхождения прошивками.