Это шестая часть нашей статьи о файловой системе CLFS и пяти уязвимостях этого компонента ОС Windows, встречавшихся в кампаниях шифровальщиков на протяжении года. Если вы еще не ознакомились с предыдущими частями, прочтите сначала их.
Используйте содержание для перехода к другим частям:
- Часть 1. Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков
- Часть 2. Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков (№ 1: CVE-2022-24521)
- Часть 3. Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков (№ 2, сентябрь 2022 г.)
- Часть 4. Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков (№ 3, октябрь 2022 г.)
- Часть 5. Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков (№ 4: CVE-2023-23376)
- Часть 6. Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков (№ 5: CVE-2023-28252)
Эксплойт № 5: CVE-2023-28252
В апреле 2023 года вышло исправление еще для одной уязвимости нулевого дня файловой системы CLFS — CVE-2023-28252. Это последняя уязвимость, которую мы обсудим в этой статье. Ее обнаружили в реальной среде ваш покорный слуга Борис Ларин (oct0xor) из «Лаборатории Касперского», Геньвэй Цзян из Mandiant и Кван Джин из DBAPPSecurity WeBin Lab. Исправление вышло ровно через год после исправления для уязвимости CVE-2022-24521, которую использовал эксплойт № 1.
Одновременно с обновлением в апреле 2023 года мы опубликовали короткое сообщение об атаках шифровальщика Nokoyawa с использованием этой уязвимости нулевого дня, а также сведения о самом эксплойте. Через восемь дней мы дополнили статью описанием уязвимости. Мы решили не углубляться в детали, чтобы не облегчать другим злоумышленникам разработку дополнительных эксплойтов для этой уязвимости в тот момент, когда еще не все установили обновление. Сейчас прошло уже несколько месяцев с момента выпуска исправления, так что можно подробно разобрать первопричину возникновения этой уязвимости.
Эксплойт № 5 (CVE-2023-28252) очень похож на эксплойт № 4 (CVE-2023-23376). Новый эксплойт также нацелен на структуру CLFS_CONTROL_RECORD и также стремится обойти верификацию индексов iExtendBlock и iFlushBlock. На самом деле эти два эксплойта почти одинаковы, единственное отличие заключается в модификациях, которые вносятся в файл BLF. Несмотря на практически полное сходство эксплойтов, первопричины соответствующих уязвимостей совершенно разные. Уязвимость CVE-2023-28252, как и все обсуждавшиеся выше, можно отнести к логическим уязвимостям, но она не похожа ни на одну из них, так как не связана с наложением структур друг на друга.
Эксплойт изменяет файл BLF следующим образом.
- Значения eExtendState, iExtendBlock, iFlushBlock и других полей в структуре CLFS_CONTROL_RECORD блока CONTROL изменяются так, чтобы код выполнял функцию ExtendMetadataBlock из функции OpenImage.
- Эксплойт создает вредоносную структуру CLFS_CONTROL_RECORD в блоке CONTROL_SHADOW.
- Значение поля DumpCount для блока CONTROL_SHADOW задается таким образом, чтобы оно было меньше значения DumpCount в блоке CONTROL.
- Эксплойт увеличивает значение cbSymbolZone в записи блока GENERAL таким образом, чтобы функция ExtendMetadataBlock выполнялась повторно при попытке кода добавить новый символ.
- Эксплойт уменьшает значение в поле ValidSectorCount в блоке CONTROL с 2 до 1.
Чтобы понять эту уязвимость, рассмотрим подробнее, как блоки считываются с диска. За это отвечает довольно массивная функция ReadMetadataBlock. Она считывает указанный блок и его теневую версию SHADOW, затем решает, какую из версий следует использовать. Ниже в упрощенном виде представлен код, обеспечивающий процесс такого решения.
Если оба блока в порядке, используется более новый (с большим значением в поле DumpCount). Если один блок в порядке, а второй — нет, то используется тот, что в порядке. Если оба блока не в порядке, код возвращает ошибку.
В порядке блок или нет, решает функция ClfsDecodeBlock. Она представлена ниже.
Функция проверяет, действительна ли контрольная сумма блока и не устарела ли версия формата, но дополнительные проверки выполняет функция ClfsDecodeBlockPrivate.
Эта функция дополнительно проверяет версию, проверяет общее количество секторов TotalSectorCount, проверяет флаги и, если все хорошо, заменяет сигнатуры секторов оригинальными байтами.
Теперь рассмотрим функцию ClfsEncodeBlock, которая используется при записи блоков на диск. Код этой функции представлен ниже.
Эта функция ничего не проверяет. Она просто удаляет контрольную сумму и вызывает функцию ClfsEncodeBlockPrivate. А эта функция выполняет некоторые проверки.
Первое, что бросается в глаза, — несогласованность проверок в функциях ClfsDecodeBlock(Private) и ClfsEncodeBlock(Private). Функция ClfsEncodeBlockPrivate также проверяет TotalSectorCount и флаги, однако, в отличие от ClfsDecodeBlockPrivate, она также проверяет значение ValidSectorCount. Другими словами, если значение ValidSectorCount блока недействительно, блок можно декодировать без проблем, но код не сможет его повторно закодировать. Последний кусочек этой головоломки встает на место, если рассмотреть, как функция ClfsEncodeBlock используется внутри WriteMetadataBlock.
Функция WriteMetadataBlock не проверяет, какое значение возвращает ClfsEncodeBlock. В результате, если она повредит блок, удалив контрольную сумму и возвратив ошибку из-за недействительного значения ValidSectorCount, выполнение кода продолжится в обычном порядке. Это ведет к следующим последствиям:
- При открытии файла BLF код переходит к функции ExtendMetadataBlock, которая вызывает функцию ReadMetadataBlock.
- Функция ReadMetadataBlock проверяет блоки CONTROL и CONTROL_SHADOW. Поскольку оба блока действительны, она использует блок CONTROL из-за большего значения DumpCount.
- Функция ExtendMetadataBlock вносит изменения и запускает функцию WriteMetadataBlock.
- Функция WriteMetadataBlock вызывает ClfsEncodeBlock и повреждает блок CONTROL, задавая в контрольной сумме значение 0 и возвращая ошибку, так как ValidSectorCount < TotalSectorCount.
- Поврежденный блок CONTROL записывается на диск, так как возвращаемое значение ClfsEncodeBlock не проверяется.
- Эксплойт добавляет новый контейнер и, поскольку значение cbSymbolZone изменено, функция ExtendMetadataBlock выполняется снова.
- Функция ReadMetadataBlock проверяет блоки CONTROL и CONTROL_SHADOW — и на этот раз использует вредоносный блок CONTROL_SHADOW, так как у блока CONTROL контрольная сумма равна нулю. В результате ExtendMetadataBlock использует непроверенные индексы iExtendBlock и iFlushBlock.
Дальнейший процесс эксплойта точно такой же, как в эксплойте № 4.
Заключение
Как и ожидалось, некоторые уязвимости из числа описанных в этой статье на самом деле являются вариантами ранее известных уязвимостей. Более тщательное исправление этих ошибок, вероятно, предотвратило бы появление этих эксплойтов.
Сама файловая система CLFS — наглядный пример того, как не следует проектировать формат файла. Меня удивляет, что она до сих пор существует в нынешнем виде. Можно ли считать CLFS полностью безопасной после выявления такого количества уязвимостей и эксплойтов нулевого дня? С момента выхода исправления для CVE-2023-28252 в апреле 2023 года было закрыто еще несколько уязвимостей CLFS.
С другой стороны, мы очень благодарны Microsoft за работу по блокировке техник PreviousMode и NtQuerySystemInformation. В последние два года мы наблюдаем лавину эксплойтов нулевого дня, позволяющих киберпреступникам повысить уровень привилегий со среднего IL до системного IL. Блокировка этих приемов делает новые версии Windows 11 более устойчивыми к подобным эксплойтам.
Мы, в свою очередь, продолжим внимательно следить за операциями злоумышленников и охотиться на эксплойты нулевого дня.
Драйвер Windows CLFS и пять эксплойтов операторов шифровальщиков (№ 5: CVE-2023-28252)