Исследование

Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков

В апреле 2023 года мы выпустили статью об эксплойте нулевого дня, который мы обнаружили в атаках с использованием шифровальщиков. Уязвимость CVE-2023-28252 используемая этим эксплойтом была закрыта компанией Microsoft после нашего оперативного уведомления.

В той статье мы отметили, что обнаруженный эксплойт нулевого дня сильно напоминал другие эксплойты Microsoft Windows для повышения привилегий, с которыми мы сталкивались в других кампаниях шифровальщиков в течение года. Мы установили, что с июня 2022 года злоумышленники активно использовали эксплойты, затрагивающие не менее пяти уязвимостей драйвера файловой системы CLFS. Четыре из них (CVE-2022-24521, CVE-2022-37969, CVE-2023-23376 и CVE-2023-28252) были обнаружены «в дикой природе» и являлись эксплойтами нулевого дня.

Сейчас уже нет ничего удивительного в атаках на основе уязвимостей нулевого дня в драйвере Win32k. Недостатки проектирования этого компонента хорошо известны и злоумышленники эксплуатируют их раз за разом. Однако никогда прежде мы не наблюдали, чтобы атаки через уязвимости драйвера CLFS шли одна за другой в течение одного года.

Что-то серьезно не так с драйвером CLFS? Похожи ли все эти уязвимости между собой? Была ли Microsoft небрежна в исправлении этих уязвимостей? Эти вопросы пробудили мой интерес и побудили меня подробно изучить драйвер CLFS и его уязвимости.

Исследование получилось довольно объемным, поэтому, для удобства читателя, оно разделено на шесть частей.

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

Вы можете перейти к нужному разделу из содержания или по ссылкам в конце этой части.

Устройство файловой системы CLFS

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

CLFS (Common Log File System) — это универсальная файловая подсистема ведения журналов. Она используется операционной системой и может использоваться любыми другими приложениями, которым необходима быстрая запись данных и/или событий в журнал. Для этого компания Microsoft опубликовала документацию для API режима ядра и пользовательского режима. Впервые эта файловая система появилась в Windows Server 2003 R2 и Windows Vista, и реализуется посредством драйвера clfs.sys.

Журналы создаются и открываются функцией API CreateLogFile. Они состоят из специального мастер-файла с метаданными (с названием Base Log File и расширением .blf) и неограниченного количества контейнеров для хранения фактических данных. Контейнеры создаются с помощью функций API AddLogContainer и AddLogContainerSet.

Как нетрудно догадаться, ключевую роль при работе с журналами играет файл BLF с метаданными. Компания Microsoft не предоставляет документацию к этому формату. Предполагается, что все операции с ним должны выполняться посредством предоставленного API. Но учитывая несложную структуру этого формата и тот факт, что Microsoft предоставляет отладочные символы для clfs.sys, обратная разработка формата BLF была лишь вопросом времени. По этой ссылке вы можете найти подробное описание этого формата, составленное Алексом Ионеску.

И неудивительно, что Microsoft не предоставляет документацию на этот формат, ведь один лишь взгляд на него вызывает тревогу. Файлы BLF состоят из структур памяти ядра и даже имеют поля для хранения указателей памяти!

Выдержка из документации CLFS, намекающая на структуру файлов BLF

Выдержка из документации CLFS, намекающая на структуру файлов BLF

С одной стороны, Microsoft не афиширует эти особенности, с другой — упоминает о них прямым текстом в документации. Там сказано, что файловая система CLFS оптимизирована для высокой производительности, и вся работа выполняется в буферах, которые записываются на диск без копирования. Логично предположить, что считывание таких буферов с диска происходит аналогичным образом.

Файловая система CLFS была создана для решения сложных задач, и, следовательно, обладает сложной функциональностью. Кодовая база этой системы очень старая. Она разбирает файлы сомнительной структуры прямо в ядре. Весь код оптимизирован для достижения лучшей производительности. Мой опыт говорит о том, что код с такими характеристиками обычно содержит уязвимости.

И данный случай — не исключение. Поиск по запросу Windows Common Log File System Driver Elevation Of Privilege Vulnerability («уязвимость повышения привилегий в драйвере файловой системы CLFS Windows») на портале Security Update Guide показывает, что за период с 2018 года было исправлено более 30 таких уязвимостей, включая четыре упомянутые выше уязвимости нулевого дня, обнаруженных в реальных атаках.

А теперь рассмотрим подробнее файловый формат BLF. Документация Алекса Ионеску была очень полезна в проведении этого исследования, но для полного понимания первопричин уязвимостей мне пришлось создать свой собственный парсер CLFS и провести обратную разработку того же кода самостоятельно. Ниже я подробно расскажу о ключевых особенностях формата BLF, важных для понимания первопричин обсуждаемых уязвимостей и способов их эксплуатации.

