Всем привет!
На xss.is нашёл классный перевод:
Но к сожалению там не оформили как статью, поэтому надёюсь никто не против, если я перенесу этот интересный материал сюда.
2 сентября 2022 г. компания Zscaler Threatlabz зафиксировала эксплойт нулевого дня в общем системном драйвере файлов журнала Windows (CLFS.sys) и сообщила об этом обнаружении в Microsoft. В сентябрьском
Злоумышленник, успешно воспользовавшийся этой уязвимостью, может получить системные привилегии. Эксплойт 0-day может успешно выполнить повышение привилегий в Windows 10 и Windows 11 до сентябрьского исправления.
Причина уязвимости связана с отсутствием строгой проверки границ поля SignaturesOffset в базовом блоке blf-файла журнала (BLF) в CLFS.sys. Специально созданный массив клиентского контекста и фальшивый клиентский контекст в базовом файле журнала могут использовать CLFS для перезаписи поля SignaturesOffset ненормальным значением. Это приводит к обходу проверки поля cbSymbolZone при выделении символа. Таким образом, недопустимое поле cbSymbolZone может привести к записи вне границ с произвольным смещением. В этой серии блогов, состоящей из двух частей, мы демистифицируем уязвимость и эксплойт нулевого дня, обнаруженный в дикой природе. Блоги состоят из двух частей: анализа основной причины и анализа эксплойта. В этом блоге мы впервые представляем подробный анализ основной причины CVE-2022-37969.
Отладочная среда
Весь анализ и отладка в этой серии блогов, состоящей из двух частей, проводились в следующей среде:
Common Log File System (CLFS) — это подсистема ведения журналов общего назначения, которая может использоваться приложениями, работающими как в режиме ядра, так и в пользовательском режиме, для создания высокопроизводительных журналов транзакций и реализована в драйвере CLFS.sys. Общая файловая система журналов создает журналы транзакций в базовом файле журнала (BLF). Введение в понятия и терминологию для CLFS указано в
Перед использованием CLFS файл журнала создается с помощью
Рисунок 1 иллюстрирует формат BLF на основе
Рис. 1. Формат базового файла журнала (BLF)
Blf-файл состоит из шести различных блоков метаданных: Control Block, Base Block и Truncate Block, а также соответствующих им shadow block. В этих блоках могут находиться три типа записей (Control Record, Base Record и Truncate Record). Этот блог посвящен только базовой записи, которая имеет отношение к данной уязвимости. Базовая запись включает в себя символьные таблицы, которые хранят информацию о контекстах клиента, контекстах контейнера и контекстах безопасности, связанных с базовым файлом журнала.
Каждый блок журнала начинается с заголовка блока журнала, структура которого определена ниже:
Схема памяти структуры CLFS_LOG_BLOCK_HEADER, размер которой составляет 0x70 байт, показана на рисунке 1. Поле SignaturesOffset - это смещение массива в памяти, который используется для хранения всех подписей секторов. Массив должен располагаться на последнем секторе каждого блока. Сигнатура сектора располагается в конце каждого сектора (размер: 0x200) и состоит из типа Sector Block Type (1 байт) и Usn (1 байт). Ниже перечислены типы сектора.
На рисунке 1 base block начинается по смещению 0x800 и заканчивается по смещению 0x71FF в файле .BLF и начинается с заголовка Log Block Header (0x70 байт), за которым следует заголовок Base Record Header, а затем записи. Заголовок Base Record Header может быть представлен структурой CLFS_BASE_RECORD_HEADER, описанной на рисунке 2.
Рисунок 2. Определение структуры CLFS_BASE_RECORD_HEADER
Схема структуры CLFS_BASE_RECORD_HEADER показана на рисунке 3
Рисунок 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, определенная ниже:
Схема памяти структуры CLFSHASHSYM показана на рисунке 4, далее следуют различные объекты контекста.
Рисунок 4. Структура CLFSHASHSYM (символично)
В Base Record клиентский контекст используется для идентификации клиента для файла журнала. В Base Log File может быть создан как минимум один Client Context. Client Context представлен структурой CLFS_CLIENT_CONTEXT, определенной ниже:
В Base Record контекст контейнера связан с добавлением файла контейнера для base log file, который представлен структурой CLFS_CONTAINER_CONTEXT, определенной ниже:
Поле pContainer является указателем на объект в адресном пространстве ядра CClfsContainer, представляющий контейнер во время выполнения, который находится по смещению 0x18 в структуре CLFS_CONTAINER_CONTEXT. На рисунке 5 показана схема памяти структуры CLFS_CONTAINER_CONTEXT.
Рисунок 5. Схема памяти структуры CLFS_CONTAINER_CONTEXT
Чтобы определить первопричину CVE-2022-37969, ThreatLabz разработала Proof-of-Concept (PoC), который стабильно вызывает сбой "синего экрана смерти" (BSOD). На рисунке 6 показана подробная информация о сбое после срабатывания уязвимости.
Рисунок 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.
Рисунок 7. Специально созданный файл Base Log File (BLF) для CVE-2022-37969
После создания этого bfl-файла определенные байты, включая поле SignatureOffset, массив смещений клиентского контекста, cbSymbol, фальшивый клиентский контекст и т.д., должны быть соответствующим образом изменены. Как показано на рисунке 7, все измененные байты находятся в записи Base Log Record (смещение: 0x800 ~ 0x81FF в файле .blf). Модификации файла .blf перечислены на рисунке 8.
Рисунок 8. Модификации файла .BLF для запуска CVE-2022-37969
Код Proof-of-Concept для запуска CVE-2022-37969 показан на рисунке 9.
Рисунок 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() в пространстве пользователя. Для отслеживания процесса обработки этого запроса можно установить следующую точку останова.
В CLFS.sys класс CClfsRequest отвечает за обработку запросов из пространства пользователя. Функция CClfsRequest::AllocContainer используется для обработки запроса на добавление контейнера в физический журнал. Функция CClfsRequest::AllocContainer вызывает CClfsLogFcbPhysical::AllocContainer, объявление которого показано ниже:
Далее точка останова на CClfsLogFcbPhysical::AllocContainer устанавливается следующим образом:
На шаге 5, когда код вызывает функцию AddLogContainer, срабатывает точка останова на CClfsLogFcbPhysical::AllocContainer. Когда точка останова достигнута, давайте проверим указатель this класса CClfsLogFcbPhysical. Тhis указывает на объект CClfsLogFcbPhysical. Как показано на рисунке 10, в регистре rcx хранится указатель this класса CClfsLogFcbPhysical.
Рисунок 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.
Рисунок 11. Структура CLFS_CONTAINER_CONTEXT после успешного добавления контейнера
По смещению 0x1C0 в объекте CClfsBaseFilePersisted хранится указатель на объект CClfsContainer, который берется из поля pContainer в структуре CLFS_CONTAINER_CONTEXT. В этот момент можно установить точку останова записи в память по адресу CLFS_CONTAINER_CONTEXT+0x18, чтобы отследить, когда указатель на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT будет поврежден. Еще одна точка останова записи в память по смещению 0x1C0 в объекте CClfsBaseFilePersisted может быть установлена следующим образом:
На шаге 7, когда код вызывает функцию AddLogContainer, точки останова на CLFS!CClfsRequest::AllocContainer и CLFS!CClfsLogFcbPhysical::AllocContainer снова сбиваются. В этот момент давайте проверим указатель this (см. рисунок 12) класса CClfsLogFcbPhysical. Стоит отметить, что поле SignaturesOffset, которое изначально было установлено в 0x00000050 в созданном файле MyLog.blf, в памяти было установлено в 0xFFFF0050.
Рисунок 12. Проверка указателя this для класса CClfsLogFcbPhysical
В WinDbg продолжим выполнение кода. Точка останова записи в память "ba w8 ffffc80c`cc86a4f0" будет достигнута, и структура CLFS_CONTAINER_CONTEXT в base Record производит out-of-bound запись, что приводит к повреждению указателя в объекте CClfsContainer, показанном на рисунке 13.
Рисунок 13. Повреждение указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT
Исходя из приведенной выше обратной трассировки стека вызовов, функция memset была вызвана, чтобы вызвать точку останова записи в память в функции CClfsBaseFilePersisted::AllocSymbol. На рисунке 14 показан псевдокод функции CClfsBaseFilePersisted::AllocSymbol.
Рисунок 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.
Рисунок 15. Объяснение несанкционированной записи, вызванной CVE-2022-37969
Итак, мы обсудили, почему произошла запись вне границ и как был поврежден указатель на объект CClfsContainer в структуре CLFS_CONTAINER_CONEXT. Далее рассмотрим, когда произойдет разыменование поврежденного указателя CClfsContainer. После этого мы вернемся к выяснению того, почему поле SignaturesOffset в памяти установлено в 0xFFFF0050 из 0x00000050.
Когда в пространстве пользователя вызывается функция CloseHandle, за обработку этого запроса отвечает CClfsRequest::Close(PIRP Irp). В ядре еще одна точка останова памяти (0x1c0+CClfsBaseFilePersisted) достигается в функции ClfsBaseFilePersisted::WriteMetadataBlock, как показано на рисунке 16.
Рисунок 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.
Рисунок 17. Псевдокод функции ClfsBaseFilePersisted::WriteMetadataBlock
Наконец, точка останова на CLFS!CClfsBaseFilePersisted::RemoveContainer может быть установлена для отслеживания момента разыменования поврежденного указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT в Base Record.
На рисунке 18 показан псевдокод функции CClfsBaseFilePersisted::RemoveContainer.
Рисунок 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.
Рисунок 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.
Рисунок 20. Фрагмент псевдокода функции CClfsLogFcbPhysical::Initialize
Эта функция описывается следующим образом:
1. Вызвать функцию CClfsBaseFilePersisted::OpenImage для создания bigpool (размер: 0x7a00) для базы блока в базовом файле журнала. Для входа в функцию 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.
Рисунок 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.
Рисунок 22. Фрагмент псевдокода функции CClfsLogFcbPhysical::ResetLo
Рисунок 23. Подпись сектора перезаписана 0xFFFF
5. Вызовите функцию CClfsLogFcbPhysical::FlushMetaData. Для входа в функцию CLFS!ClfsEncodeBlockPrivate можно выполнить следующие вызовы функций.
На рисунке 24 показан фрагмент псевдокода функции CLFS!ClfsEncodeBlockPrivate.
Приведенный выше код получает сигнатуру сектора из каждого сектора базового блока и перезаписывает массив сигнатур сектора сигнатурой сектора. Массив сигнатур секторов расположен по смещению 0x50 и перекрывает поле SignaturesOffset в базовом блоке. Подпись сектора 14-го сектора была установлена в 0xFFFF, как показано на рисунке 23. Поэтому два байта (0xFFFF) перезаписываются по смещению 0x6C (0x50+0xE*2) в базовом блоке. В это время поле SignaturesOffset имеет значение 0xFFFF0050, как показано на рисунке 25.
Рисунок 25. Поле SignaturesOffset перезаписано значением 0xFFFF0050
В конце мы обобщаем процесс перезаписи поля SignaturesOffset на рисунке 26.
Рисунок 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
!КТО ПРОЧИТАЛ, СНИМАЮ ШЛЯПУ!
СЕЙЧАС ВЫЛОЖУ ВТОРУЮ ЧАСТЬ
На xss.is нашёл классный перевод:
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
Но к сожалению там не оформили как статью, поэтому надёюсь никто не против, если я перенесу этот интересный материал сюда.
2 сентября 2022 г. компания Zscaler Threatlabz зафиксировала эксплойт нулевого дня в общем системном драйвере файлов журнала Windows (CLFS.sys) и сообщила об этом обнаружении в Microsoft. В сентябрьском
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
, Microsoft исправила эту уязвимость, идентифицированную как
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
, которая представляет собой уязвимость повышения привилегий драйвера общей файловой системы 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
Common Log File System (CLFS) — это подсистема ведения журналов общего назначения, которая может использоваться приложениями, работающими как в режиме ядра, так и в пользовательском режиме, для создания высокопроизводительных журналов транзакций и реализована в драйвере CLFS.sys. Общая файловая система журналов создает журналы транзакций в базовом файле журнала (BLF). Введение в понятия и терминологию для CLFS указано в
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
Microsoft.Перед использованием CLFS файл журнала создается с помощью
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
. Файл журнала состоит из blf-файла, состоящего из блоков метаданных, и нескольких контейнеров, в которых хранятся фактические данные. API
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
используется для добавления контейнера в физический журнал, связанный с дескриптором журнала.Рисунок 1 иллюстрирует формат BLF на основе
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
Алекса Ионеску
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
.Рис. 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.
Рисунок 2. Определение структуры CLFS_BASE_RECORD_HEADER
Схема структуры CLFS_BASE_RECORD_HEADER показана на рисунке 3
Рисунок 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, далее следуют различные объекты контекста.
Рисунок 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.
Рисунок 5. Схема памяти структуры CLFS_CONTAINER_CONTEXT
Чтобы определить первопричину CVE-2022-37969, ThreatLabz разработала Proof-of-Concept (PoC), который стабильно вызывает сбой "синего экрана смерти" (BSOD). На рисунке 6 показана подробная информация о сбое после срабатывания уязвимости.
Рисунок 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.
Рисунок 7. Специально созданный файл Base Log File (BLF) для CVE-2022-37969
После создания этого bfl-файла определенные байты, включая поле SignatureOffset, массив смещений клиентского контекста, cbSymbol, фальшивый клиентский контекст и т.д., должны быть соответствующим образом изменены. Как показано на рисунке 7, все измененные байты находятся в записи Base Log Record (смещение: 0x800 ~ 0x81FF в файле .blf). Модификации файла .blf перечислены на рисунке 8.
Рисунок 8. Модификации файла .BLF для запуска CVE-2022-37969
Код Proof-of-Concept для запуска CVE-2022-37969 показан на рисунке 9.
Рисунок 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.
Рисунок 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.
Рисунок 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.
Рисунок 12. Проверка указателя this для класса CClfsLogFcbPhysical
В WinDbg продолжим выполнение кода. Точка останова записи в память "ba w8 ffffc80c`cc86a4f0" будет достигнута, и структура CLFS_CONTAINER_CONTEXT в base Record производит out-of-bound запись, что приводит к повреждению указателя в объекте CClfsContainer, показанном на рисунке 13.
Рисунок 13. Повреждение указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT
Исходя из приведенной выше обратной трассировки стека вызовов, функция memset была вызвана, чтобы вызвать точку останова записи в память в функции CClfsBaseFilePersisted::AllocSymbol. На рисунке 14 показан псевдокод функции CClfsBaseFilePersisted::AllocSymbol.
Рисунок 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.
Рисунок 15. Объяснение несанкционированной записи, вызванной CVE-2022-37969
Итак, мы обсудили, почему произошла запись вне границ и как был поврежден указатель на объект CClfsContainer в структуре CLFS_CONTAINER_CONEXT. Далее рассмотрим, когда произойдет разыменование поврежденного указателя CClfsContainer. После этого мы вернемся к выяснению того, почему поле SignaturesOffset в памяти установлено в 0xFFFF0050 из 0x00000050.
Когда в пространстве пользователя вызывается функция CloseHandle, за обработку этого запроса отвечает CClfsRequest::Close(PIRP Irp). В ядре еще одна точка останова памяти (0x1c0+CClfsBaseFilePersisted) достигается в функции ClfsBaseFilePersisted::WriteMetadataBlock, как показано на рисунке 16.
Рисунок 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.
Рисунок 17. Псевдокод функции ClfsBaseFilePersisted::WriteMetadataBlock
Наконец, точка останова на CLFS!CClfsBaseFilePersisted::RemoveContainer может быть установлена для отслеживания момента разыменования поврежденного указателя на объект CClfsContainer в структуре CLFS_CONTAINER_CONTEXT в Base Record.
На рисунке 18 показан псевдокод функции CClfsBaseFilePersisted::RemoveContainer.
Рисунок 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.
Рисунок 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.
Рисунок 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
Рисунок 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.
Рисунок 22. Фрагмент псевдокода функции CClfsLogFcbPhysical::ResetLo
Рисунок 23. Подпись сектора перезаписана 0xFFFF
5. Вызовите функцию CClfsLogFcbPhysical::FlushMetaData. Для входа в функцию CLFS!ClfsEncodeBlockPrivate можно выполнить следующие вызовы функций.
Код:
CLFS!CClfsLogFcbPhysical::FlushMetadata -> CLFS!CClfsBaseFilePersisted::FlushImage -> CLFS!CClfsBaseFilePersisted::WriteMetadataBlock -> CLFS!ClfsEncodeBlock -> CLFS!ClfsEncodeBlockPrivate
На рисунке 24 показан фрагмент псевдокода функции CLFS!ClfsEncodeBlockPrivate.
Приведенный выше код получает сигнатуру сектора из каждого сектора базового блока и перезаписывает массив сигнатур сектора сигнатурой сектора. Массив сигнатур секторов расположен по смещению 0x50 и перекрывает поле SignaturesOffset в базовом блоке. Подпись сектора 14-го сектора была установлена в 0xFFFF, как показано на рисунке 23. Поэтому два байта (0xFFFF) перезаписываются по смещению 0x6C (0x50+0xE*2) в базовом блоке. В это время поле SignaturesOffset имеет значение 0xFFFF0050, как показано на рисунке 25.
Рисунок 25. Поле SignaturesOffset перезаписано значением 0xFFFF0050
В конце мы обобщаем процесс перезаписи поля SignaturesOffset на рисунке 26.
Рисунок 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
!КТО ПРОЧИТАЛ, СНИМАЮ ШЛЯПУ!
СЕЙЧАС ВЫЛОЖУ ВТОРУЮ ЧАСТЬ
Последнее редактирование: