Как стать автором
Поиск
Написать публикацию
Обновить
310
8
Николай Шлей @CodeRush

Firmware Security Engineer

Отправить сообщение

Всей прошивки - исключена практически, а для NVRAM конкретно вместе с хранилищем основных переменных либо делают резервное (чтобы если основное вышло из строя, можно было загрузиться и восстановить то, что выжило, а остальное взять из копии), либо используют отдельный блок и драйвер для Fault Tolerant Write.

Если немного раскрыть идею про "накапливать", можно сделать атрибут для SetVariable вроде "переменная не очень важная, можно кэшировать, если 0, писать разу на флеш, если 1", и в зависимости от него в кэше делать упаковку тех, кому не срочно (т.е. "ждем пока накопится 128 байт изменений, сливаем всех в один блок"), и писать сразу в целый блок тех, кому срочно.

Получится не очень плотно, если срочных будет много, но тут я не вижу вариантов.

Ограничения слишком неприятные получаются, если упаковывать плотнее. По факту у нас запись блоками по 128 байт, и в старые блоки нельзя писать, так что для данных, которые надо обновить, у нас по факту ровно одно место, куда можно писать их - следующий свободный 128-байтовый блок. А дальше там любая переменная размером от 1 до 126 (пусть будет счетчик поколений в 2 байта, для ровного счета) - это одна запись блок. Можно попробовать каждый раз при записи решать задачу о рюкзаке, и пытаться впихнуть сколько-то уже существующих переменных (бампнуть им поколение тоже) в один блок вместе с новой, но может быть медленно и печально (сложность нормального решения такой задачи - почти квадратичная, а у нас МК слабый). В общем, можно разменять производительность на более плотную упаковку, либо нахер выкинуть такой флеш и поставить нормальный SPI/I2C NOR и пошло оно все это в жопу.

А вообще, если еще немного подумать, никакого толку от решения задачи о рюкзаке не будет, если не "накапливать" где-то в ОЗУ несколько вызовов SetVariable перед тем, как на флеш писать. Если писать по одной переменной за раз - никакими оптимизациями там ничего не сделать, потому что мы за один раз в любом случае инвалидируем (т.е. раньше туда можно было писать, теперь - нет) один блок в 128 байт, и потому ничего там меньше все равно сэкономить не выйдет.

Если переменных немного, и место экономить не нужно, то можно сделать минимальный размер переменной в 128 байт, и писать именно с такой грануляцией. Тогда получается, что нам нужно научиться отличать "валидные" переменные от "устаревших", для этого подойдет банальный счетчик "поколений", т.е. функция GetVariable внутри себя проходит по всем записям на флеше, и возвращает значение той, у которой счетчик больше. SetVariable делает то же самое, только пишет в свободное место новую запись с инкрементированным счетчиком. Чтобы не ловить переполнения, счетчик можно сделать 2 или даже 4-байтным.

Как только хранилище заполнилось - стереть все, что сейчас "устарело" по 8 кб за раз, и перенести все оставшееся в начало, сбросив счетчики. Там будет еще проблема небольшая с Fault Tolerant Write, но она решается выделением одного 8кб блока и переносом данных через него.

Если прямо совсем одноразовой - лучше на такой NVRAM не делать. Если же одноразовой-до-страния-блока, можно попробовать ставить в последнем блоке перед свободными счетчик "столько-то блоков до меня - активные, остальные - мусор", и писать все содержимое заново каждый раз при добавлении новой записи. Когда свободные блоки закончатся - стереть все, кроме активных, скопировать активные из конца в начало, стереть в конце. Нагрузка на флеш будет - атас, но работать будет.

Я предпочитаю OpenWRT и роутеры, для которых производитель нативно заявляет его поддержку. В России у меня Cudy WR3000H, в Германии - GL.Inet Flint 2.

Следующая уязвимость с идентификатором CVE-2025-47827 обнаружена исследователем Заком Дидкоттом. Она содержится в модуле igel-flash-driver для ядра Linux, разработанном компанией IGEL Technology. Суть в следюущем: ошибка при верификации криптографической подписи может приводить к загрузке с использованием вредоносной файловой системы.

Несмотря на красивые картинки, которые уважаемый исследователь у себя рисует, уязвимость эта не является обходом UEFI SecureBoot, потому что фаза BDS заканчивается на вызове ExitBootServices, и никаким, даже самым волшебным kexec вернуться к состоянию "было до" без перезагрузки уже не получится. Так ведь можно все уязвимость в драйверах для Windows в обход SB записать...

Обход UEFI SecureBoot - это получение управления в фазе BDS (или раньше, но там уже говорят о перехвате контроля на DXE, а обход SB - это побочный результат), и этому критерию удовлетворяют и CVE-2025-3052, и CVE-2025-4275, и остальные проблемы обходы SecureBoot, которые Binarly нашли до этого.

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

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

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

Только вот это готовы делать три с половиной анонимуса, а MS доставили защиту от загрузочных вирусов на каждый х86 ПК 13 лет назад, пусть дырявую-хреновую, но тем не менее. И буткит теперь в дикой природе найти - очень редкое событие, раз в год плюс-минус, т.е. для обычного пользователя и от дешевых атак защита вполне себе работает.

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

Там вообще надо долго рассказывать, но в итоге получилось удивительно дерьмовое решение, в котором т.н. shim подписан ключом MS (UEFI CA, которым подписана чертова прорва всего, в том числе уязвимого), сам этот shim доверяет всему, что записано в переменной MOKList, которая от перезаписи из ОС защищена (как Задорнов говорил, внимание!) отсутствием атрибута RT.

По человечески, надо всю эту бессмысленную хрень давно уже выкидывать и заново проектировать с учетом того, что на дворе 25 год, и скоро без PQC безопасную загрузку перестанут покупать. Но пока в UEFI Forum заседают три с половиной пенсионера, а за развитие EDK2 отвечают два разработчика из Intel - ничего не изменится.

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

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

Отдельно очень хочется спросить у Microsoft следующее: "господа, а вы там не охуели случайно, подписывать вашим сертификатом для загрузчиков всякое говно хрен пойми от кого"?

Сертификату MS CA 2011 по умолчанию доверяют чуть ли не вообще все системы с UEFI SecureBoot, и MS все время очень ревностно относилась к тому, что она им подписывает (пока внезапно не подписала древний и дырявый насквозь загрузчик для Windows 7, но это другая история), а тут такая оказия.

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

Самое удивительное, что Binarly раскрыли эту уязвимость 10 июня, в тот же день, что и я раскрыл свою CVE-2025-4275, и они получились идеально дополняющими друг друга.

Дело в том, что переменная IhisiParamBuffer, которая используется для эксплуатации CVE-2025-3052, на прошивках Insyde H2O защищена от записи, т.е. их эксплоит работает на всех прошивках, кроме Insyde, а мой - только на Insyde, и для обоих нужна всего лишь возможность писать в NVRAM.

Основная угроза, от которой призван защищать UEFI SB - подмена EFI-загрузчика на вредоносный и\или запуск вредоносных исполняемых файлов до либо параллельно с загрузчиком, через механизмы вроде DriverXXXX/DriverOrder, OptionROM и т.п.

В вашем примере, при правильной настройке (т.е. использовании EFI_STUB и встроенного initramfs) - защитит.

Есть мнение, что вся эта вакханалия - это способ заставить и дальше использовать arm64 и x86 на высокопроизводительных системах, потому что иначе как саботажем вот это "развитие" сложно назвать.

Пока что RISC-V отлично себя чувствует у корпораций как замена микро- и нано-ядер, на которых никакой пользовательский код никогда не должен исполняться, а для своих прошивок можно накрутить любые нестандартные расширения, хоть аналог Apple Matrix eXtension, хоть CHERI, хоть PAC, хоть MTE, и при этом не нужно каждый раз в arm чемодан бабла заносить.

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

Надо статью писать давно уже, и про DriverXXXX, и про KeyXXXX, и про SysPrepXXXX, а то авторы спецификации потребовали, IBV молча реализовали, и никто не в курсе, кроме атакующих, очень удобно...

@ValdikSS, приколись, как они могут. Я думал, что всякую фигню UEFI CA подписывать, а потом ее героически (неправильно) банить - это максимум того, что эта "индустрия" может, но здесь Insyde превзошли и самих себя, и всех остальных. Очень веселый тамада, и очень интересные конкурсы...

1
23 ...

Информация

В рейтинге
120-й
Дата рождения
Зарегистрирован
Активность

Специализация

Embedded Software Engineer, System Software Engineer
Lead