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.