Не так давно я случайно обнаружил, что современные UEFI-совместимые прошивки имеют подозрительно много, скажем так, особенностей настройки как самого BootGuard (и его аналога от AMD, который UEFITool NE пока что не поддерживает, но мы работаем над этим), так и вендорских продолжений BG на том(а) DXE. Странности эти - не новость, и о них говорили и Трэммел Хадсон, и Александр Матросов, и многие другие исследователи безопасности UEFI-совместимых прошивок, но воз этот не просто “и ныне там”, он, по ощущениям, с тех пор еще сильнее уехал в сторону жопы. Вот про нее я в этой статье и постараюсь вам рассказать, про то, как делать надо, и как делать не надо, и про то, как делают нынешние IBV, и почему у них получается именно так. Поехали!
Для начала, краткая справка о BootGuard, если вдруг кто не знал, что это, или забыл за давностью лет: BootGuard - это, с одной стороны, название вполне определенной технологии криптографической защиты начального загрузчика (фаз SEC и PEI), поддерживаемой процессорами Intel начиная с Haswell (где он хоть и был, но работал довольно криво, отчего прошивок Haswell с настроенным BootGuard практически не встречается) или Broadwell (где он, наконец, заработал, и вендоры начали его включать). С другой же стороны (как это ранее произошло с Unitas, Jeep, Xerox и т.п.) BootGuard’ом начали называть все подобные системы (и других вендоров процессоров, и IBV-шные продолжения на фазу DXE).
Суть BootGuard (в более широком смысле) в том, чтобы обеспечить цепочку доверия от начального загрузчика до (в идеале) всех неизменяемых байт образа прошивки, который хранится на заведомо недоверенном устройстве (NOR flash с интерфейсом SPI или, позднее, eSPI). Корнем доверия при этом BootGuard не является (у Intel таковым является CSME, у AMD - PSP), и выполняется на основном процессоре (т.е. там же, где и остальные компоненты UEFI-совместимой прошивки).
В общем, BootGuard нужен для того, чтобы атакующий, получивший доступ на запись NOR flash, на котором хранится прошивка, не мог внести в нее неавторизованные изменения, добавить своих PEI/DXE-драйверов, удалить имеющиеся (к примеру, компоненты Computrace), применить какие-либо патчи, и т.п. Правильно реализованный BG должен “накрывать” все исполняемые компоненты прошивки, не накрытые уже до него другими средствами (например, микрокоды накрывать BG не нужно, потому что они уже и так накрыты собственной криптографической подписью).
На практике, к сожалению, получается далеко не так здорово, как в теории, и проблемы имеются и с самим Intel BootGuard (в узком смысле), и со всеми его продолжениями (которых вендоры от радости, вызванной отсутствием BootGuard (в широком смысле) в спецификациях UEFI Forum, понаписали целый зоопарк своих проприетарных). Вот о них я и предлагаю поговорить в этой статье, упуская пока что отдельный случай AMD PSP, о котором потом нужно будет отдельную большую статью писать (и в котором я разбираюсь несколько менее хорошо на данный момент, и до того, как лучше разберусь, не хочу ерунды понаписать).
Вопросы к настройке Intel BootGuard
Не стану тут в подробностях рассказывать, как именно устроен и работает Intel BootGuard, отправлю интересующихся вот сюда (на русском), и вот сюда, сюда и сюда (на английском), ограничусь только вопросами.
Для начала, вопросов нет к тайваньским вендорам, которые не настраивают BG совсем - это не ужасная проблема безопасности, а сознательный выбор не ограничивать пользователя (и атакующего) в возможностях отката и модификации прошивки его материнской платы. Более того, те же вендоры предоставляют возможности прошить модифицированную прошивку, используя инструменты для ее восстановления, такие как ASUS USB BIOS Flashback, ASRock BIOS Flashback, и т.п. Gigabyte иногда умудряется настроить BootGuard таким образом, чтобы он покрывал лишь малую часть фазы PEI, и делает это, видимо, для предотвращения атаки вида “злоумышленник сконфигурировал до этого не сконфигурированный BG, и теперь пользователь не может ни обновить прошивку, ни удалить зловредные модификации, не имея ключа, которым владеет злоумышленник”, которую нетрудно провернуть, имея доступ к утилитам Intel для разработчиков прошивок (а именно, к Flash Image Tool, Flash Programing Tool, и MEManuf, поставляемых вендорам в составе пакета Intel System Tools, и постоянно утекающих в широкий доступ). Короче - если BG не настроен совсем, или какие-то его компоненты присутствуют (ACM, к примеру), а какие-то нет (нет ни Key Manifest, ни Boot Policy Manifest, например, и при этом также отсутствуют вендорские продолжения на фазу DXE) - это не ужас-кошмар-уязвимость, а честный сознательный выбор вендора, скажем ему спасибо.