Итак, основные факты об этом формате. Файлы BLF состоят из записей (records). Эти записи сохраняются в блоках. Запись и считывание блоков осуществляются сектор за сектором. Размер сектора составляет 0x200 байт. В последних двух байтах сектора хранится сигнатура сектора. Если последние два байта сектора заняты сигнатурой сектора, то где же хранятся оригинальные байты блока? В другом месте, указанном в виде относительного адреса в заголовке блока, но к этому мы вернемся чуть позже. Записи, в зависимости от типа, также могут содержать дополнительные структуры данных.

Каждый блок начинается с заголовка блока: CLFS_LOG_BLOCK_HEADER. Его формат представлен на иллюстрации ниже. Описание этой структуры в символах отладки отсутствует, поэтому во избежание путаницы, я использую имена полей из упомянутой выше документации.

Структура CLFS_LOG_BLOCK_HEADER

Структура CLFS_LOG_BLOCK_HEADER

Заголовок блока содержит информацию о количестве секторов, контрольную сумму данных блока и другие поля, которые для нас несущественны. Нам важны только два поля. Первое — это RecordOffsets, это поле представляет собой массив с относительными адресами записей. Формат позволяет блокам содержать много записей, однако в коде всегда используется только первый относительный адрес. Также нас интересует относительный адрес с именем SignaturesOffset. Он указывает на местоположение блока с оригинальными байтами — теми, которые были заменены упомянутыми выше сигнатурами секторов. Все вышеупомянутые относительные адреса представляют собой смещения относительно начальной позиции заголовка блока.

Файлы BLF состоят из шести блоков. Эти блоки имеют следующие имена (типы): CONTROL, CONTROL_SHADOW, GENERAL, GENERAL_SHADOW, SCRATCH и SCRATCH_SHADOW. При этом фактически используется не шесть разных типов, а всего три. Блоки SHADOW содержат предыдущий экземпляр записанных метаданных и помогают восстановить данные в случае прерывания записи.

На схеме ниже представлено расположение и размер блоков в только что созданном файле BLF.

Схема блоков в новом файле BLF

Схема блоков в новом файле BLF

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

А теперь обратимся к записям, которые хранятся в блоках. Записи, сохраняемые в блоках CONTROL, определяются структурой CLFS_CONTROL_RECORD; записи, сохраняемые в блоках GENERAL, определяются структурой CLFS_BASE_RECORD_HEADER; записи, сохраняемые в блоках SCRATCH, определяются структурой CLFS_TRUNCATE_RECORD_HEADER.

Все эти структуры записей начинаются со структуры CLFS_METADATA_RECORD_HEADER, которая представляет собой поле DumpCount.

Структура CLFS_METADATA_RECORD_HEADER

Структура CLFS_METADATA_RECORD_HEADER

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

Блок CONTROL находится в самом начале файла BLF, и структура CLFS_CONTROL_RECORD содержит информацию о расположении остальных блоков. Это позволяет CLFS увеличивать или уменьшать размер журнала.

Структура CLFS_CONTROL_RECORD

Структура CLFS_CONTROL_RECORD

Большинство полей в структуре CLFS_CONTROL_RECORD используются функцией изменения размера журнала, однако она содержит также поле rgBlocks, которое интересует нас в первую очередь. Это поле представляет собой массив структур CLFS_METADATA_BLOCK с информацией обо всех блоках, присутствующих в файле. Как видно из схемы выше, этот массив имеет произвольный размер, однако в действительности его размер жестко закодирован и равен шести (потому что в файле BLF шесть блоков). Каждая структура CLFS_METADATA_BLOCK содержит информацию о размере блока, его относительный адрес (смещение относительно начала файла) и плейсхолдер для сохранения указателя ядра на блок, когда он будет загружен в память.

Блок GENERAL содержит фактическую информацию, хранящуюся в файле BLF. Он содержит информацию о клиентах (использующих журнал), контейнерах (файлах с фактическими данными) и дескрипторах безопасности для контейнеров.

Структура CLFS_BASE_RECORD_HEADER

Структура CLFS_BASE_RECORD_HEADER

Структура CLFS_BASE_RECORD_HEADER довольно большая: она может занимать до 10 секторов. Это связано с тем, что она содержит пять больших массивов с относительными адресами. Информация о клиентах и контейнерах представлена в виде структур CLFS_CLIENT_CONTEXT и CLFS_CONTAINER_CONTEXT, которые хранятся в блоке GENERAL в виде символов. Что такое символ? Это сочетание структуры CLFSHASHSYM и непосредственно следующей за ней структуры CONTEXT. Такое решение позволяет коду быстро находить структуру CONTEXT посредством поиска по хешу. Массивы rgClientSymTbl, rgContainerSymTbl и rgSecuritySymTbl содержат относительные адреса на структуры CONTEXT в виде символов. Массивы rgClients и rgContainers содержат относительные адреса, указывающие на те же структуры CONTEXT, но напрямую, пропуская структуры CLFSHASHSYM. Драйвер CLFS использует все эти массивы, а разные функции задействуют разные методы доступа к структурам CLFS_CLIENT_CONTEXT и CLFS_CONTAINER_CONTEXT. Очевидно, это неудачное проектное решение, и далее мы рассмотрим его негативные последствия.

Также нас интересует поле cbSymbolZone. Поскольку во время выполнения работы журналу могут назначаться новые клиенты и контейнеры, код использует это поле для получения следующего свободного относительного адреса в блоке GENERAL, где можно создать новый символ. Эта зона для новых структур начинается непосредственно за структурой CLFS_BASE_RECORD_HEADER.

Все структуры, присутствующие в зоне символов (включая CLFSHASHSYM, CLFS_CLIENT_CONTEXT и CLFS_CONTAINER_CONTEXT), представлены в виде узлов (nodes). Все эти структуры начинаются с уникального магического числа, которое идентифицирует тип узла, а за ним следует размер структуры.

Структура CLFSHASHSYM

Структура CLFSHASHSYM

В связи с CLFSHASHSYM интересно то, что некоторые функции просто берут адрес структуры CONTEXT, вычитают из него 12 или 16 и работают с полями cbSymName и cbOffet структуры CLFSHASHSYM, просто исходя из предположения, что они должны там находиться.

Структура CLFS_CLIENT_CONTEXT

Структура CLFS_CLIENT_CONTEXT

Структура CLFS_CLIENT_CONTEXT содержит много полей, значительная часть которых понятна без объяснений. Для понимания первопричин уязвимостей, которые будут описаны ниже, нам наиболее интересны поля llCreateTime/llAccessTime/llWriteTime и fAttributes. Назначение первых трех очевидно, а поле fAttributes содержит FILE_ATTRIBUTE флаги, ассоциированные с файлом BLF.

Структура CLFS_CONTAINER_CONTEXT

Структура CLFS_CONTAINER_CONTEXT

Последняя из интересующих нас структур — это CLFS_CONTAINER_CONTEXT. Обратите внимание на поле pContainer. Это плейсхолдер для указателя ядра на класс CClfsContainer. Вероятно, стоит повторить: CLFS_CONTAINER_CONTEXT и все остальные упомянутые выше структуры считываются из сохраненных на диске файлов BLF. А значит, если злоумышленникам удастся внедрить вредоносную структуру CLFS_CONTAINER_CONTEXT в файл BLF и она будет обработана кодом без надлежащей проверки или инициализации, злоумышленники смогут перехватить поток управления и повысить свои привилегии с уровня пользователя до уровня ядра.

Критические недостатки файловой системы CLFS

Файловая система CLFS, пожалуй, слишком сильно «оптимизирована для высокой производительности». Было бы разумнее использовать более традиционный формат файла, а не записывать в файл дамп структур ядра. Вся работа с этими структурами ядра (с указателями) происходит прямо в блоках, считываемых с диска. Поскольку изменения вносятся в блоки и сохраненные в них структуры ядра, и эти изменения записываются на диск, то при каждом обращении к какому-то элементу код выполняет разбор блоков заново, начиная с CLFS_LOG_BLOCK_HEADER. Весь разбор осуществляется с использованием относительных адресов, которые могут указывать на любое место в блоке. Если один из таких относительных адресов оказывается поврежден в памяти во время выполнения, последствия могут быть катастрофическими, так как злоумышленники получают возможность предоставить вредоносную структуру CLFS_CONTAINER_CONTEXT. Но, пожалуй, хуже всего то, что путем манипуляций с относительными адресами в файле BLF на диске можно добиться наложения разных структур с непредвиденными последствиями. Все эти факторы создают множество уязвимостей, которые легко использовать.

Перейдите по ссылке, чтобы ознакомиться со следующей частью:

Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков

Ваш e-mail не будет опубликован. Обязательные поля помечены *

 

Отчеты

CloudSorcerer: новая APT-угроза, нацеленная на российские государственные организации

«Лаборатория Касперского» обнаружила новую APT-угрозу CloudSorcerer, нацеленную на российские государственные организации и использующую облачные службы в качестве командных серверов аналогично APT CloudWizard.

StripedFly: двуликий и незаметный

Разбираем фреймворк StripedFly для целевых атак, использовавший собственную версию эксплойта EternalBlue и успешно прикрывавшийся майнером.

Подпишитесь на еженедельную рассылку

Самая актуальная аналитика – в вашем почтовом ящике