Малварь как искусство Windows CLFS CVE-2022-37969 - часть 2. Эксплуатируем уязвимость (1 Viewer)

Пользователи, которые просматривают: тема

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 611
Реакции
22 826
Если кто-то осилил часть 1:Малварь как искусство - Уязвимость Windows CLFS CVE-2022-37969 - часть 1. Слабонервным не читать. Опасно для мозга

Даже мне было не легко прочитать, но интересно... ohmy88 wacko88 Dmeh-Smeh-Smeh!!! Dmeh-Smeh-Smeh!!! Dmeh-Smeh-Smeh!!!

Набераемся сил, и...Dmeh-Smeh-Smeh!!!

Читаем вторую часть:

Также благодарим Crypt0_Rabb1t с xss.is за крутой перевод.)

Отладочная среда:
Анализ и отладка для эксплуатации проводились в следующей среде.
Windows 11 21H2 версии 22000.918
CLFS.sys 10.0.22000.918

Windows 10 21H2 версии 19044.1949
CLFS.sys 10.0.19041.1865

Предпосылка

Прежде чем приступить к анализу эксплуатации CVE-2022-37969, мы хотели бы представить некоторые ключевые структуры ядра, связанные с этой уязвимостью.
Структура _EPROCESS — это непрозрачная структура, представляющая объект процесса для процесса в ядре. Другими словами, каждый процесс, работающий в Windows, имеет соответствующий объект _EPROCESS где-то в ядре. На рис. 1 показан макет структуры _EPROCESS в ядре для Windows 11. Этот макет может существенно различаться между версиями Windows.

1668956069924.png

Рисунок 1. Структура _EPROCESS в Windows 11

Поле Token хранится по смещению 0x4B8 в структуре _EPROCESS. _EPROCESS. Token указывает на структуру _EX_FAST_REF, а не на структуру _TOKEN. Исходя из схемы структуры _EX_FAST_REF, три ее поля (Object, RefCnt, Value) имеют одинаковое смещение, последние 4 цифры объекта _EX_FAST_REF представляют поле RefCnt, обозначающее ссылку на данный токен. Поэтому мы можем обнулить последние 4 цифры и получить фактический адрес структуры _TOKEN.

Структура _TOKEN - это структура ядра, которая описывает контекст безопасности процесса и содержит такую информацию, как идентификатор токена, привилегии токена, идентификатор сессии, тип токена, сессия входа и т.д. На рисунке 2 показана схема структуры _TOKEN в ядре.

1668956109702.png

Рисунок 2. Структура _Token в Windows 11

В целом, манипулирование объектом _Token может быть использовано для выполнения эскалации привилегий в ядре. При этом используются две общие техники: замена токена, которая означает, что низкопривилегированный токен, связанный с процессом, заменяется высокопривилегированным токеном, связанным с другим процессом. Вторая техника - корректировка привилегий токена, которая означает, что к существующему токену добавляются и включаются дополнительные привилегии. Эксплойт, зафиксированный ThreatLabz для CVE-2022-37969, использовал технику замены токена.

В пользовательском пространстве пользователь может использовать функцию CreatePipe для создания анонимной передачи данных, которая возвращает манипуляторы для чтения и записи на концах созданной передачи.

