
Подробный технический анализ и PoC-эксплойт для CVE-2024-30051 — переполнение буфера в куче в библиотеке Windows DWM Core Library, обеспечивающее локальное повышение привилегий до уровня целостности System.
В этом сообщении блога я объясню уязвимость в основной библиотеке Microsoft Windows DWM, которую я анализировал при разработке эксплойта для Core Impact. Она позволяет непривилегированному злоумышленнику выполнять код от имени пользователя DWM с привилегиями целостности системы (CVE-2024-30051).
Поскольку на момент разработки эксплойта было недостаточно общедоступной информации, мне пришлось много реверсить, поэтому здесь я покажу, как реверсировать патч KB5037771 для Windows 23H2 с помощью IDA PRO. Я буду использовать BINDIFF для выполнения бинарного сравнения между dwmcore.dll версии 10.0.22621.3447 и версии 10.0.22621.3593, покажу, как возникает переполнение кучи, а затем проэксплуатирую его, повышая привилегии, и, наконец, создам рабочий PoC.
Содержание:
[Уязвимость повышения привилегий в основной библиотеке DWM Windows (CVE-2024-30051) 1](#windows-dwm-core-library-elevation-of-privilege-vulnerability-cve-2024-30051)
[Детали уязвимости: 2](#vulnerability-details)
[Сравнение для поиска ошибки: 3](#diffing-to-find-the-bug)
[Анализ PoC, эксплуатирующего CVE-2024-30051: 8](#analysis-of-the-poc-exploiting-cve-2024-30051)
[1) Инициализация 8](#initialization)
[2) Перехват (Hooking) 8](#hooking)
[3) Создание окна 16](#creating-the-window)
[4) Создание устройства 16](#create-device)
[5) Создание фабрики 22](#create-factory)
[6) Создание контекста устройства 28](#create-a-device-context)
[7) Создание композиционного устройства 29](#create-a-composition-device)
[8) Вызов функции hook3 31](#calling-dcompositioncreatedevice-function)
[9) Создание цели для дескриптора окна (HWND) 32](#creating-a-target-for-handle-hwnd)
[10) Создание поверхности (Surface) 33](#creating-surface)
[11) Вызов BeginDraw, EndDraw и CreateVisual 34](#calling-begindraw-enddraw-and-createvisual)
[11) Вызов Visual SetContent 36](#calling-visual-setcontent)
[12) Освобождение объектов 38](#release-objects)
[13) Фиксация композиционного устройства 38](#commit-composition-device)
[14) Вызов hook2 39](#calling-hook2)
[15) Вызов hook 39](#remember-that-the-vulnerable-function-can-be-reached-using-some-methods-of-the-cprimitivegroup-class.-at-this-point-it-creates-a-heap-then-hook2-captures-and-saves-the-corresponding-heaphandle.)
[16) Вызов hook4 41](#calling-the-function-hook4)
[17) Выполнение Heap Spray 49](#performing-heap-spray)
[18) Изменение базового блока перед отправкой 51](#modifying-the-base-chunk-before-send)
[19) Отладка процесса DWM 52](#debugging-the-dwm-process)
[20) Повышение привилегий до уровня целостности системы 62](#elevating-privileges-to-integrity-system-level)
Уязвимость повышения привилегий в основной библиотеке DWM Windows CVE-2024-30051
Опубликовано: 14 мая 2024 г.
Назначение CNA: Microsoft CVE-2024-30051
Воздействие: Повышение привилегий
Максимальная серьезность: Важно
Слабость:
CWE-122: Переполнение буфера в куче
CVSS: 3.1 7.8 / 7.2
Уязвимость существует из-за ошибки в расчете размера при целочисленном делении в основной библиотеке Windows DWM, называемой dwmcore.dll. Локальный пользователь может вызвать переполнение буфера в куче в методе CCommandBuffer::Initialize в dwmcore.dll и может выполнить произвольный код от имени пользователя DWM с привилегиями целостности системы. Эксплойт выполнит Heap Spray в процессе DWM для подготовки памяти и, наконец, вызовет переполнение кучи в dwmcore.dll, которое активируется при освобождении определенных частей heap spray.
Как только эксплойт успешен, процесс DWM загружает нашу специально созданную DLL, которая выполняет наш код или наш исполняемый файл (в нашем случае CMD) от имени пользователя DWM, имеющего привилегии целостности системы.

Давайте разберем эту уязвимость и посмотрим, как она позволяет нам запускаться от имени пользователя DWM с уровнем целостности SYSTEM. Обратите внимание, что поскольку это не пользователь, принадлежащий к группе администраторов, у него есть некоторые ограничения привилегий.
Патч для Windows 11 23H2 можно загрузить с:
https://www.catalog.update.microsoft.com/Search.aspx?q=KB5037771
windows11.0-kb5037771-x64_19a3f100fb8437d059d7ee2b879fe8e48a1bae42.msu
Уязвимая версия dwmcore.dll: 10.0.22621.3447
Исправленная версия dwmcore.dll: 10.0.22621.3593
Анализируя измененные функции, видно, что исправленная версия CCommandBuffer::Initialize имеет много добавленных блоков, что делает ее совершенно непохожей на незаплатанную версию.

После статического реверс-инжиниринга этой функции обнаруживаются два вызова CD2DSharedBuffer::GetBufferSize.
Первый вызов получает размер для выделения в new, а второй вызов получает тот же размер для memcpy.

На первый взгляд все кажется правильным. Однако перед выделением выполняются некоторые операции с размером.

Он получает buffer_size и buffer_size2, вызывая одну и ту же функцию CD2DSharedBuffer::GetBufferSize, причем оба возвращают одно и то же значение. Но в new выполняется предварительная операция: целочисленное деление buffer_size на 0x90, а затем умножение на 0x90, тогда как в memcpy используется возвращаемое buffer_size2 без каких-либо операций над ним.
С помощью этих операций я обнаружил, что размер, используемый в new и в memcpy, может различаться.
buffer_size = buffer_size2 (возвращаемые размеры)
size_new= buffer_size/0x90 x 0x90
size_memcpy=buffer_size2
Например, если buffer_size равно 0x91
buffer_size = buffer_size2=0x91
size_new= buffer_size/0x90 x 0x90 =0x90
size_memcpy= buffer_size2= 0x91
Этот пример доказывает, что существует переполнение кучи. Копируется больше байт, чем выделено, и размер контролируем.
Например, если buffer_size равно 0x23f, как используется в POC.
buffer_size = buffer_size2=0x23F
size_new= buffer_size/0x90 x 0x90 =0x1b0
size_memcpy= buffer_size2=0x23f