October 11, 2023

CVE-2023-38146: выполнение произвольного кода через темы Windows.

Это забавная ошибка, которую я обнаружил, исследуя странные форматы файлов Windows. Это своего рода классическая уязвимость в стиле Windows, характеризующаяся нарушенной подписью, отрывочной загрузкой DLL, гонками файлов, CAB-файлами и глупостью Mark-of-the-Web. Кроме того, это был мой первый опыт участия в программе MSRC по обнаружению ошибок Windows с тех пор, как я покинул Microsoft в апреле 2022 года.

Следуя великой традиции именования уязвимостей, я с любовью назвал эту уязвимость ThemeBleed (логотипа пока нет, но я принимаю предложения).

В целом было очень весело найти и выявить эту уязвимость, и MSRC невероятно быстро отреагировал и назначил за нее награду :^]

Ниже представлена ​​слегка измененная версия отчета, который я отправил в Microsoft. После отчета идет график и мои заметки по их исправлению.

Краткое содержание

В Windows 11 существует ряд проблем, которые могут привести к выполнению произвольного кода при загрузке файла пользователем .theme.

Подробности об ошибке

1. История

В Windows .themeфайлы позволяют настраивать внешний вид ОС. Сами файлы .themeпредставляют собой ini-файлы, содержащие сведения о конфигурации. Нажатие на .themeфайл в Windows 11 вызовет следующую команду:

"C:\WINDOWS\system32\rundll32.exe" C:\WINDOWS\system32\themecpl.dll,OpenThemeAction <theme file path>

Эта уязвимость конкретно связана с обработкой .msstylesфайлов. Это файлы PE (DLL), которые содержат ресурсы, такие как значки, которые будут использоваться в теме, но (не должны) содержать никакого кода. На файл .msstylesможно ссылаться в .themeфайле следующим образом:

[VisualStyles]
Path=%SystemRoot%\resources\Themes\Aero\Aero.msstyles

При .themeоткрытии файла он .msstylesтакже будет загружен.

2. Проверка «Версии 999»

При загрузке .msstylesфайла LoadThemeLibraryвинда uxtheme.dllпроверит версию темы. Это будет сделано путем загрузки ресурса, указанного PACKTHEM_VERSIONв двоичном файле. Если версия, которую он читает, равна 999, он вызовет другую функцию ReviseVersionIfNecessary. Декомпилированную версию этой функции с комментариями к соответствующим частям можно увидеть ниже:

__int64 __fastcall LoadThemeLibrary(const WCHAR *msstyles_path, HMODULE *out_module, int *out_version)
{
  HMODULE module_handle;
  signed int result;
  int version;
  signed int return_val;
  unsigned int resource_size;
  __int16 *version_ptr;

  if ( out_version )
    *out_version = 0;
  module_handle = LoadLibraryExW(msstyles_path, 0, 2u);
  if ( !module_handle )
    return (unsigned int)MakeErrorLast();
  result = GetPtrToResource(
             module_handle,
             L"PACKTHEM_VERSION",
             (const unsigned __int16 *)1,
             (void **)&version_ptr,
             &resource_size); // !!! [1] version number is extracted from resource "PACKTHEM_VERSION"
  if ( result < 0 || resource_size != 2 )
    goto LABEL_22;
  version = *version_ptr;
  if ( out_version )
    *out_version = version;
  return_val = -2147467259;
  if ( version >= 4 )
  {
    if ( version > 4 )
      result = -2147467259;
    return_val = result;
  }
  if ( return_val < 0 && (_WORD)version == 999 ) // !!! [2] special case for version 999
  {
    resource_size = 999;
    return_val = ReviseVersionIfNecessary(msstyles_path, 999, (int *)&resource_size); // !!! [3] call to `ReviseVersionIfNecessary`
...
}

3. Время проверки-время использования в ReviseVersionIfNecessary позволяет обходить подпись

Функция ReviseVersionIfNecessary, вызванная на предыдущем шаге, выполняет несколько действий. Учитывая путь к .msstylesфайлу, он выполнит следующее:

  1. Создайте новый путь к файлу, добавив его _vrf.dllк .msstylesпути к файлу.
  2. Проверьте, существует ли этот новый _vrf.dllфайл. Если нет, выйдите.
  3. Открыть _vrf.dllфайл
  4. Проверьте подпись в _vrf.dllфайле. Если подпись недействительна, выйдите.
  5. Закрыть _vrf.dllфайл
  6. Загрузите _vrf.dllфайл как DLL и вызовите VerifyThemeVersionфункцию.

Целью этого, по-видимому, является попытка безопасно загрузить подписанную DLL и вызвать функцию. Однако эта реализация ошибочна, поскольку DLL закрывается после проверки подписи на шаге 5, а затем снова открывается, когда DLL загружается посредством вызова LoadLibrary на шаге 6. Это обеспечивает окно гонки между этими двумя шагами, где злоумышленник может заменить _vrf.dllфайл, подпись которого проверена, на вредоносный файл, который не подписан. Затем эта вредоносная DLL будет загружена и выполнена.

4. Обход веб-меток

Если пользователь загружает .themeфайл, при его запуске он получит предупреждение системы безопасности из-за наличия в файле метки Интернета. Оказывается, это можно обойти, упаковав .themeфайл в .themepackфайл.

Файл .themepackпредставляет собой CAB-файл, содержащий .themeфайл. Когда .themepackфайл открывается, содержащийся в нем .themeфайл будет загружен. При открытии .themepackфайла с помощью Mark-of-the-Web предупреждение не отображается, поэтому предупреждение, которое обычно отображается, игнорируется.

Доказательство концепции

Я разработал PoC для этой проблемы. PoC состоит из двух компонентов: исполняемого файла SMB-сервера, который нужно запустить на компьютере злоумышленника, и файла, который .themeнужно открыть на компьютере цели.

Я решил использовать для этого SMB-сервер, контролируемый злоумышленником, поскольку .themeфайл может указывать на .msstyleпуть к удаленному общему ресурсу SMB. Поскольку общий ресурс SMB контролируется злоумышленником, он может легко использовать ошибку TOCTOU, ReviseVersionIfNecessaryвозвращая правильно подписанный файл, когда клиент сначала запрашивает его для проверки подписи, а затем вредоносный файл, когда клиент загружает DLL.

PoC можно найти здесь: https://github.com/gabe-k/themebleed .

Подготовка среды

Для запуска PoC вам понадобятся две машины: одна машина злоумышленника, на которой будет работать SMB-сервер, и одна целевая машина, на которую вы загрузите файл .theme. Ниже приведены требования к соответствующим машинам:

Атакующая машина

  • Windows 10 или 11
  • Отключите службу «Сервер», чтобы освободить порт SMB (отключите и перезапустите, а не просто останавливайте службу)
  • Актуальная версия .NET
  • Доступен для целевой машины в сети.

Целевая машина

  • Последняя версия Windows 11

Шаги воспроизведения

  1. Создайте .themeфайл, запустив:themebleed.exe make_theme <attacker machine ip> exploit.theme
  2. На машине злоумышленника выполните:themebleed.exe server
  3. На целевой машине откройтеexploit.theme

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

Кредиты

PoC использует SMBLibrary Тала Алони.

Заключение

Это надежная уязвимость, которая позволяет перейти от загрузки темы к загрузке и выполнению кода без повреждения памяти. Кроме того, эта уязвимость кажется новой и присутствует только в Windows 11. Я прошу рассмотреть эту заявку на предмет вознаграждения.

Чтобы исправить эту уязвимость, я бы рекомендовал:

  • Полностью удаляю функциональность «версии 999», но я не совсем уверен, для чего она предназначена.
  • Подписание и проверка _vrf.dllдвоичного файла стандартным способом Windows проверяет другой код, а не тот, который уязвим для подобных состояний гонки.
  • Запретить загрузку ресурсов из удаленных общих ресурсов в файлах темы.
  • Добавляйте в файлы предупреждения о веб-маркировке .themepack.
Конец исходного отчета

График отчетности

  • 15 мая 2023 г. — отчет и PoC отправлены в Microsoft.
  • 16.05.2023 — Признание уязвимости со стороны Microsoft.
  • 17.05.2023 — вознаграждено вознаграждение в размере 5000 долларов США.
  • 12.09.2023 - Выпущен фикс.

Анализ исправлений Microsoft

Выпущенное Microsoft исправление этой проблемы полностью удалило функциональность «версии 999». Хотя это и смягчает этот конкретный эксплойт, оно по-прежнему не решает проблему TOCTOU при подписании .msstylesфайлов.

Кроме того, Microsoft не добавила в файлы предупреждения о наличии веб-маркировки .themepack.