• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Технический анализ уязвимости нулевого дня в драйвере clfs.sys и сплоента (CVE-2022-37969)

varwar

El Diff
Забанен
Регистрация
12.11.2020
Сообщения
1 383
Решения
5
Реакции
1 537
Пожалуйста, обратите внимание, что пользователь заблокирован
В первой части описана причина:

Во второй анализируется сэмпл сплоента:

Вторая часть будет особенно полезна энтузиастам, т.к. подробно описаны актуальные (всё еще) техники для LPE (Windows 10/11). Забавно, но в эксплойте есть одинаковые строки с другим ядерным сплоентом и код явно был частично скопирован или переиспользован (там ошибочка есть). Также любопытно, что в этом сплоенте реализована функция проверки по UBR, что действительно актуально для сплоентов, т.к. версии билда уже недостаточно. Нигде раньше не видел, хотя писал про это пару лет назад на форуме. Только непонятно почему разраб дергал UBR из реестра, а билд дергал из PEB, хотя всю необходимую системную информацию можно было также взять из той ветки, ну да ладно.
 
Ребята, вавилонец yashechka (или возможно, кто-то еще захочет взяться и перевести). Давайте переведем на русский?
прикреплю их пониже
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ребята, вавилонец yashechka (или возможно, кто-то еще захочет взяться и перевести). Давайте переведем на русский?
Перевод нужен, потому что такого качества разборы уязвимостей ядра в Win сейчас на вес золота. Тем более, что это действительно актуальная информация и пока нет намеков на то, что она устареет.

P.S.
Правда у некоторых новичков может отпасть желание заниматься вулн ресерчем и экспдевом после такого. Но дорогу осилит идущий.
 
Последнее редактирование:
Перевод нужен, потому что такого качества разборы уязвимостей ядра в Win сейчас на вес золота. Тем более, что это действительно актуальная информация и пока нет намеков на то, что она устареет.

P.S.
Правда у некоторых новичков может отпасть желание заниматься вулн ресерчем и экспдевом после такого. Но дорогу осилит идущий.
желание отпадёт у тех кого оно не сильное. А если глаза не краснеют от монитора думаю желание не сильное)
 
ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия ноды ETHEREUM и тестов

Технический анализ уязвимости нулевого дня Windows CLFS CVE-2022-37969 — часть 1: анализ первопричин​

2 сентября 2022 г. компания Zscaler Threatlabz зафиксировала эксплойт нулевого дня в общем системном драйвере файлов журнала Windows (CLFS.sys) и сообщила об этом обнаружении в Microsoft. В сентябрьском патче, выпущенном во вторник , Microsoft исправила эту уязвимость, идентифицированную как CVE-2022-37969 , которая представляет собой уязвимость повышения привилегий драйвера общей файловой системы Windows. Злоумышленник, успешно воспользовавшийся этой уязвимостью, может получить системные привилегии. Эксплойт 0-day может успешно выполнить повышение привилегий в Windows 10 и Windows 11 до сентябрьского исправления. Причина уязвимости связана с отсутствием строгой проверки границ поля SignaturesOffset в базовом блоке blf-файла журнала (BLF) в CLFS.sys. Специально созданный массив клиентского контекста и фальшивый клиентский контекст в базовом файле журнала могут использовать CLFS для перезаписи поля SignaturesOffset ненормальным значением. Это приводит к обходу проверки поля cbSymbolZone при выделении символа. Таким образом, недопустимое поле cbSymbolZone может привести к записи вне границ с произвольным смещением. В этой серии блогов, состоящей из двух частей, мы демистифицируем уязвимость и эксплойт нулевого дня, обнаруженный в дикой природе. Блоги состоят из двух частей: анализа основной причины и анализа эксплойта. В этом блоге мы впервые представляем подробный анализ основной причины CVE-2022-37969.

Отладочная среда


Весь анализ и отладка в этой серии блогов, состоящей из двух частей, проводились в следующей среде:
Код:
Windows 11 21H2 version 22000.918
CLFS.sys 10.0.22000.918

Введение во внутренние устройства CLFS


Common Log File System (CLFS) — это подсистема ведения журналов общего назначения, которая может использоваться приложениями, работающими как в режиме ядра, так и в пользовательском режиме, для создания высокопроизводительных журналов транзакций и реализована в драйвере CLFS.sys. Общая файловая система журналов создает журналы транзакций в базовом файле журнала (BLF). Введение в понятия и терминологию для CLFS указано в официальной документации Microsoft.

Перед использованием CLFS файл журнала создается с помощью API CreateLogFile. Файл журнала состоит из blf-файла, состоящего из блоков метаданных, и нескольких контейнеров, в которых хранятся фактические данные. API AddLogContainer используется для добавления контейнера в физический журнал, связанный с дескриптором журнала.


Рисунок 1 иллюстрирует формат BLF на основе официальной документации CLFS Алекса Ионеску и неофициальной документации .

1667866839959.png


Рис. 1. Формат базового файла журнала (BLF)

