Evil MSI. A story about vulnerabilities in MSI Files
你们可能经常遇到 MSI 文件。软件制造商使用它们来提供他们的程序。与标准的 EXE 格式相比,这种格式更方便,原因如下:
-
能够恢复、安装某些组件 -
数据存储在结构良好的表中,可以通过 API 轻松访问 -
通过 SCCM、WEB 端点轻松分发
MSI 文件内部可能存在各种漏洞,其中大多数会导致 权限提升。这些漏洞包括逻辑漏洞:DLL/TypeLib/COM/Exe 文件/脚本等劫持、PATH 滥用,以及 MSI 文件格式本身的漏洞:自定义操作滥用、遗留凭据、特权子进程。
你可能之前读过关于 MSI 文件漏洞的文章:
-
https://cloud.google.com/blog/topics/threat-intelligence/privileges-third-party-windows-installers/ -
https://github.com/mandiant/msi-search -
https://intezer.com/blog/incident-response/how-to-analyze-malicious-msi-installer-files/ -
https://blog.doyensec.com/2024/07/18/custom-actions.html -
https://www.trendmicro.com/en_us/research/19/d/analysis-abuse-of-custom-actions-in-windows-installer-msi-to-run-malicious-javascript-vbscript-and-powershell-scripts.html -
https://badoption.eu/blog/2023/10/03/MSIFortune.html
如果你刚开始熟悉在 MSI 文件中查找漏洞,这些文章非常不错。我们的文章也可以作为学习更多关于这个主题的良好起点。此外,我们开发了一款名为 MyMSIAnalyzer 的工具,可以更轻松地查找 MSI 文件中的漏洞。如果你想了解更多关于 MSI 格式内部结构及该工具如何工作的内容,建议你阅读这篇文章。
MSI 文件格式
MSI 格式本身与 SQL 数据库有些相似。在 MSI 文件内部,有多个包含各种数据的表。这些表之间存在关系。在安装 MSI 文件时,会分析并使用这些表。
MSI 文件格式
我注意到有很多表。我们只对其中的少数几个感兴趣。完整的表列表可以在 这里 找到。
-
组件表 — 一个特殊的表,里面存放应用程序使用的资源(图像、快捷方式、图标等); -
每个资源与特定功能相关联。因此,有一个 功能表,它通过 FeatureComponents 表 与组件表相连; -
文件表 — 一个指定系统上应安装哪些文件的表; -
目录表 — 包含要安装的程序的文件夹结构信息的表; -
安装操作 — 包含在 MSI 文件安装过程中要执行的操作(创建快捷方式、创建注册表项、写入值)的表; -
自定义操作 — 在安装过程中需要执行的操作,但无法通过 Windows Installer API 执行,因此使用第三方程序、DLL 文件、cmd 命令等。
收集 MSI 文件以进行分析
手动
定位所有 MSI 文件的最简单方法是查看 C:WindowsInstaller 文件夹。在这里,你一定会找到计算机上安装的所有程序的 MSI 文件。
文件夹内容 #1
文件夹内容 #2
在该文件夹内,你可以找到 MSI 文件和其他文件夹。其他文件夹通常存储 MSI 文件所需的各种资源。它们的名称是 GUID。这个 GUID 可以在已安装软件产品的 IdentifiyingNumber 字段中看到。
你可以使用以下命令检查已安装的程序并进行映射:
wmic product get identifyingnumber,name,vendor,version
已安装产品列表
您还可以使用 PowerShell 并通过软件添加过滤器。
Get-WmiObject -class Win32_Product | ? { $_.Name -like "*Office*" } | select IdentifyingNumber,Name
工具
当然,使用自动化工具来收集信息和 MSI 文件本身更为方便。
-
https://github.com/mandiant/msi-search — 这个工具可以用来搜索 MSI 文件,然后下载它们,并直接在攻击者的机器上分析,以检测特权提升向量(例如,可以使用我们的 MyMSIAnalyzer 工具进行特权提升向量的分析 ); -
https://github.com/1njected/CMLoot — 非常适合从 SCCM 中提取 MSI 文件。例如,从分发点提取;
PS> Invoke-CMLootInventory -SCCMHost sccm01.domain.local -Outfile sccmfiles.txt
PS> Invoke-CMLootDownload -InventoryFile .sccmfiles.txt -Extension msi
-
https://github.com/shelltrail/cmloot — CMLoot 的 Python 版本。
网络
您也可以在互联网上找到用于分析的文件。例如,您可以使用 Google Dorks:
ext:msi "download"
或者使用包含 MSI 文件列表的特殊资源:
-
https://github.com/microsoft/winget-pkgs
-
https://sourceforge.net/projects/msi-installers/
搜索漏洞
遗留凭证
这是最简单的选项。在 MSI 文件中,可以找到遗留的密码、API 密钥、端点以及其他可能引起我们作为攻击者兴趣的数据。
我们在 MyMSIAnalyzer 中专门设置了一个 CredFinder 类用于凭证发现。搜索凭证的过程简单明了。它检查 MSI 文件的所有属性,并尝试通过关键词找到敏感信息。
CredFinder.cs
由于 MSI 格式接近 SQL 格式,您可以通过一个查询获取所有属性。然而,如果您需要一个便携的选项或尚不清楚如何编译 CSharp 项目,您可以使用具有相同逻辑的 PowerShell 脚本。
$installerPath = "C:WindowsInstaller"
$package = New-Object -ComObject WindowsInstaller.Installer
function AnalyzeMsiFile {
param (
[string]$msiPath
)
try {
$database = $package.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $package, @($msiPath, 0))
$view = $database.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $database, @("SELECT * FROM Property"))
$view.Execute()
while ($record = $view.Fetch()) {
$property = $record.StringData(1)
$value = $record.StringData(2)
if ($property -match "USERNAME|PASSWORD|USER|PASS") {
Write-Host "File: $msiPath, Property: $property, Value: $value"
}
}
} catch {
Write-Host "Error processing file: $msiPath" -ForegroundColor Red
}
}
Get-ChildItem -Path $installerPath -Filter *.msi -Recurse | ForEach-Object {
AnalyzeMsiFile $_.FullName
}
行为分析
MSI 修复模式
当然,在 MSI 文件中找到凭证的情况非常少见。通常只有在分析从 SCCM 被盗的 MSI 文件时才会出现。因此,如果我们在寻找权限提升的途径,就需要分析 MSI 文件的行为。
在这里,我们需要熟悉一个不寻常的功能:MSI 文件的修复机制。
MSI 的修复机制允许 Windows 系统重新安装整个产品或产品的单个组件。实际上,如果在使用或安装过程中出现问题,可以修复程序。
此功能最方便的使用方式是通过命令行工具 msiexec。
此外,MSI 文件的开发者创建的 MSI 自定义操作在恢复模式下被调用。在这里也可能存在漏洞。如果自定义操作或整个 MSI 文件配置错误,恢复过程将以 NT AUTHORITYSYSTEM 用户的身份执行,这使我们能够提升权限。
例如,如果开发者设置自定义操作以运行 cmd.exe,那么在正常安装过程中,cmd.exe 将以当前用户的身份运行,但在恢复过程中,它将以系统用户的身份运行。
通过自定义操作还可以以系统身份运行一些图形应用程序,从而实现类似 Kiosk Bypass 的效果,进入 explorer.exe 并从中运行 cmd.exe。cmd.exe 将以系统身份启动。
自定义操作滥用中的 GUI
在 Internet Explorer 安装程序中的滥用示例
如何检测?
让我们开始检查整个 MSI 文件。我们需要监控的只有两件事:
-
GUI 界面的存在,如果我们想通过 explorer.exe 进行逃逸 -
在恢复模式下 MSI 文件以哪个用户的身份运行,如果我们想检查文件是否存在其他漏洞,例如 DLL 劫持
检测此类 MSI 文件的最简单方法是使用 GuiFinder 工具。
.GuiFinder.exe --folder C:Temp
如果你发现自己正在以 NT AUTHORITYSystem 身份运行,并且存在图形界面,你可以尝试如上所述从环境中逃逸。
自定义操作怎么办?
自定义操作也可以以 NT AUTHORITYSYSTEM 的身份执行。为此,它们必须配置为 Impersonate=“no” 选项。例如,如下所示
<?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>
这将导致自定义操作以 NT AUTHORITYSYSTEM 的身份运行。我们创建了一个 ActionAnalyzer 类来分析自定义操作。
首先,我们还强调了在自定义操作中出现的关键字,这些关键字的存在将导致权限提升。毕竟,滥用此功能将变得非常简单。
有趣的关键字
该工具接着检查自定义操作是否原则上会被调用。为此,它们必须位于 InstallExecuteSequence 和 InstallFinalize 之间的调用序列中。
获取序列索引
这些索引的验证稍后进行。在获取索引后,我们提取所有自定义操作,并检查最重要的参数 Impersonate: NO。
自定义操作标志分析
在确保自定义操作以系统身份执行并且位于正确的操作序列中后,进行关键字检查。
关键字检查
让我们运行该工具。
示例输出
该工具将显示一些有趣的自定义操作。您可以开始寻找滥用它们的方法。例如,执行 DLL 侧载,从用户可写路径启动文件,寻找其他漏洞。我鼓励您研究 这篇文章 和 这篇。它涵盖了滥用自定义操作的最常见方法。
您可以学习如何使用我们的工具,并在以下漏洞上磨练您的技能:
-
CVE-2023–26077(MSI 安装程序 DLL 劫持) -
CVE-2023–21800(符号链接滥用) -
CVE-2023–26078(逃逸到 cmd.exe)
自定义操作覆盖
还有一个更有趣的向量。我们可以找到一个以系统身份运行的自定义操作。然而,我们可能无法滥用它。在这种情况下,我们可以尝试覆盖它!当然,前提是 MSI 文件的权限允许。在某些情况下,管理员会覆盖默认的 DACL,这将导致权限提升。
为了找到这个向量,我们创建了一个 Writer 类。
输出示例
差异
MSI 文件既包含漏洞,也修复了它们!因此,我们需要一种方便的方法来实现两个文件的差异分析。
最简单的方法是使用 msidiff,其语法不言自明。
差异示例
结论
MSI 文件在 Windows 基础设施中使用相当频繁。通常,对开发或部署此类文件的不当处理将导致主机上可能出现权限提升的风险。
原文始发于微信公众号(securitainment):恶意 MSI - 关于 MSI 文件漏洞的故事
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论