Код:
  BOOL CreatePipe(
      [out] PHANDLE hReadPipe,
      [out] PHANDLE hWritePipe,
[in, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
      [in] DWORD nSize

    );

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

Код:
    struct PipeAttribute {
       LIST_ENTRY list ;
       char * AttributeName;
       uint64_t AttributeValueSize;
       char * AttributeValue;
       char data [0];

    };

    typedef struct _LIST_ENTRY {
      struct _LIST_ENTRY *Flink;
      struct _LIST_ENTRY *Blink;
    } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;

Схема памяти структуры PipeAttribute показана на рисунке 3.

1668956197080.png

Рисунок 3. Структура PipeAttribute

PipeAttribute может быть создан с помощью API NtFsControlFile, где 6-й параметр FsControlCode имеет значение 0x11003C. Значение атрибута можно прочитать с помощью API NtFsControlFile, где 6-й параметр FsControlCode имеет значение 0x110038.

Структура _ETHREAD - это непрозрачная структура, которая представляет объект потока для потока в ядре. На рисунке 4 показана схема структуры _ETHREAD. Поле PreviousMode расположено по смещению 0x232 в структуре _ETHREAD.

1668956222709.png

Рисунок 4. Структура _ETHREAD

Что касается PreviousMode, в документации Microsoft говорится: "Когда приложение в пользовательском режиме вызывает Nt или Zw версию процедуры системных служб, механизм системного вызова переводит вызывающий поток в режим ядра. Чтобы указать, что значения параметров были получены в пользовательском режиме, обработчик системного вызова устанавливает поле PreviousMode в объекте потока вызывающего приложения в UserMode".

В качестве примера возьмем функцию NtWriteVirtualMemory. На рисунке 5 показана реализация функции NtWriteVirtualMemory. Когда PreviousMode установлен в 1 (UserMode), вызов функции версии NT или Zw происходит из пространства пользователя, где она проводит проверку адреса. В этом случае произвольная запись во всю память ядра будет неудачной. Напротив, когда PreviousMode установлен в 0 (KernelMode), проверка адреса пропускается, и произвольный адрес памяти ядра может быть записан. Эксплойт, нацеленный на Windows 10 для CVE-2022-37969, использует PreviousMode для реализации примитива произвольной записи.

1668956281228.png

Рисунок 5. Реализация функции NtWriteVirtualMemory

Эксплуатация в Windows 11

В предыдущем разделе мы представили ключевые структуры, которые будут задействованы в процессе эксплуатации. Давайте углубимся в пример эксплойта.

0x01 Проверка версии ОС Windows

Сначала эксплойт проверяет, поддерживается ли версия операционной системы (ОС) Windows, на которой запущен образец. На рисунке 6 показан фрагмент псевдокода для проверки версии ОС Windows.

1668956316618.png

Рисунок 6. Фрагмент псевдокода, проверяющий версию ОС Windows

На рисунке 7 показан номер сборки ОС Windows, который состоит из номера сборки ОС и UBR.

1668956336140.png

Рисунок 7. Номер сборки ОС Windows

Эксплойт сначала получает объект _PEB через NtCurrentTeb()->ProcessEnvironmentBlock, затем получает номер сборки ОС из поля OSBuildNumber по смещению 0x120 в структуре _PEB. UBR может быть получен путем запроса значения UBR в ключе реестра HKEY_LOCAL_MACHINE\Software\\\Microsoft\Windows NT\CurrentVersion. Как только эксплойт подтверждает, что целевая Windows поддерживается, код сохраняет смещение поля Token для структуры _EPROCESS в глобальной переменной. В нашей отладочной среде для Windows 11 (21H2) 10.0.22000.918 смещение было равно 0x4B8.

Основываясь на коде на рисунке 6, мы обобщили поддерживаемые версии ОС Windows на рисунке 8.

1668956372806.png

Рисунок 8. Поддерживаемая версия ОС Windows (до патча)

Лаборатория ThreatLabz компании Zsclaer проверила эксплойт в следующих версиях, где можно успешно выполнить локальное повышение привилегий. Другие уязвимые версии ОС Windows на рисунке 8 не были проверены ThreatLabz на момент публикации.

Windows 10 21H2 версия 19044.1949, Windows 10 Enterprise
Windows 10 20H2 версия 19042.1949, Windows 10 Enterprise
Windows 11 21H2 версия 22000.918, Windows 11 Pro x64

0x02 Получение _EPROCESS и _TOKEN

Далее эксплойт получает ключевые структуры данных _EPROCESS и _TOKEN для текущего процесса и процесса System (всегда PID 4), обладающего привилегией SYSTEM, путем вызова API NtQuerySystemInformation с соответствующими параметрами. API NtQuerySystemInformation используется для получения указанной системной информации на основе первого параметра, с объявлением, показанным ниже.

Код:
 __kernel_entry NTSTATUS NtQuerySystemInformation(
      [in] SYSTEM_INFORMATION_CLASS SystemInformationClass,
      [in, out] PVOID SystemInformation,
      [in] ULONG SystemInformationLength,
      [out, optional] PULONG ReturnLength

    );

На рисунке 9 показан фрагмент псевдокода для получения соответствующих адресов объектов _EPROCESS и _TOKEN для текущего процесса и процесса System.
1668956435523.png

Рисунок 9. Фрагмент псевдокода для получения соответствующего адреса объектов _EPROCESS и _TOKEN

Эта функция описывается следующим образом:

1. Определите адрес функции API NtQuerySystemInformation.
2. Вызовите API NtQuerySystemInformation, где первый параметр задан SystemExtendedHandleInformation (0x40). Если функция возвращает NTSTATUS success, то полученная информация сохраняется во втором параметре SystemInformation, который является указателем на структуру SYSTEM_HANDLE_INFORMATION_EX, схема памяти которой показана на рисунке 10. Далее код находит объект _EPROCESS, связанный с текущим процессом. Наконец, адрес объекта _EPROCESS сохраняется в глобальной переменной.

1668956465877.png

Рисунок 10. Схема памяти структуры SYSTEM_HANDLE_INFORMATION_EX

3. Снова вызовите API NtQuerySystemInformation, где первым параметром задается SystemExtendedHandleInformation (0x40). Если функция возвращает NTSTATUS success, код определяет местонахождение объекта _EPROCESS, связанного с процессом System (PID 4). Наконец, адрес объекта System _EPROCESS сохраняется в глобальной переменной.
4. Получите адрес поля Token объекта _EPROCESS, представляющего текущий процесс, и адрес поля Token объекта _EPROCESS, представляющего процесс System. Оба адреса хранятся в соответствующих глобальных переменных.

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

1668956498910.png


0x03 Проверка маркера доступа

Эксплойт вызывает функцию OpenProcessToken для открытия маркера доступа, связанного с текущим процессом. Указатель на handle, идентифицирующий только что открытый маркер доступа, сохраняется в третьем параметре, когда функция OpenProcessToken возвращается. Затем эксплойт вызывает API NtQuerySystemInformation, где первый параметр задается SystemHandleInformation (0x10). Если возвращается NTSTATUS success, то проверяется, существует ли handle, идентифицирующий только что открытый маркер доступа, в списке системных handle. На рисунке 12 показан фрагмент псевдокода для проверки маркера доступа.

1668956530661.png

Рисунок 12. Фрагмент псевдокода для проверки маркера доступа

0x04 Получение постоянного смещения между двумя большими пулами, представляющими Base Block

Как показано на рисунке 9 в части 1, код Proof-of-Concept для CVE-2022-37969 сначала создает базовый файл журнала MyLog.blf через CreateLogFile API. Затем код создает десятки базовых журнальных файлов с именем MyLog_xxx.blf, где в PoC Zscaler ThreatLabz используется постоянный счетчик. Код эксплойта использует следующую усовершенствованную технику, чтобы обеспечить постоянство смещения между двумя впоследствии созданными bigpools, представляющими базовый блок. На рисунке 13 показан фрагмент кода для получения постоянного значения между двумя соседними пулами, представляющими Base Block.

1668956571954.png

Рисунок 13. Фрагмент кода для получения постоянного значения между двумя соседними бигпулами, представляющими Base Block

После создания каждого нового базового файла с именем MyLog_xxx.blf код вызывает API ZwQuerySystemInformation, где первым параметром задается SystemBigPoolInformation(0x42). Если функция возвращает NTSTATUS success, то полученная информация сохраняется во втором параметре SystemInformation, который является указателем на структуру SYSTEM_BIGPOOL_ENTRY, хранящую всю память бигпула во время выполнения. Затем находится бигпул, представляющий Base Block базового файла журнала, где размер бигпула должен быть 0x7a00, а имя тега бигпула - "Clfs". Адрес bigpool хранится в локальном массиве. Далее, в цикле, код проверяет, является ли смещение между базовым блоком N-го BLF и базовым блоком N+1-го BLF постоянным. Код будет не выходить из цикла до тех пор, пока смещение не станет постоянным. В нашей отладочной среде постоянное значение равно 0x11000. Постоянное значение плюс 0x14B устанавливается в поле cbSymbolZone в Base Record Header.

0x05 Создание базового файла журнала

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

На рисунке 14 показан процесс распыления кучи.

1668956659881.png

Рисунок 14. Выполните распыление кучи для настройки памяти

На рисунке 15 показана схема памяти после выполнения распыления кучи.

1668956679278.png

Рисунок 15. Макет памяти после выполнения распыления кучи

0x06 Модуль-гаджет, выполняющий примитив произвольной записи

На рисунке 16 показан фрагмент кода для выполнения произвольной записи на объект PipeAttribute.

1668956697991.png

Рисунок 16. Фрагмент кода для выполнения произвольной записи на объект PipeAttribute

Этот фрагмент кода описывается следующим образом:

1. Вызов функции CreatePipe для создания анонимного перехода и добавление атрибутов этого перехода с помощью API NtFsControlFile, где 6-й параметр FsControlCode имеет значение 0x11003C. Затем код вызывает API ZwQuerySystemInformation, где первый параметр установлен в SystemBigPoolInformation(0x42). После того как функция возвращает NTSTATUS success, полученная информация представляет собой указатель на структуру SYSTEM_BIGPOOL_ENTRY, в которой хранится вся память bigpool во время выполнения. Наконец, эксплойт находит bigpool, представляющий только что созданный объект PipeAttribute. Переменная v30 хранит адрес ядра этого объекта PipeAttribute. На рисунке 17 показано расположение памяти созданного объекта PipeAttribute в ядре.

1668956737980.png

Рисунок 17. Схема памяти созданного объекта PipeAttribute в ядре Windows

2. В глобальной переменной qword_1400A8108 хранится адрес ядра объекта _EPROCESS для процесса System (PID 4). Затем эксплойт выполняет распыление кучи, как показано на рисунке 18. Адрес поля AttributeValueSize в объекте PipeAttribute устанавливается по смещению N*8+8 в области памяти (0x10000 ~ 0x1010000). Результат addr_EPROCESS_System & 0xfffffffffff000 записывается по смещению 0xFFFFFFFFFF, а 0x41414141414141005A записывается по смещению 0x100000007.

1668956769991.png

Рисунок 18. Эксплойт CVE-2022-37969 выполняет распыление кучи

3. Упорядочить область памяти (0x5000000~0x5100000), где адрес функции ClfsEarlierLsn хранится по адресу 0x5000008, а адрес функции SeSetAccessStateGenericMapping - по адресу 0x5000018 (см. рисунок 19).

1668956792708.png

Рисунок 19. Область памяти (0x5000000~0x5100000)

4. Запустить уязвимость CLFS. Будет поражена функция CClfsBaseFilePersisted::RemoveContainer. На рисунке 20 показано место разыменования поврежденного указателя на поддельный объект CClfsContainer в CLFS.sys. Данные, на которые указывает разыменовываемый адрес, можно контролировать и манипулировать с помощью распыления кучи в пространстве пользователя.

1668956841451.png

Рисунок 20. Разыменование поврежденной точки в объекте CClfsContainer

Поддельный vftable в поддельном объекте CClfsContainer указывает на 0x5000000, где адрес функции ClfsEarlierLsn хранится по адресу 0x5000008, а адрес функции SeSetAccessStateGenericMapping хранится по адресу 0x0x5000018. Последующий код будет последовательно вызывать функцию ClfsEarlierLsn и функцию nt!SeSetAccessStateGenericMapping. После возврата функции ClfsEarlierLsn регистр RDX равен 0xFFFFFFFF. На рисунке 21 показано, что делает функция SeSetAccessStateGenericMapping и как выполнить произвольную запись.

1668956877375.png
Рисунок 21. Выполнение произвольной записи в объект PipeAttribute

В конце функции SeSetAccessStateGenericMapping поле AttributeValue в объекте PipeAttribute было перезаписано в addr_EPROCESS_System & 0xfffffffffffff000. addr_EPROCESS_System представляет собой адрес объекта _EPROCESS для процесса System (PID 4).

5. Прочитайте атрибут pipe с помощью API NtFsControlFile, где 6-й параметр FsControlCode установлен в 0x110038. Это позволяет получить атрибут pipe с адреса, на который указывает перезаписанное поле AttributeValue, и скопировать данные ядра в буфер кучи в пространстве пользователя. Переписанное поле AttributeValue указывает на адрес addr_EPROCESS_System & 0xfffffffffff000. Затем код получает поле Token в объекте _EPROCESS для процесса System (PID 4), основываясь на смещении поля Token. Наконец, значение поля Token для процесса System (PID 4) сохраняется в глобальной переменной qword_1400A8128.

1668956927341.png

Рисунок 22. Сохранение значения поля Token для процесса System (PID 4)

0x07 Замена Token

На рисунке 23 показан фрагмент кода для выполнения замены Token в Windows 11.

1668956945897.png

Рисунок 23. Фрагмент кода для выполнения замены маркера

Чтобы завершить замену Token эксплойт запускает уязвимость CLFS во второй раз и выполняет следующие действия.

1. Упорядочивает память с помощью распыления кучи. Результирующий адрес поля Token для текущего процесса минус 8 устанавливается по смещению N*8+8 в области памяти (0x10000 ~ 0x1010000). Значение поля Token в объекте _EPROCESS для процесса System (PID 4) записывается по смещению 0xFFFFFFFF, как показано на рисунке 24.

1668956977476.png

Рисунок 24. Упорядочивание памяти с помощью распыления кучи

2. Запуск уязвимости CLFS для завершения замены токена. Будет атакована функция CClfsBaseFilePersisted::RemoveContainer. На рисунке 25 показано место разыменования поврежденного указателя на поддельный объект CClfsContainer в CLFS.sys. Данные, на которые указывает разыменовываемый адрес, можно контролировать и манипулировать с помощью распыления кучи в пространстве пользователя.

1668957007544.png

Рисунок 25. Разыменование поврежденной точки на объект CClfsContainer

И снова последующий код будет последовательно вызывать функцию ClfsEarlierLsn и функцию nt!SeSetAccessStateGenericMapping. После возврата функции ClfsEarlierLsn регистр RDX равен 0xFFFFFFFF. На рисунке 26 показано, что делает функция SeSetAccessStateGenericMapping и как выполнить произвольную запись.

1668957035027.png

Рисунок 26. Выполнение произвольного примитива записи для завершения замены маркера

В конце функции SeSetAccessStateGenericMapping замена маркера была завершена, рисунок 27. Token для текущего процесса был заменен на Token для процесса System (PID 4).

Это означает, что текущий процесс успешно повысил привилегии до SYSTEM.big010101wink1

1668957094708.png

Рисунок 27. Успешно получите привилегию SYSTEM.


3. Создайте командную строку (cmd.exe) с полученной привилегией SYSTEM. На рисунке 28 показано, что эксплойт порождает cmd.exe с привилегией SYSTEM.

1668957124683.png
Рисунок 28. Создание команды cmd с привилегией SYSTEM


Мы обобщили процесс эксплуатации, нацеленный на Windows 11, на рисунке 29.

1668957154628.png

Рисунок 29. Поток эксплуатации, нацеленной на Windows 11

Далее, процесс выполнения произвольной записи на объект PipeAttribute и замены маркера продемонстрирован на рисунке 30.

1668957175060.png

Рисунок 30. Процесс выполнения произвольной записи на объект PipeAttribute и замена токена в Windows 11

Эксплуатация на Windows 10

Мы разбили процесс эксплуатации в Windows 11 на 7 шагов. Для Windows 10 процесс эксплуатации по-прежнему состоит из 7 шагов, шаги 1-5 такие же, как и в Windows 11. Выполнение произвольного примитива записи и замена маркера отличаются от шагов в Windows 11. На рисунке 31 показан фрагмент кода для выполнения произвольной записи и замены маркера в Windows 10.

1668957316337.png

Рисунок 31. Выполнение произвольного примитива записи и замены токена в Windows 10

Выполнение произвольного примитива записи и замены токена в Windows 10 включает следующие шаги.

1. Выполните распыление кучи для создания памяти, в которой 0x0018000000000800 записывается по смещению 0xFFFFFFFF, а 0x000F0000000000 записывается по смещению 0x100000007. На рисунке 32 показана память в районе 0xFFFFFFFF.

1668957345245.png

Рисунок 32. Расположение области памяти (0xFFFFFFFFFF ~ 0x10000000E)

Кроме того, на рисунке 33 показано расположение области памяти (0x10000~0x1010000). Поле PreviousMode расположено по смещению 0x232 в структуре _ETHREAD. Значение (addr_of_PreviousMode - 8) устанавливается по смещению N*8+8 в области памяти, начинающейся с 0x10000.

1668957363630.png

Рисунок 33. Схема расположения области памяти (0x10000~0x1010000)

2. Расположите область памяти (0x5000000~0x5100000), где адрес функции ClfsEarlierLsn хранится по адресу 0x5000008, а адрес функции SeSetAccessStateGenericMapping - по адресу 0x0x5000018 (см. Рисунок 34).

1668957392102.png

Рисунок 34. Область памяти (0x5000000~0x5100000)

3. Запустить уязвимость CLFS. Будет поражена функция CClfsBaseFilePersisted::RemoveContainer. На рисунке 35 показано место разыменования поврежденного указателя на поддельный объект CClfsContainer в CLFS.sys. Данные, на которые указывает разыменовываемый адрес, можно контролировать и манипулировать с помощью распыления кучи в user space.

1668957429454.png

Рисунок 35. Разыменование поврежденного указателя на объект CClfsContainer

Поддельный vftable в поддельном объекте CClfsContainer указывает на 0x5000000, где адрес функции ClfsEarlierLsn хранится по адресу 0x5000008, а адрес функции SeSetAccessStateGenericMapping хранится по адресу 0x0x5000018. Последующий код будет последовательно вызывать функцию ClfsEarlierLsn и функцию nt!SeSetAccessStateGenericMapping. После возврата функции ClfsEarlierLsn регистр RDX равен 0xFFFFFFFF. На рисунке 36 показано, что делает функция SeSetAccessStateGenericMapping и как выполнить произвольную запись.

1668957464508.png

Рисунок 36. Выполнение произвольной записи в режиме PreviousMode в Windows 10

В конце функции SeSetAccessStateGenericMapping параметр PreviousMode в объекте _ETHREAD устанавливается в 0, что означает, что разрешена неограниченная операция чтения/записи по всей памяти ядра с использованием NtReadVirtualMemory и NtWriteVirtualMemory. Это мощный метод для разрешения чтения/записи. На этом этапе эксплойт готов к выполнению произвольной записи.

4. Вызов функции NtWriteVirtualMemory для перезаписи буфера, на который указывает переменная локального указателя, значением поля Token в _EPROCESS для System (PID 4). Далее код снова вызывает функцию NtWriteVirtualMemory для перезаписи поля Token в _EPROCESS для текущего процесса данными (значение поля Token в _EPROCESS для System), которые хранятся в буфере, на который указывает эта локальная переменная-указатель, что завершает замену маркера. Рисунок 37 демонстрирует, что поле Token в _EPROCESS для текущего процесса было заменено на поле Token в _EPROCESS для процесса System (PID 4).

1668957509367.png

Рисунок 37. Замена маркера в Windows 10

5. Вызовите NtWriteVirtualMemory для перезаписи поля PreviousMode в объекте _ETHREAD, чтобы завершить восстановление PreviousMode, что может предотвратить крах вновь запущенного процесса с привилегией SYSTEM.

6. Создайте командную строку (cmd.exe) с привилегией SYSTEM, как показано на рисунке 38.

1668957547920.png

Рисунок 38. Создание команды cmd с привилегией SYSTEM в Windows 10

В итоге процесс выполнения произвольной записи в PreviousMode и замены маркера на Windows 10 продемонстрирован на рисунке 39.

1668957570888.png

Рисунок 39. Процесс выполнения произвольной записи в PreviousMode и замены токена в Windows 10

Общий эксплойт, совместимый с Windows 10 и Windows 11

ThreatLabz протестировала код эксплойта, нацеленный на Windows 10, на Windows 11 с помощью исправления бинарного файла эксплойта. После срабатывания уязвимости CLFS значение _EThread.PreviousMode перезаписывается на 0, что приводит к следующему сбою, показанному на рисунке 40.

1668957607848.png

Рисунок 40. Сбой происходит после того, как _EThread.PreviousMode устанавливается в 0 в Windows 11

Как показано на рисунке 36, код эксплойта перезаписывает PreviousMode через вызов SeSetAccessStateGenericMapping, что может привести к повреждению поля AffinityFill и вызвать крах на Windows 11. На рисунке 41 показаны смещения полей PreviousMode и AffinityFill в структуре _EThread.

1668957633143.png

Рисунок 41. Смещения PreviousMode и AffinityFill в структуре _EThread

Предположим, что только PreviousMode (1 байт) перезаписывается в 0 через новый указанный гаджет. В качестве такого указанного гаджета выберем nt!RtlClearBit. Мы можем изменить область памяти (0x5000000~0x5100000), где адрес функции nt!RtlClearBit хранится по адресу 0x5000018, а адрес функции CLFS!ClfsEarlierLsn - по адресу 0x0x5000008 (см. Рисунок 42). Кроме того, нам необходимо переставить область памяти (0x10000~0x1010000). Адрес PreviousMode в объекте _ETHREAD устанавливается по смещению N*8+8 в области памяти, начинающейся с 0x10000.

1668957655909.png

Рисунок 42. Запуск данной уязвимости CLFS

Сначала вызывается функция nt!RtlClearBit. На рисунке 43 показано, как происходит перезапись PreviousMode. Инструкция BTR сохраняет выбранный бит во флаге CF и очищает выбранный бит в битовой строке до 0, где регистр EDX равен 0. В результате PreviousMode устанавливается в 0. Мы видим, что в конце функции nt!RtlClearBit перезаписывается только поле PreviousMode, а другие последующие байты не перезаписываются.

1668957676355.png

Рисунок 43. PreviousMode устанавливается в 0 посредством вызова nt!RtlClearBit

Затем функция ClfsEarlierLsn вызывается в функции CLFS!CClfsBaseFilePersisted::RemoveContainer. Таким образом, мы можем использовать другую группу гаджетов (nt!RtlClearBit и CLFS!ClfsEarlierLsn) для выполнения произвольной записи в PreviousMode, что хорошо работает в Windows 11. Код эксплойта для Windows 10 будет работать и на Windows 11, если заменить старые гаджеты на новые (nt!RtlClearBit и CLFS!ClfsEarlierLsn). В результате, использование (nt!RtlClearBit и CLFS!ClfsEarlierLsn) может упростить рабочий процесс эксплуатации на Windows 11, где эта CLFS-уязвимость срабатывает только один раз.

По итогу:

Мы проанализировали процесс эксплуатации CVE-2022-37969 на Windows 10 и Windows 11. Для Windows 11 эксплойт сначала запускает уязвимость CLFS для выполнения произвольной записи для объекта PipeAttribute. Затем эксплойт задействует уязвимость CLFS во второй раз, чтобы выполнить замену маркера. Для Windows 10 эксплойт запускает уязвимость CLFS только один раз и использует технику PreviousMode для реализации примитива произвольной записи, а затем завершает замену маркера вызовом функции NtWriteVirtualMemory.

Более того, мы убедились, что техника PreviousMode по-прежнему работает в Windows 11. Мы продемонстрировали еще одну группу гаджетов (nt!RtlClearBit и CLFS!ClfsEarlierLsn), которые могут быть использованы для выполнения произвольной записи для PreviousMode. Таким образом, общий эксплойт, совместимый с Windows 10 и 11, может использовать nt!RtlClearBit для выполнения произвольной записи на PreviousMode, а затем завершить замену маркера вызовом функции NtWriteVirtualMemory.
 

Вложения

  • 1668957386255.png
    1668957386255.png
    81.2 КБ · Просмотры: 0
Верх