Отдельный вопрос - утечка ключей, которых было несколько (Lenovo China, MSI, Clevo), и все они автоматически приводят весь BootGuard в полную небоеготовность. Если злоумышленник может подписывать свои образы тем же ключем, что и вендор - никакая самая правильная настройка уже не поможет, а поможет только отзыв и перевыпуск вендорского ключа (которые может выполнить только Intel, потому что Key Manifest подписывают именно они). При этом отозвать утекший ключ можно только на системах, поддерживающих SVN, т.е. использующих CSME v12 и выше (Cannon Lake и новее).
Что делать: не хранить закрытые ключи в том же репозитории, что и исходный код прошивки, вместо этого использовать отдельный защищенный сервер, доступный только через корпоративную систему SSO, и только тем, кто имеет право подписывать финальные релизные образы. Обычным разработчикам прошивок давать доступ только к специальным ключам для разработчиков, утечка которых ни к чему плохому не приведет на всех production-fused системах в руках у пользователей.
Второй отдельный вопрос - пропуск этапа перехода с эмуляции FPF на использование реальных FPF. Поначалу такие забавные системы встречались даже у Lenovo, Dell и HP, но баг довольно быстро нашли и исправили, и теперь он либо совсем не встречается, либо очень быстро и тихо чинится. В данном случае результат тот же - если хеш Boot Policy Manifest не прописан в FPF по-настоящему, то BootGuard можно считать не настроенным, со всеми вытекающими.
Что делать: не пропускать этапы окончательной настройки вашей платформы, читать документацию глазами, а не жопой, не менять настройки доступа к флеш-регионам по желанию левой пятки (а если таки меняете, помните, что вы теперь сами отвечаете за отключение CSME Manufacturing Mode, и не забудьте отключить его).
Дальше у нас идут разного рода тупые ошибки конфигурации, которые нынче встречаются хоть и редко, но метко. К примеру, пустой блок IBB, в котором не записано ни одного хеша, не являлся для Flash Image Tool ошибкой сборки какое-то нетривиальное время, и такие прошивки точно были у Gigabyte на некоторых ноутбуках (сейчас уже не найду такого образа, но помню точно). Получается, что все компоненты настроены, фьюзы прошиты, но ничего не проверятся, потому что ничего проверять и не просили. Очень удобно, хоть и очень глупо, все время на инициализацию ACM, проверку подписи его самого, подписи Key Manifest’а, подписи и хеша Boot Policy Manifest’а, хеша IBB - потрачено впустую, каждый раз при очередной загрузке ПК или просыпании его ото сна. Не то, чтобы 50 мс делали какую-то великую погоду, но тем не менее.
Что делать: открывать релизный образ прошивки в новых версиях (M)FIT, или в последней версии UEFITool NE, оба будут жаловаться на такое безобразие.
Отдельная максимально тупая ошибка конфигурации (которая будет преследовать нас на протяжении всей этой портянки, и всплывет еще не раз, и даже не два) - дыры в сегментах IBB, т.е. либо не полное накрытие томов PEI (DXE обычно накрывают уже вендорским продолжением, потому что при просыпании из S3 он не нужен, а читать его каждый раз из NOR flash, чтобы посчитать его хеш(и) - очень медленно), либо экономия на проверке свободного места в томах (в которое атакующий спокойно добавит свои драйверы, и место перестанет быть свободным, а хеши как сходились, так и продолжат сходиться).
Что делать: открывать релизный образ в UEFITool NE и очень внимательно смотреть его на предмет наличия дыр. К сожалению, и само умение видеть дыры, и желание открывать каждый образ перед релизом - за них нужно платить высокую зарплату, а большинство конечных вендроров - бомжи, и на зарплаты у них денег нет. Те, у кого все же есть, пишут иногда свои собственные утилиты для поиска дыр, плюс Intel теперь мягко, но настойчиво предлагает использовать FSP, в котором весь свой BootGuard они настраивают сами, и специалисты у них есть, поэтому и настроен он теперь чаще всего так, что дыры в нем не зияют.