Blf-файл состоит из шести различных блоков метаданных: Control Block, Base Block и Truncate Block, а также соответствующих им shadow block. В этих блоках могут находиться три типа записей (Control Record, Base Record и Truncate Record). Этот блог посвящен только базовой записи, которая имеет отношение к данной уязвимости. Базовая запись включает в себя символьные таблицы, которые хранят информацию о контекстах клиента, контекстах контейнера и контекстах безопасности, связанных с базовым файлом журнала.

Каждый блок журнала начинается с заголовка блока журнала, структура которого определена ниже:

Код:
typedef struct _CLFS_LOG_BLOCK_HEADER
{
    UCHAR MajorVersion;
    UCHAR MinorVersion;
    UCHAR Usn;
    CLFS_CLIENT_ID ClientId;
    USHORT TotalSectorCount;
    USHORT ValidSectorCount;
    ULONG Padding;
    ULONG Checksum;
    ULONG Flags;
    CLFS_LSN CurrentLsn;
    CLFS_LSN NextLsn;
    ULONG RecordOffsets[16];
    ULONG SignaturesOffset;
} CLFS_LOG_BLOCK_HEADER, *PCLFS_LOG_BLOCK_HEADER;

Схема памяти структуры CLFS_LOG_BLOCK_HEADER, размер которой составляет 0x70 байт, показана на рисунке 1. Поле SignaturesOffset - это смещение массива в памяти, который используется для хранения всех подписей секторов. Массив должен располагаться на последнем секторе каждого блока. Сигнатура сектора располагается в конце каждого сектора (размер: 0x200) и состоит из типа Sector Block Type (1 байт) и Usn (1 байт). Ниже перечислены типы сектора.

Код:
const UCHAR SECTOR_BLOCK_NONE   = 0x00;
const UCHAR SECTOR_BLOCK_DATA   = 0x04;
const UCHAR SECTOR_BLOCK_OWNER  = 0x08;
const UCHAR SECTOR_BLOCK_BASE   = 0x10;
const UCHAR SECTOR_BLOCK_END    = 0x20;
const UCHAR SECTOR_BLOCK_BEGIN  = 0x40;

На рисунке 1 base block начинается по смещению 0x800 и заканчивается по смещению 0x71FF в файле .BLF и начинается с заголовка Log Block Header (0x70 байт), за которым следует заголовок Base Record Header, а затем записи. Заголовок Base Record Header может быть представлен структурой CLFS_BASE_RECORD_HEADER, описанной на рисунке 2.

1667867654333.png


Рисунок 2. Определение структуры CLFS_BASE_RECORD_HEADER​

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

1667867702901.png


Рисунок 3. Структурная схема заголовка Base Record Header в файле .BLF​

Base Record начинается с заголовка (CLFS_BASE_RECORD_HEADER) размером 0x1338 байт, за которым следуют связанные контекстные данные. В структуре CLFS_BASE_RECORD_HEADER ниже описаны некоторые важные поля, связанные с данной уязвимостью:

rgClients представляет массив смещений, указывающих на объект Client Context.
rgContainers представляет собой массив смещений, указывающих на объект Container Context.
cbSymbolZone представляет следующее свободное смещение для нового символа в зоне символов.

В Base Record, Client Context, Container Context и Shared Security Context представлены символами, которым предшествует структура CLFSHASHSYM, определенная ниже:

Код:
typedef struct _CLFS_NODE_ID {
  ULONG cType;
  ULONG cbNode;
} CLFS_NODE_ID, *PCLFS_NODE_ID;

typedef struct _CLFSHASHSYM
{
    CLFS_NODE_ID cidNode;
    ULONG ulHash;
    ULONG cbHash;
    ULONGLONG ulBelow;
    ULONGLONG ulAbove;
    LONG cbSymName;
    LONG cbOffset;
    BOOLEAN fDeleted;
} CLFSHASHSYM, *PCLFSHASHSYM;

Схема памяти структуры CLFSHASHSYM показана на рисунке 4, далее следуют различные объекты контекста.

1667867945505.png

Рисунок 4. Структура CLFSHASHSYM (символично)​

В Base Record клиентский контекст используется для идентификации клиента для файла журнала. В Base Log File может быть создан как минимум один Client Context. Client Context представлен структурой CLFS_CLIENT_CONTEXT, определенной ниже:

Код:
typedef struct _CLFS_CLIENT_CONTEXT
{
    CLFS_NODE_ID cidNode;
    CLFS_CLIENT_ID cidClient;
    USHORT fAttributes;
    ULONG cbFlushThreshold;
    ULONG cShadowSectors;
    ULONGLONG cbUndoCommitment;
    LARGE_INTEGER llCreateTime;
    LARGE_INTEGER llAccessTime;
    LARGE_INTEGER llWriteTime;
    CLFS_LSN lsnOwnerPage;
    CLFS_LSN lsnArchiveTail;
    CLFS_LSN lsnBase;
    CLFS_LSN lsnLast;
    CLFS_LSN lsnRestart;
    CLFS_LSN lsnPhysicalBase;
    CLFS_LSN lsnUnused1;
    CLFS_LSN lsnUnused2;
    CLFS_LOG_STATE eState; //+0x78
    union
    {
        HANDLE hSecurityContext;
        ULONGLONG ullAlignment;
    };
} CLFS_CLIENT_CONTEXT, *PCLFS_CLIENT_CONTEXT;

В Base Record контекст контейнера связан с добавлением файла контейнера для base log file, который представлен структурой CLFS_CONTAINER_CONTEXT, определенной ниже:

Код:
typedef struct _CLFS_CONTAINER_CONTEXT
{
    CLFS_NODE_ID cidNode; //8 bytes
    ULONGLONG cbContainer; //8 bytes
    CLFS_CONTAINER_ID cidContainer; // 4 bytes
    CLFS_CONTAINER_ID cidQueue; // 4 bytes
    union
    {
        CClfsContainer* pContainer; //8 bytes
        ULONGLONG ullAlignment;
    };
    CLFS_USN usnCurrent;
    CLFS_CONTAINER_STATE eState;
    ULONG cbPrevOffset; //4 bytes
    ULONG cbNextOffset; //4 bytes
} CLFS_CONTAINER_CONTEXT, *PCLFS_CONTAINER_CONTEXT;

Поле pContainer является указателем на объект в адресном пространстве ядра CClfsContainer, представляющий контейнер во время выполнения, который находится по смещению 0x18 в структуре CLFS_CONTAINER_CONTEXT. На рисунке 5 показана схема памяти структуры CLFS_CONTAINER_CONTEXT.

1667868548721.png


Рисунок 5. Схема памяти структуры CLFS_CONTAINER_CONTEXT​

Воспроизведение сбоя BSOD

Чтобы определить первопричину CVE-2022-37969, ThreatLabz разработала Proof-of-Concept (PoC), который стабильно вызывает сбой "синего экрана смерти" (BSOD). На рисунке 6 показана подробная информация о сбое после срабатывания уязвимости.

1667868924197.png


Рисунок 6. Информация о крахе CVE-2022-37969 в WinDbg​

Как показано на рисунке 6, регистр rdi указывает на ошибочный адрес памяти. В регистре rdi хранится указатель на объект CClfsContainer. В структуре CLFS_CONTAINER_CONTEXT, описанной ранее, поле pContainer является указателем на объект CClfsContainer и расположено по смещению 0x18 в схеме памяти. Судя по расположению сбоя, поле pContainer в структуре CLFS_CONTAINER_CONTEXT было испорчено. Это приводит к сбою BSOD при разыменовании этого указателя.

На рисунке 7 показано сравнение правильно структурированного BLF-файла и специально созданного BLF-файла, который используется для запуска уязвимости CVE-2022-37969.

1667869110569.png


Рисунок 7. Специально созданный файл Base Log File (BLF) для CVE-2022-37969​

После создания этого bfl-файла определенные байты, включая поле SignatureOffset, массив смещений клиентского контекста, cbSymbol, фальшивый клиентский контекст и т.д., должны быть соответствующим образом изменены. Как показано на рисунке 7, все измененные байты находятся в записи Base Log Record (смещение: 0x800 ~ 0x81FF в файле .blf). Модификации файла .blf перечислены на рисунке 8.

1667869221903.png


Рисунок 8. Модификации файла .BLF для запуска CVE-2022-37969​

Код Proof-of-Concept для запуска CVE-2022-37969 показан на рисунке 9.

1667869268960.png



Рисунок 9. Фрагмент кода для доказательства концепции CVE-2022-37969​

Proof-of-Concept для CVE-2022-37969 включает следующие шаги.

Создайте основной файл журнала MyLog.blf в папке C:\Users\Public\ с помощью API CreateLogFile.
Создайте дюжину базовых файлов журнала с именем MyLog_xxx.blf. Очень важно, чтобы смещение между двумя созданными впоследствии областями памяти, представляющими Base Block, было постоянным (где постоянное смещение равно 0x11000 байт). Оригинальный образец 0-day использовал усовершенствованный метод для получения константы смещения. Во второй части этой серии блогов будет рассмотрена эта техника. В PoC ThreatLabz используется постоянный счетчик для создания blf-файлов, и поэтому смещение между двумя созданными впоследствии областями памяти может быть не постоянным. Следовательно, в данной ситуации необходимо подстроить значение константы.
Измените пару байт в определенных смещениях в файле MyLog.blf, пересчитайте новую контрольную сумму CRC32 для Base Block, затем запишите новое значение контрольной суммы по смещению 0x80C. Затем откройте существующий MyLog.blf.
Вызовите API CreateLogFile, чтобы создать MyLxg_xxx.blf в папке C:\Users\Public\.
Вызовите API AddLogContainer, чтобы добавить контейнер журнала для MyLxg_xxx.blf, созданного на шаге 4.
Вызовите GetProcAddress(LoadLibraryA("ntdll.dll"), "NtSetInformationFile"), чтобы получить адрес функции API NtSetInformationFile.
Вызовите API AddLogContainer, чтобы добавить контейнер журнала для MyLog.blf, открытого в шаге 3.
Вызовите NtSetInformationFile(v55, (PIO_STATUS_BLOCK)v33, v28, 1, (FILE_INFORMATION_CLASS)13), где последний параметр - тип FileInformationClass. Если значение равно FileDispositionInformation (13), функция удалит файл при его закрытии или отменит ранее запрошенное удаление.
Вызовите API CloseHandle для закрытия обработчика MyLxg_xxx.blf, чтобы запустить эту уязвимость.


Анализ причины

Теперь, когда доказательство кода было представлено, можно проанализировать первопричину. На рисунке 9 шаг 3 вызывает API CreateLogFile, 5-й параметр которого равен 4 (OPEN_ALWAYS), что открывает существующий файл или создает его, если он не существует. В данном случае открывается существующий MyLog.blf. На шаге 4 код вызывает API CreateLogFile для создания нового blf-файла с именем MyLxg_xxx.blf. На шагах 5 и 7, соответственно, код вызывает AddLogContainer, чтобы добавить контейнер в физический журнал, связанный с данным хэндлом журнала.
Сначала рассмотрим подробнее, как драйвер CLFS обрабатывает запрос на добавление контейнера журнала при вызове функции AddLogContainer() в пространстве пользователя. Для отслеживания процесса обработки этого запроса можно установить следующую точку останова.

Код:
 bu CLFS!CClfsRequest::AllocContainer

В CLFS.sys класс CClfsRequest отвечает за обработку запросов из пространства пользователя. Функция CClfsRequest::AllocContainer используется для обработки запроса на добавление контейнера в физический журнал. Функция CClfsRequest::AllocContainer вызывает CClfsLogFcbPhysical::AllocContainer, объявление которого показано ниже:

Код:
CClfsLogFcbPhysical::AllocContainer(CClfsLogFcbPhysical *this, _FILE_OBJECT *,_UNICODE_STRING *,unsigned __int64 *)


Далее точка останова на CClfsLogFcbPhysical::AllocContainer устанавливается следующим образом:

Код:
bu CLFS!CClfsLogFcbPhysical::AllocContainer

На шаге 5, когда код вызывает функцию AddLogContainer, срабатывает точка останова на CClfsLogFcbPhysical::AllocContainer. Когда точка останова достигнута, давайте проверим указатель this класса CClfsLogFcbPhysical. Тhis указывает на объект CClfsLogFcbPhysical. Как показано на рисунке 10, в регистре rcx хранится указатель this класса CClfsLogFcbPhysical.

1667870468637.png


Рисунок 10. Проверка указателя этого класса CClfsLogFcbPhysical в CClfsLogFcbPhysical::AllocContainer

Адрес vftable в классе CClfsLogFcbPhysical хранится по смещению 0x00. По смещению this+0x30 хранится указатель на имя журнала. По смещению this+0x2B0 хранится указатель на класс CClfsBaseFilePersisted. В памяти Base Log File CLFS представлен классом CClfsBaseFile, который может быть расширен классом CClfsBaseFilePersisted. В этом указателе класса CClfsBaseFilePersisted по смещению 0x30 хранится указатель на буфер кучи размером 0x90 байт. Кроме того, в буфере кучи по смещению 0x30 хранится указатель на Base Block. Кроме того, в этом указателе CClfsBaseFilePersisted по смещению 0x1C0 хранится указатель на объект CClfsContainer. После успешного добавления контейнера мы можем проверить структуру CLFS_CONTAINER_CONTEXT, описанную на рисунке 5, в памяти, как показано на рисунке 11.

1667870683805.png

Рисунок 11. Структура CLFS_CONTAINER_CONTEXT после успешного добавления контейнера​

По смещению 0x1C0 в объекте CClfsBaseFilePersisted хранится указатель на объект CClfsContainer, который берется из поля pContainer в структуре CLFS_CONTAINER_CONTEXT. В этот момент можно установить точку останова записи в память по адресу CLFS_CONTAINER_CONTEXT+0x18, чтобы отследить, когда указатель на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT будет поврежден. Еще одна точка останова записи в память по смещению 0x1C0 в объекте CClfsBaseFilePersisted может быть установлена следующим образом:


Код:
1: kd> ba w8 ffffc80c`cc86a4f0 //CLFS_CONTAINER_CONTEXT: +0x18

    1: kd> ba w8 ffffb702`3cf251c0 //CClfsBaseFilePersisted: +0x1C0



На шаге 7, когда код вызывает функцию AddLogContainer, точки останова на CLFS!CClfsRequest::AllocContainer и CLFS!CClfsLogFcbPhysical::AllocContainer снова сбиваются. В этот момент давайте проверим указатель this (см. рисунок 12) класса CClfsLogFcbPhysical. Стоит отметить, что поле SignaturesOffset, которое изначально было установлено в 0x00000050 в созданном файле MyLog.blf, в памяти было установлено в 0xFFFF0050.

1667870899802.png


Рисунок 12. Проверка указателя this для класса CClfsLogFcbPhysical

В WinDbg продолжим выполнение кода. Точка останова записи в память "ba w8 ffffc80c`cc86a4f0" будет достигнута, и структура CLFS_CONTAINER_CONTEXT в base Record производит out-of-bound запись, что приводит к повреждению указателя в объекте CClfsContainer, показанном на рисунке 13.

1667870989669.png


Рисунок 13. Повреждение указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT​

Исходя из приведенной выше обратной трассировки стека вызовов, функция memset была вызвана, чтобы вызвать точку останова записи в память в функции CClfsBaseFilePersisted::AllocSymbol. На рисунке 14 показан псевдокод функции CClfsBaseFilePersisted::AllocSymbol.

1667871057186.png


Рисунок 14. Псевдокод функции CClfsBaseFilePersisted::AllocSymbol

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

Переменная v9 - это значение поля cbSymbolZone в заголовке Base Record Header. Поле cbSymbolZone было установлено в аномальное значение, описанное на рисунке 8. Это значение было изменено с 0x000000F8 на 0x0001114B.
Проверьте поле cbSymbolZone. Чтобы выполнить ООВ-запись на шаге 4, эту проверку необходимо обойти. Поле SignaturesOffset, которое изначально имело значение 0x00000050 в файле MyLog.blf, описанном на рисунке 7, было перезаписано большим числом (0xFFFF0050) в памяти. Поэтому, даже когда поле cbSymbolZone установлено в ненормальное значение, проверку для поля cbSymbolZone все равно можно обойти. Определение причины того, что поле SignaturesOffset установлено в 0xFFFF0050 из 0x00000050, является первопричиной CVE-2022-37969.
Переменная v10 равна v9 плюс BaseLogRecord плюс 0x1338, а переменная v9 равна 0x0001114b, что приводит к недопустимому смещению в v10.
Функция вызывает memset(), что приводит к OOB-записи по недопустимому смещению v10, которое попадает в структуру CLFS_CONTAINER_CONTEXT в базовой записи для MyLxg_xxx.blf, что приводит к повреждению указателя CClfsContainer по смещению 0x18 в структуре CLFS_CONTAINER_CONTEXT.

На рисунке 15 показано, как происходит запись вне границ, что приводит к повреждению указателя в объекте CClfsContainer.

1667871169026.png


Рисунок 15. Объяснение несанкционированной записи, вызванной CVE-2022-37969​

Итак, мы обсудили, почему произошла запись вне границ и как был поврежден указатель на объект CClfsContainer в структуре CLFS_CONTAINER_CONEXT. Далее рассмотрим, когда произойдет разыменование поврежденного указателя CClfsContainer. После этого мы вернемся к выяснению того, почему поле SignaturesOffset в памяти установлено в 0xFFFF0050 из 0x00000050.

Когда в пространстве пользователя вызывается функция CloseHandle, за обработку этого запроса отвечает CClfsRequest::Close(PIRP Irp). В ядре еще одна точка останова памяти (0x1c0+CClfsBaseFilePersisted) достигается в функции ClfsBaseFilePersisted::WriteMetadataBlock, как показано на рисунке 16.

1667871258165.png


Рисунок 16. Точка останова памяти(0x1c0+CClfsBaseFilePersisted) в ClfsBaseFilePersisted::WriteMetadataBlock​

Поврежденный указатель копируется на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT в базовой записи по смещению 0x1c0 в объекте CClfsBaseFilePersisted.

На рисунке 17 показан псевдокод функции ClfsBaseFilePersisted::WriteMetadataBlock после того, как поврежденный указатель на CClfsContainer был сохранен по смещению 0x1c0 в объекте CClfsBaseFilePersisted. Код обнуляет поле указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT. После декодирования блока указатель на объект CClfsContainer восстанавливается в структуре CLFS_CONTAINER_CONTEXT со смещения 0x1c0 в объекте CClfsBaseFilePersisted.

1667871802798.png


Рисунок 17. Псевдокод функции ClfsBaseFilePersisted::WriteMetadataBlock​

Наконец, точка останова на CLFS!CClfsBaseFilePersisted::RemoveContainer может быть установлена для отслеживания момента разыменования поврежденного указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT в Base Record.

На рисунке 18 показан псевдокод функции CClfsBaseFilePersisted::RemoveContainer.

1667871869911.png


Рисунок 18.Псевдокод функции CClfsBaseFilePersisted::RemoveContainer​

В функции CClfsBaseFilePersisted::RemoveContainer выполняются следующие шаги.

Получает смещение контекста контейнера по смещению 0x398 в Base Record.
Вызывает CClfsBaseFile::GetSymbol для получения указателя на структуру CLFS_CONTAINER_CONTEXT и сохраняет его в 4-м параметре.
Присваивает значение указателя на объект CClfsContainter в структуре CLFS_CONTAINER_CONTEXT, полученной на шаге 2, локальной переменной v13.
Обнуляет указатель на объект CClfsContainter в структуре CLFS_CONTAINER_CONTEXT.
Поочередно вызывает CClfsContainer::Remove и CClfsContainer::Release для удаления связанного с контейнером файла журнала и освобождения объекта CClfsContainer.

Разыменование поврежденного указателя на объект CClfsContainter приводит к нарушению памяти. На рисунке 19 показана информация о сбое в WinDbg, в результате чего происходит сбой BSOD.

1667871946204.png


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

Как описано на рисунке 14, в функции CClfsBaseFilePersisted::AllocSymbol произошла несвязанная запись. Перед вызовом функции memset проверка поля cbSymbolZone была обойдена из-за того, что поле SignaturesOffset в памяти было перезаписано значением 0xFFFF0050. Поле SignaturesOffset в памяти базового блока может быть перезаписано на 0xFFFF0050 в процессе обработки запроса вызова API CreateLogFile для открытия специально созданного базового файла журнала MyLog.blf, описанного в шаге 3 на рисунке 9.
Когда функция CreateLogFile вызывается в пространстве пользователя, CLFS!CClfsRequest::Create отвечает за обработку этого запроса. Когда функция CreateLogFile используется для открытия существующего base log file, в CLFS.sys вызывается функция CClfsLogFcbPhysical::Initialize. На рисунке 20 показан фрагмент псевдокода функции CClfsLogFcbPhysical::Initialize.

1667872038741.png


Рисунок 20. Фрагмент псевдокода функции CClfsLogFcbPhysical::Initialize​

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

1. Вызвать функцию CClfsBaseFilePersisted::OpenImage для создания bigpool (размер: 0x7a00) для базы блока в базовом файле журнала. Для входа в функцию CClfsBaseFilePersisted::ReadMetadataBlock можно выполнить следующие вызовы функций.


Код:
CClfsBaseFilePersisted::OpenImage -> CClfsBaseFilePersisted::ReadImage -> CClfsBaseFile::AcquireMetadataBlock -> CClfsBaseFilePersisted::ReadMetadataBlock

На рисунке 21 показан фрагмент псевдокода функции CClfsBaseFilePersisted::ReadMetadataBlock, где вызывается ExAllocatePoolWithTag(PagedPoolCacheAligned, 0x7a00, 0x73666C43u) для создания bigpool для хранения базового блока, затем следует инициализация, а затем вызывается функция ClfsDecodeBlock для декодирования блока. В функции ClfsDecodeBlock вызывается функция ClfsDecodeBlockPrivate для разбора массива сигнатур секторов, расположенного по смещению 0x50 (значение SignaturesOffset) в базовом блоке. Для перезаписи подписи сектора каждого сектора требуется два байта. Эти два байта 0x0050 по смещению 0x68 в базовом блоке могут быть перезаписаны по смещению 0x19FE (0xC*0x200+0x1FE), где хранится подпись сектора 13-й секции. В этот момент мы можем установить две точки останова записи в память, расположенные по адресам base_block+0x68 и base_block+0x200*0xE-0x8. Цель установки этих двух точек останова записи в память - отследить момент перезаписи подписи сектора 14-го раздела в базовом блоке, а поле SignaturesOffset в базовом блоке переписать в 0xFFFF0050.


Код:
    1: kd> ba w8 ffffd08b`51c03000+0x68 //base_block+0x68

    1: kd> ba w8 ffffd08b`51c03000+0x200*0xE-0x8 //базовый_блок+0x200*0xe-0x8

1667872200813.png


Рисунок 21. Фрагмент псевдокода функции CClfsBaseFilePersisted::ReadMetadataBlock​

2. Вызов функции CClfsBaseFile::AcquireClientContext для получения клиентского контекста из базового блока. Как показано на рисунке 7, первое смещение в массиве смещений клиентского контекста, расположенное по адресу 0x9A8 в blf-файле, является специально созданным. Поддельный клиентский контекст расположен по смещению 0x23A0 в base log file. Поле eState, расположенное по смещению 0x78 в структуре поддельного Контекста клиента, установлено в 0x20 (CLFS_LOG_SHUTDOWN).

3. Проверьте, не является ли поле eState значением CLFS_LOG_SHUTDOWN или базовый журнал является мультиплексированным журналом.

4. Вызовите функцию CClfsLogFcbPhysical::ResetLog, так как условие было ложным на шаге 3. На рисунке 22 показан фрагмент псевдокода функции CClfsLogFcbPhysical::ResetLog. 8 байт, расположенные по адресу base_block+0x1BF8, установлены в 0xFFFFFFFF000000. Подпись сектора расположена по смещению base_block+0x1BFC. Поэтому сигнатура сектора перезаписывается на 0xFFFFFF. На рисунке 23 показано, что подпись сектора перезаписана в WinDbg.

1667872530223.png


Рисунок 22. Фрагмент псевдокода функции CClfsLogFcbPhysical::ResetLo​

1667872613928.png


Рисунок 23. Подпись сектора перезаписана 0xFFFF​

5. Вызовите функцию CClfsLogFcbPhysical::FlushMetaData. Для входа в функцию CLFS!ClfsEncodeBlockPrivate можно выполнить следующие вызовы функций.


Код:
  CLFS!CClfsLogFcbPhysical::FlushMetadata -> CLFS!CClfsBaseFilePersisted::FlushImage -> CLFS!CClfsBaseFilePersisted::WriteMetadataBlock -> CLFS!ClfsEncodeBlock -> CLFS!ClfsEncodeBlockPrivate

На рисунке 24 показан фрагмент псевдокода функции CLFS!ClfsEncodeBlockPrivate.

1667872723782.png


Приведенный выше код получает сигнатуру сектора из каждого сектора базового блока и перезаписывает массив сигнатур сектора сигнатурой сектора. Массив сигнатур секторов расположен по смещению 0x50 и перекрывает поле SignaturesOffset в базовом блоке. Подпись сектора 14-го сектора была установлена в 0xFFFF, как показано на рисунке 23. Поэтому два байта (0xFFFF) перезаписываются по смещению 0x6C (0x50+0xE*2) в базовом блоке. В это время поле SignaturesOffset имеет значение 0xFFFF0050, как показано на рисунке 25.

1667872787404.png


Рисунок 25. Поле SignaturesOffset перезаписано значением 0xFFFF0050​

В конце мы обобщаем процесс перезаписи поля SignaturesOffset на рисунке 26.

1667872831107.png


Рисунок 26. Процесс перезаписи поля SignaturesOffset​


Заключение

В этом блоге ThreatLabz представила подробный анализ первопричины CVE-2022-37969, которая связана с неправильной проверкой границ поля SignaturesOffset в Base Block для базового файла журнала (BLF) в CLFS.sys. Специально созданный массив клиентских контекстов и поддельный клиентский контекст в base log file могут использовать CLFS для перезаписи поля SignaturesOffset ненормальным значением. Это приводит к обходу проверки для поля cbSymbolZone при выделении символа. Таким образом, недействительное поле cbSymbolZone может привести к ООВ - записи по произвольному смещению. Поэтому указатель на объект CClfsContainer может быть поврежден. При разыменовании поврежденный указатель на объект CClfsContainer вызывает нарушение памяти, которое приводит к аварийному завершению работы BSOD. Во второй части мы представим анализ эксплойта 0-day, использующего эту уязвимость для повышения привилегий. Оставайтесь с нами!

Всем пользователям Windows рекомендуется обновить систему до последней версии. Решения Advanced Threat Protection и Advanced Cloud Sandbox от Zscaler могут защитить клиентов от эксплойта 0-day, использующего уязвимость CVE-2022-37969.

Win32.GenExploit.LogFile
Win32.Exploit.CVE-2022-37969
1667872982106.png


Ссылки


https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-37969
https://github.com/ionescu007/clfs-docs/blob/main/README.md
https://i.blackhat.com/USA-22/Thursday/us-22-Jin-The-Journey-Of-Hunting-ITW-Windows-LPE-0day.pdf
https://www.slideshare.net/PeterHlavaty/deathnote-of-microsoft-windows-kernel
https://www.pixiepointsecurity.com/blog/nday-cve-2022-24521.html
https://blog.exodusintel.com/2022/03/10/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs/
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/clfs/common-log-file-system-portal
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/clfs/log-types
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/clfs/creating-a-log-file
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-the-common-log-file-system
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/clfs-terminology
 
Последнее редактирование:
ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия ноды ETHEREUM и тестов

Технический анализ уязвимости нулевого дня Windows CLFS CVE-2022-37969 — часть 2: анализ эксплойтов​

Отладочная среда

Анализ и отладка для эксплуатации проводились в следующей среде.
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.

1667896289417.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 в ядре.

1667896394029.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.

1667896826103.png


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

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

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

1667896964063.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 для реализации примитива произвольной записи.

1667897109168.png


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

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

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

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

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

1667897186173.png


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

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

1667897240804.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.

1667897335374.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.

1667897458818.png


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

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

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

1667897553980.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.

1667897624361.png



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

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

1667897732215.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.

1667897956351.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 показан процесс распыления кучи.

1667898268316.png

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

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

1667898312169.png


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


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

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

1667898386292.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 в ядре.

1667898610061.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.

1667898758824.png


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

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

1667898812606.png


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

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

1667898861249.png


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

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

1667898947832.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.

1667899066645.png


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

0x07 Замена Token

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

1667899164160.png


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

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

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

1667899237223.png


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

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

1667899331682.png


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

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

1667899385007.png


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

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

1667899450454.png


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

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

1667899524786.png


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

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

1667899580700.png


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

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

1667899622101.png


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

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

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

1667899690086.png



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

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

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

1667900063311.png


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

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

1667900111834.png


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

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

1667900185942.png


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

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

1667900285098.png


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

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

1667900360817.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).


1667900460761.png


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

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

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

1667900540800.png


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

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

1667900587949.png



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


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

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

1667900633822.png


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

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

1667900770319.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.

1667900820449.png


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

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

1667900872996.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.


Благодарности

Особая благодарность Нирмалу Сингху из команды Zscaler ThreatLabz за получение этого образца эксплойта 0-дня и проведение первоначального анализа!

Устранение последствий
Всем пользователям Windows рекомендуется обновить систему до последней версии. Решения Advanced Threat Protection и Advanced Cloud Sandbox компании Zscaler могут защитить клиентов от эксплойта 0-day CVE-2022-37969.


Win32.GenExploit.LogFile

Win32.Exploit.CVE-2022-37969


Обнаружение в облачной песочнице
1667901130125.png



Ссылочки​


