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
файлу, он выполнит следующее:
- Создайте новый путь к файлу, добавив его
_vrf.dll
к.msstyles
пути к файлу. - Проверьте, существует ли этот новый
_vrf.dll
файл. Если нет, выйдите. - Открыть
_vrf.dll
файл - Проверьте подпись в
_vrf.dll
файле. Если подпись недействительна, выйдите. - Закрыть
_vrf.dll
файл - Загрузите
_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
- Доступен для целевой машины в сети.
Целевая машина
Шаги воспроизведения
- Создайте
.theme
файл, запустив:themebleed.exe make_theme <attacker machine ip> exploit.theme
- На машине злоумышленника выполните:
themebleed.exe server
- На целевой машине откройте
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
.