Про остальные ошибки конфигурации я не стану писать, потому что они все мелкие, и к компрометации (в основном) не приводят, а приводят исключительно к неработоспособности каких-нибудь вещей вроде TXT или fTPM, которые вендор, зачастую, и не заявлял как работоспособные на этой конкретной плате или системе.
Вендорские продолжения, и вопросы к ним
Как я уже упоминал выше, продолжение BootGuard на фазу DXE не является ни частью открытого кода EDK2, ни спецификаций UEFI Forum, а отдано на растерзание IBV, каждый из которых выдумывает свое, в-этот-раз-точно-самое-лучшее-мамой-клянемся, решение, и успешно (или нет) им пользуется. В результате этой вакханалии нам в UEFITool NE приходится поддерживать (с переменным успехом) следующие варианты:
AMI Hash File v1, v2, v3, v4
Insyde Flash Device Map
Phoenix Hash File
Microsoft PMDA v1, v2
Нельзя уверенно утверждать, что никаких других вариантов в дикой природе не встречается, так что если вы вдруг найдете какой-то - сообщите нам о нем, постараемся добавить.
Начнем с конца, а именно с Microsoft PMDA, за который Microsoft можно смело похвалить, потому что вместо придумывания очередных непонятных костылей разработчики прошивок для всей линейки Surface, кроме самых первых поколений, использовали для хранения своих хешей уже предоставленный Intel элемент Platform Manufacturer Data, находящейся в том же Boot Policy Manifest, что и вся остальная конфигурация BootGuard. Более того, во второй версии этого манифеста MS используют и человеко-читаемую структуру данных, и TCG Hash Algorithm IDs (т.е. угадывать тип хеша по его размеру не нужно). Красавчики, так держать! Проблем с настройками BootGuard в прошивках Surface я не видел, и вопросов у меня к ним нет.
Что делать: учиться у MS делать хорошо, они умеют и практикуют.
Дальше у нас Phoenix, у этих ребят все стабильно, и они с самого Broadwell используют для своего продолжения один и тот же файл с GUID 389CC6F2-1EA8-467B-AB8A-78E769AE2A15, сигнатурой $HASHTBL, и записями вида { UINT8 sha256_hash[32]; UINT32 base; UINT32 size;} Проблемы с этим файлом бывает только одна - уже упомянутые выше дыры, и решение их такое же точно, только теперь на Intel положиться уже не выйдет, придется все делать самим.
Что делать: открывать релизный образ в UEFITool NE и очень внимательно смотреть его на предмет наличия дыр.
Теперь на очереди Insyde Flash Device Map, которая нужна не только для хранения и проверки хешей, но и используется прошивкой при обновлении, поиске компонентов, и множестве других случаев. Формат FDM тоже относительно прост и стабилен (не стану тут его расписывать, интересующихся отправлю вот сюда), но интересен тем, что даже если хеш определенного региона прошивки присутствует в карте, он может быть проигнорирован атрибутом HashIgnored. Неправильное использование этого бита (т.е. игнорирование томов, в которых либо уже лежат исполняемые файлы, либо их туда может положить атакующий) - это гарантированное разрывание всей защиты тома DXE (а иногда и PEI тоже) на немецкий крест. Вот такое, например, на 8.2 по шкале CVSS v3 (что для уязвимости, требующей обхода защиты от записи на NOR flash - неожиданно много, мою гораздо более опасную уязвимость в прошлый раз те же господа из Insyde оценили на 7.8 по той же шкале).

Еще одна проблема с FDM - возможность иметь несколько карт с разным содержимым, и не накрывать вторую карту из первой, т.е. атакующий может банально установить на запись тома DXE из ненакрытой карты бит HashIgnored (или обновить хеш, что еще менее заметно) и идти любить в нем гусей и ждать ответного гудка.
Что делать: открывать релизный образ в UEFITool NE и очень внимательно смотреть его на предмет наличия дыр, как и в прошлый раз.

Закончим на AMI Hash File, эти пацаны - вообще ребята, и потому меняли формат своих хешей уже раза четыре на моей памяти, причем угадать этот формат, не занимаясь реверс-инженерией драйверов, которые хеши проверяют - никакого способа нет, все эвристики из текущей версии UEFITool NE - игра в угадайку по размеру файла. Несмотря на постоянную смену формата файла, GUID у него один и тот же - CBC91F44-A4BC-4A5B-8696-703451D0B053. В оригинальной версии формата было сразу несколько проблем: в файле не было адреса тома DXE, и прошивка искала его сама (иногда не находя по разным причинам, и молча продолжая работу как ни в чем не бывало), и свободное место в томе DXE не было накрыто (т.е. от добавления драйверов такая “защита” не защищала). AMI понадобилось несколько месяцев, чтобы понять, что что-то там не так, и заменить формат на “два хеша с базой и размером”, стало получше, но когда два хеша оказалось мало, пришлось сделать “больше чем два хеша, но сколько точно - мы вам не скажем”, точное число хардкодилось прямо в драйвер BootGuardPei на этапе его сборки. В конце концов, кто-то знакомый с sha256_init/process/final понял, что хеш можно иметь один единственный, а не считать его для каждой пары “база, размер” отдельно. Число пар по прежнему нигде не хранится и хардкодится прямо в драйвер, блджад! Проблема у версий 2-4 одинаковая: снова дыры, будь они не ладны.
Что делать: придумать себе нормальный формат один раз (у MS срисовать хотя бы), не хардкодить однобайтовые числа хрен пойми куда, обновить GUID у файла с хешами. С дырами - то же самое, что и раньше.
Заключение
Практически все вышеописанные проблемы с настройкой BG - результат того, что у IBV нет удобного тулинга для проверки статических инвариантов вида “каждый байт каждого тома, из которого прошивка может потенциально что-то исполнять, чем-нибудь накрыт”, и сама прошивка не может проверить подобные инварианты динамически (потому что у нас тут extensibility во все поля, и нельзя просто понять, исполняемся мы с недоверенного хранилища, или с доверенного, а на сложно у нас и лапки, и денег нет). И даже если какой-то тулинг есть - нужно как-то заставить разработчиков прошивки им пользоваться, а они, чаще всего, одновременно перегружены и низкооплачиваемы. Поэтому проблемы эти все никуда не деваются, а дыры как зияли, так и продолжают зиять, к радости пользователей, которым хочется модифицировать прошивку своего компьютера (по разным причинам), а производитель её что-то там пытался от пользователя защищать, но рылом не вышел.