https://www.zscaler.com/blogs/secur...fs-zero-day-vulnerability-cve-2022-37969-part
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/eprocess
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/previousmode
https://www.sstic.org/media/SSTIC2020/SSTIC-actes/pool_overflow_exploitation_since_windows_10_19h1/SSTIC2020-Article-pool_overflow_exploitation_since_windows_10_19h1-bayet_fariello.pdf
https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation
https://www.gaijin.at/en/infos/windows-version-numbers
https://www.lifewire.com/windows-version-numbers-2625171
https://research.nccgroup.com/2021/08/17/cve-2021-31956-exploiting-the-windows-kernel-ntfs-with-wnf-part-2/
https://research.nccgroup.com/2020/05/25/cve-2018-8611-exploiting-windows-ktm-part-5-5-vulnerability-detection-and-a-better-read-write-primitive/#previousmode---a-god-mode-primitive
https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2022/CVE-2022-24521.html
https://blog.exodusintel.com/2022/03/10/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs/
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-37969
https://github.com/ionescu007/clfs-docs/blob/main/README.md
http://blog.rewolf.pl/blog/?p=1683
 
Ребята, вавилонец yashechka (или возможно, кто-то еще захочет взяться и перевести). Давайте переведем на русский?
Не успел )) Только зашел.
 
Не успел )) Только зашел.
состояние гонки / Wiki / это когда увидел тоже самое подумал
 
ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия ноды ETHEREUM и тестов

Технический анализ уязвимости нулевого дня Windows CLFS CVE-2022-37969 — часть 2: анализ эксплойтов​

Отладочная среда

Анализ и отладка для эксплуатации проводились в следующей среде.

Предпосылка

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

Посмотреть вложение 45377

Рисунок 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 в ядре.

Посмотреть вложение 45378

Рисунок 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.

Посмотреть вложение 45379

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

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

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

Посмотреть вложение 45380

Рисунок 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 для реализации примитива произвольной записи.

Посмотреть вложение 45381

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

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

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

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

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

Посмотреть вложение 45382

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

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

Посмотреть вложение 45383

Рисунок 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.

Посмотреть вложение 45384

Рисунок 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.

Посмотреть вложение 45385

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

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

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

Посмотреть вложение 45386

Рисунок 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.

Посмотреть вложение 45388


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

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

Посмотреть вложение 45389

Рисунок 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.

Посмотреть вложение 45390

Рисунок 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 показан процесс распыления кучи.

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

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

Посмотреть вложение 45392

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


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

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

Посмотреть вложение 45393

Рисунок 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 в ядре.

Посмотреть вложение 45394

Рисунок 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.

Посмотреть вложение 45395

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

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

Посмотреть вложение 45396

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

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

Посмотреть вложение 45397

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

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

Посмотреть вложение 45398

Рисунок 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.

Посмотреть вложение 45399

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

0x07 Замена Token

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

Посмотреть вложение 45400

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

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

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

Посмотреть вложение 45401

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

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

Посмотреть вложение 45402

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

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

Посмотреть вложение 45403

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

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

Посмотреть вложение 45404

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

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

Посмотреть вложение 45405

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

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

Посмотреть вложение 45406

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

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

Посмотреть вложение 45407

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

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

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

Посмотреть вложение 45408


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

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

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

Посмотреть вложение 45409

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

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

Посмотреть вложение 45410

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

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

Посмотреть вложение 45411

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

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

Посмотреть вложение 45412

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

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

Посмотреть вложение 45413

Рисунок 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).


Посмотреть вложение 45414

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

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

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

Посмотреть вложение 45415

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

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

Посмотреть вложение 45416


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


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

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

Посмотреть вложение 45417

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

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

Посмотреть вложение 45418

Рисунок 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.

Посмотреть вложение 45419

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

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

Посмотреть вложение 45420


Рисунок 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.


Благодарности

Особая благодарность Нирмалу Сингху из команды Zscaler ThreatLabz за получение этого образца эксплойта 0-дня и проведение первоначального анализа!

Устранение последствий
Всем пользователям Windows рекомендуется обновить систему до последней версии. Решения Advanced Threat Protection и Advanced Cloud Sandbox компании Zscaler могут защитить клиентов от эксплойта 0-day CVE-2022-37969.


Win32.GenExploit.LogFile

Win32.Exploit.CVE-2022-37969


Обнаружение в облачной песочнице
Посмотреть вложение 45421


Ссылочки​


https://www.zscaler.com/blogs/secur...fs-zero-day-vulnerability-cve-2022-37969-part
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/eprocess
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/previousmode
https://www.sstic.org/media/SSTIC2020/SSTIC-actes/pool_overflow_exploitation_since_windows_10_19h1/SSTIC2020-Article-pool_overflow_exploitation_since_windows_10_19h1-bayet_fariello.pdf
https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation
https://www.gaijin.at/en/infos/windows-version-numbers
https://www.lifewire.com/windows-version-numbers-2625171
https://research.nccgroup.com/2021/08/17/cve-2021-31956-exploiting-the-windows-kernel-ntfs-with-wnf-part-2/
https://research.nccgroup.com/2020/05/25/cve-2018-8611-exploiting-windows-ktm-part-5-5-vulnerability-detection-and-a-better-read-write-primitive/#previousmode---a-god-mode-primitive
https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2022/CVE-2022-24521.html
https://blog.exodusintel.com/2022/03/10/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs/
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-37969
https://github.com/ionescu007/clfs-docs/blob/main/README.md
http://blog.rewolf.pl/blog/?p=1683
Имхо, будет красивее выложить в виде отдельной статьи, вместо поста.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх