Приветствую вас, дорогие читатели! Сегодня я хочу поделиться с вами своим опытом изучения BlackLotus UEFI bootkit. В этом исследование разберем следующие темы:
Состав стенда:
Для начала необходимо примонтировать «Системный раздел EFI», для этого необходимо проделать следующие шаги.
Далее нужно скопировать файлы из poc_amd64_19041.iso в системный раздел. Для используем Total Commander (Total Commander нужно запускать с правами администратора).
Сделаем копию оригинального BCD файла и назовём ее BCDR(Понадобиться потом).
Создадим snapshot для виртуальной машины Windows 10 x64-BatonDrop, так как в будущем потребуется к нему вернуться.
Импортируем bcd файл из poc_amd64_19041.iso с помощью bcdedit.exe.
После этого выключаем виртуальную машину Windows 10 x64-BatonDrop и при включении возникает ошибка.
Замечание: При отладке Windows 10x64-BatonDrop необходимо использовать одно ядро.
Теперь приступим к настройке отладки в системе Windows 10 x64-BatonDrop. Возвращаемся к snapshot good.
Выполняем команды от имени администратора в виртуальной машине Windows 10x64-BatonDrop, затем выключим виртуальную машину Windows 10x64-BatonDrop.
Добавляем Serial Port для Windows 10x64-BatonDrop.
Потом изменим файл C:\Users\user\Documents\Virtual Machines\Windows 10x64-BatonDrop\Windows 10x64-BatonDrop.vmx. Удалим строки.
Переименуем serial1 на serial0 и сохраняем файл Windows 10x64-BatonDrop.vmx.
Находясь на рабочем месте исследователя Windows 10x64, настроим Windbg.
Дальше срабатывает системное прерывание int 3.
После срабатывания системного прерывания ищем загруженные файлы.
У нас есть файл bootmgfw (с ним и начнем работать), у которого Imagebase 0x0000000010000000.
Теперь возвращаемся к snapshot good и импортируем bcd file.
Выключаем виртуальную машину Windows 10x64-BatonDrop и изменяем файл C:\Users\user\Documents\Virtual Machines\Windows 10x64-BatonDrop\Windows 10x64-BatonDrop.vmx, чтобы отладить с помощью IDA Pro.
Включаем виртуальную машину Windows 10x64-BatonDrop и смотрим файл C:\Users\user\Documents\Virtual Machines\Windows 10x64-BatonDrop\vmware.log, так как нам необходимо узнать порт для подключения с помощью IDA Pro.
После проделанных действий открываем IDA Pro и загружаем файл bootmgfw.efi(Файл bootmgfw.efi берётся из E:\EFI\Microsoft\Boot\bootmgfw.efi).
Добавляем bootmgfw.pdb файл в IDA PRO.
Замечание: Файл bootmgfw.pdb можно скачать, воспользовавшись ссылкой http://msdl.microsoft.com/download/...94B898929165E26611E4791B87F6B1B2/bootmgfw.pdb, где C94B898929165E26611E4791B87F6B1B2.
Или можно использовать скрипт pdbdownload.py.
Изменяем Imagebase на 0x0000000010000000 в IDA Pro.
Ставим breakpoint на начало функции BmMain.
Настраиваем отладку в IDA Pro и запускаем отладку.
В функции BmMain мы можем увидеть срабатывание breakpoint.
Эти находки значительно упрощают задачу и помогают понять с чего начать исследование.
Начнем с восстановления читабельности функции BlImgLoadPEImageEx и получим следующие. Замечание: В этих двух проектах есть описание функции BlImgLoadPEImageEx.
Поставим breakpoint на функцию BlImgLoadPEImageEx -> ImgpOpenFile , чтобы детально проанализировать передаваемые в неё аргументы.
Запускаем отладку в IDA Pro и останавливаемся на функции BlImgLoadPEImageEx -> ImgpOpenFile. Однако мы не можем просмотреть содержимое аргументов (регистров или памяти), потому что IDA Pro не может отобразить эту память — она находится вне области видимости IDA Pro.
Для решения этой проблемы напишем скрипт read_memory.py для IDA Pro.
Воспользуемся скриптом read_memory.py. При первом срабатывании breakpoint(BlImgLoadPEImageEx → ImgpOpenFile) видим открытие файла BOOTX64.ELF.MUI. Поскольку этот файл нас не интересует, просто нажимаем F9 и продолжаем выполнение.
При втором срабатывании breakpoint(BlImgLoadPEImageEx → ImgpOpenFile) видим открытие файла bootmgr.elf, это тот файл который нам нужен.
Теперь перейдем к изучениюфункции BlImgLoadPEImageEx → ImgpLoadPEI mage, откроем ссылку. И после исследования кода по ссылке, мы приходим к выводу, что нам нужно получить адрес VirtualAddress.
В IDA Pro устанавливаем breakpoint на функцию RtlImageNtHeaderEx (BlImgLoadPEImageEx → ImgpLoadPEImage → RtlImageNtHeaderEx).
Запускаем отладку в IDA Pro, останавливаемся на функции BlImgLoadPEImageEx -> ImgpLoadPEImage -> RtlImageNtHeaderEx и мы видим начало файла bootmgr.elf, которое начинается с 'MZ'.
Дальше перейдём к изучению функции ImgArchStartBootApplication и восстановим её читабельность. В проекте ReactOS: boot/freeldr/freeldr/bootmgr.c File Reference описание данной функции не было найдено, однако в GitHub - backengineering/Voyager: A Hyper-V Hacking Framework For Windows 10 x64 (AMD & Intel) удалось обнаружить описание её аргументов. Это означает, что нам придётся провести отладку, чтобы разобраться в работе функции ImgArchStartBootApplication. После отладки можно сделать вывод, что функция ImgArchStartBootApplication работает следующим образом.
Сначала мы проходим по функциям.
В конце функции Archpx64TransferTo64BitApplicationAsm, после retfq необходимо еще немного отладить.
В итоге, это приведет нас к call rax, при вызове которого происходит передача управления на функцию BmMain в файле bootmgr.elf.
Откроем IDA Pro и загрузим файл bootmgr.elf (Файл bootmgr.elf берётся из E:\EFI\ minram\bootmgr.elf).
Добавляем bootmgr.pdb файл в IDA Pro (Ссылка для скачивания).
Изменяем Imagebase на 0x0000000000613000 в IDA Pro.
Устанавливаем breakpoint в конец функции Archpx64TransferTo64BitApplicationAsm на retfq.
Запускаем отладку в IDA Pro, останавливаемся в конец функции Archpx64TransferTo64BitApplicationAsm на retfq и после retfq еще немного отлаживаем.
И это нас привело к call rax, при вызове которого происходит передача управления на функцию HvlMain в файле hvloader.efi.
- Подготовка тестового стенда.
- Запуск CVE-2022–21 894 (baton drop).
- Компиляция payload и компонентов для его выполнения.
- Добавление сертификата в базу данных MOK.
- Чтение и запись файлов в операционной системе Windows10 из файловой системы NTFS через grub.elf.
1. Подготовка тестового стенда.
Состав стенда:
- Windows 10×64 — рабочее место исследователя.
- VMware Workstation — платформа для виртуализации (Версия 17.0.0 build-20 800 274).
- VMware Workstation Менеджер — ПО для предоставления доступа к виртуальным машинам на VMware Workstation.
- Windows 10×64-BatonDrop — виртуальная машина, подготовленная для проведения исследований (Версия Windows 10 Pro 21H2 19 044.1288). Настройки системы были выбраны стандартные.
1.1 Попытка запуска CVE-2022-21894(BatonDrop).
Для начала попробуем запустить CVE-2022-21894. В этом исследование действия будут проводиться с файлом poc_amd64_19041.iso, который скачаем по ссылке.Для начала необходимо примонтировать «Системный раздел EFI», для этого необходимо проделать следующие шаги.
Далее нужно скопировать файлы из poc_amd64_19041.iso в системный раздел. Для используем Total Commander (Total Commander нужно запускать с правами администратора).
Сделаем копию оригинального BCD файла и назовём ее BCDR(Понадобиться потом).
Создадим snapshot для виртуальной машины Windows 10 x64-BatonDrop, так как в будущем потребуется к нему вернуться.
Импортируем bcd файл из poc_amd64_19041.iso с помощью bcdedit.exe.
После этого выключаем виртуальную машину Windows 10 x64-BatonDrop и при включении возникает ошибка.
2. Отладка CVE-2022-21894 (baton drop)
После появления ошибки 0xc0 000 010, обратимся к статье BlackLotus UEFI bootkit: Myth confirmed (welivesecurity.com), чтобы понять, какие файлы загружаются и в каком порядке. Эта информация важна для определения того, что именно требуется отладить. Только пройдя по этим файлам можно понять, где срабатывает ошибка 0xc0 000 010.Замечание: При отладке Windows 10x64-BatonDrop необходимо использовать одно ядро.
2.1 Настройка отладки
Для начала разберёмся, что именно мы будем настраивать и как это сделать. Мы изучили документы MSDN по следующим темам:Теперь приступим к настройке отладки в системе Windows 10 x64-BatonDrop. Возвращаемся к snapshot good.
Выполняем команды от имени администратора в виртуальной машине Windows 10x64-BatonDrop, затем выключим виртуальную машину Windows 10x64-BatonDrop.
Добавляем Serial Port для Windows 10x64-BatonDrop.
Потом изменим файл C:\Users\user\Documents\Virtual Machines\Windows 10x64-BatonDrop\Windows 10x64-BatonDrop.vmx. Удалим строки.
Переименуем serial1 на serial0 и сохраняем файл Windows 10x64-BatonDrop.vmx.
Находясь на рабочем месте исследователя Windows 10x64, настроим Windbg.
2.2 Отладка файла bootmgfw.elf.
После настройке отладки запускаем виртуальную машину Windows 10x64-BatonDrop и в Windbg(Windows 10x64) видим подключение.Дальше срабатывает системное прерывание int 3.
После срабатывания системного прерывания ищем загруженные файлы.
У нас есть файл bootmgfw (с ним и начнем работать), у которого Imagebase 0x0000000010000000.
Теперь возвращаемся к snapshot good и импортируем bcd file.
Выключаем виртуальную машину Windows 10x64-BatonDrop и изменяем файл C:\Users\user\Documents\Virtual Machines\Windows 10x64-BatonDrop\Windows 10x64-BatonDrop.vmx, чтобы отладить с помощью IDA Pro.
Включаем виртуальную машину Windows 10x64-BatonDrop и смотрим файл C:\Users\user\Documents\Virtual Machines\Windows 10x64-BatonDrop\vmware.log, так как нам необходимо узнать порт для подключения с помощью IDA Pro.
После проделанных действий открываем IDA Pro и загружаем файл bootmgfw.efi(Файл bootmgfw.efi берётся из E:\EFI\Microsoft\Boot\bootmgfw.efi).
Добавляем bootmgfw.pdb файл в IDA PRO.
Замечание: Файл bootmgfw.pdb можно скачать, воспользовавшись ссылкой http://msdl.microsoft.com/download/...94B898929165E26611E4791B87F6B1B2/bootmgfw.pdb, где C94B898929165E26611E4791B87F6B1B2.
Или можно использовать скрипт pdbdownload.py.
Python:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
import re
import binascii
import pefile
import struct
def to_pdb(filename):
return re.sub(r'.[^.]+$', '.pdb', os.path.basename(filename))
def build_url(filename):
guid = ""
pdb = to_pdb(filename)
pe = pefile.PE(filename)
for dbg in pe.DIRECTORY_ENTRY_DEBUG:
if dbg.struct.Type == 2: # IMAGE_DEBUG_TYPE_CODEVIEW
guid = '%s%s%s%s%s%s%s' % (
binascii.hexlify(struct.pack('>I', dbg.entry.Signature_Data1)).decode('ascii').upper(),
binascii.hexlify(struct.pack('>H', dbg.entry.Signature_Data2)).decode('ascii').upper(),
binascii.hexlify(struct.pack('>H', dbg.entry.Signature_Data3)).decode('ascii').upper(),
binascii.hexlify(dbg.entry.Signature_Data4).decode('ascii').upper() if isinstance(dbg.entry.Signature_Data4, bytes) else struct.pack('H', dbg.entry.Signature_Data4).hex().upper(),
binascii.hexlify(dbg.entry.Signature_Data5).decode('ascii').upper() if isinstance(dbg.entry.Signature_Data5, bytes) else struct.pack('H', dbg.entry.Signature_Data5).hex().upper(),
binascii.hexlify(dbg.entry.Signature_Data6).decode('ascii').upper() if isinstance(dbg.entry.Signature_Data6, bytes) else struct.pack('I', dbg.entry.Signature_Data6).hex().upper(),
dbg.entry.Age)
break
return 'http://msdl.microsoft.com/download/symbols/%s/%s/%s' % (pdb, guid, pdb)
def main():
if len(sys.argv) < 2:
print("Usage: %s /tmp/notepad.exe /tmp/kernel32.dll" % (sys.argv[0]))
return
for filename in sys.argv[1:]:
downurl = build_url(filename)
destfile = os.path.dirname(os.path.abspath(filename)) + "/" + to_pdb(filename)
print("Saving %s to %s" % (downurl, destfile))
os.system("curl -L %s -o %s" % (downurl, destfile))
if __name__ == '__main__':
main()
Изменяем Imagebase на 0x0000000010000000 в IDA Pro.
Ставим breakpoint на начало функции BmMain.
Настраиваем отладку в IDA Pro и запускаем отладку.
В функции BmMain мы можем увидеть срабатывание breakpoint.
2.3 Переход из файла bootmgfw.elf в файл bootmgr.elf.
Теперь нам необходимо перейти из файла bootmgfw.elf в файл bootmgr.elf, однако возникает сложность: непонятно, как это сделать. Не ясно, какие функции исследовать в файле bootmgfw.elf, а изучать и отлаживать всё подряд — неэффективно. В такой ситуации Google становится нашим лучшим помощником. Во время поиска информации было найдено несколько полезных проектов:- ReactOS: boot/freeldr/freeldr/bootmgr.c File Reference: В этот проекте есть детальная документация по структурам, функциям, их аргументам и многому другому для ОС Windows.
- GitHub - backengineering/Voyager: A Hyper-V Hacking Framework For Windows 10 x64 (AMD & Intel): В этом проекте наибольшую ценность представляет фотография, на которой указаны функции BlImgLoadPEImageEx, BlImgLoadPEImage, BlImgAllocateImageBuffer, ImgArchStartBootApplication.
Эти находки значительно упрощают задачу и помогают понять с чего начать исследование.
Начнем с восстановления читабельности функции BlImgLoadPEImageEx и получим следующие. Замечание: В этих двух проектах есть описание функции BlImgLoadPEImageEx.
Поставим breakpoint на функцию BlImgLoadPEImageEx -> ImgpOpenFile , чтобы детально проанализировать передаваемые в неё аргументы.
Запускаем отладку в IDA Pro и останавливаемся на функции BlImgLoadPEImageEx -> ImgpOpenFile. Однако мы не можем просмотреть содержимое аргументов (регистров или памяти), потому что IDA Pro не может отобразить эту память — она находится вне области видимости IDA Pro.
Для решения этой проблемы напишем скрипт read_memory.py для IDA Pro.
Python:
import idc
import sys
def read_memory_debug(ea, size):
memory_data = []
for i in range(size):
byte = idc.DbgByte(ea + i)
if byte == 0xFF and not idc.isLoaded(ea + i):
print("Не удалось прочитать байт по адресу 0x{0:X}".format(ea + i))
break
memory_data.append(byte)
return memory_data
def main():
if len(sys.argv) != 3:
print("Использование: script.py <адрес> <размер>")
return
try:
start_ea = int(sys.argv[1], 16) # преобразование адреса из строки в число
size = int(sys.argv[2])
except ValueError:
print("Ошибка: убедитесь, что адрес и размер введены корректно.")
return
# Чтение и вывод данных
offset = 0
for i in range(0, size, 16):
start_ea_offset = start_ea + offset
data = read_memory_debug(start_ea_offset, 16)
if data:
hex_data = " ".join("{:02X}".format(byte) for byte in data)
str_data = "".join(chr(byte) if 32 <= byte <= 126 else '.' for byte in data)
print("0x{0:X} | ".format(start_ea_offset) + "{0:<47} | ".format(hex_data) + "{0}".format(str_data))
offset += 16
if __name__ == "__main__":
main()
Воспользуемся скриптом read_memory.py. При первом срабатывании breakpoint(BlImgLoadPEImageEx → ImgpOpenFile) видим открытие файла BOOTX64.ELF.MUI. Поскольку этот файл нас не интересует, просто нажимаем F9 и продолжаем выполнение.
При втором срабатывании breakpoint(BlImgLoadPEImageEx → ImgpOpenFile) видим открытие файла bootmgr.elf, это тот файл который нам нужен.
Теперь перейдем к изучениюфункции BlImgLoadPEImageEx → ImgpLoadPEI mage, откроем ссылку. И после исследования кода по ссылке, мы приходим к выводу, что нам нужно получить адрес VirtualAddress.
В IDA Pro устанавливаем breakpoint на функцию RtlImageNtHeaderEx (BlImgLoadPEImageEx → ImgpLoadPEImage → RtlImageNtHeaderEx).
Запускаем отладку в IDA Pro, останавливаемся на функции BlImgLoadPEImageEx -> ImgpLoadPEImage -> RtlImageNtHeaderEx и мы видим начало файла bootmgr.elf, которое начинается с 'MZ'.
Дальше перейдём к изучению функции ImgArchStartBootApplication и восстановим её читабельность. В проекте ReactOS: boot/freeldr/freeldr/bootmgr.c File Reference описание данной функции не было найдено, однако в GitHub - backengineering/Voyager: A Hyper-V Hacking Framework For Windows 10 x64 (AMD & Intel) удалось обнаружить описание её аргументов. Это означает, что нам придётся провести отладку, чтобы разобраться в работе функции ImgArchStartBootApplication. После отладки можно сделать вывод, что функция ImgArchStartBootApplication работает следующим образом.
Сначала мы проходим по функциям.
В конце функции Archpx64TransferTo64BitApplicationAsm, после retfq необходимо еще немного отладить.
В итоге, это приведет нас к call rax, при вызове которого происходит передача управления на функцию BmMain в файле bootmgr.elf.
2.4 Переход из файла bootmgr.elf в файл hvloader.efi.
После того как мы нашли Imagebase 0x0000000000613000 файла bootmgr.elf и понимания, что нужно отлаживать функцию Archpx64TransferTo64BitApplicationAsm. Переход из файла bootmgr.elf в файл hvloader.efi должен пройти без затруднений, так как принцип перехода такой же как переход из файла bootmgfw.elf в файл bootmgr.elf.Откроем IDA Pro и загрузим файл bootmgr.elf (Файл bootmgr.elf берётся из E:\EFI\ minram\bootmgr.elf).
Добавляем bootmgr.pdb файл в IDA Pro (Ссылка для скачивания).
Изменяем Imagebase на 0x0000000000613000 в IDA Pro.
Устанавливаем breakpoint в конец функции Archpx64TransferTo64BitApplicationAsm на retfq.
Запускаем отладку в IDA Pro, останавливаемся в конец функции Archpx64TransferTo64BitApplicationAsm на retfq и после retfq еще немного отлаживаем.
И это нас привело к call rax, при вызове которого происходит передача управления на функцию HvlMain в файле hvloader.efi.
Последнее редактирование: