Hello everybody, my name is Michael Zhmailo and I am a penetration testing expert in the MTS Innovation Center CICADA8 team.
You have probably come across MSI files quite often. They are used by software manufacturers to provide their programs. This format is more convenient than the standard EXE format for the following reasons:
- Ability to restore, install certain components
- Data storage in well-structured tables that can be easily accessed via APIs
- Easy distribution via SCCM, WEB endpoints
There may be various vulnerabilities inside MSI files, most of which will lead to privilege escalation. These include both logical vulnerabilities: DLL/TypeLib/COM/Exe File/Script/etc hijacking, PATH Abusing, and vulnerabilities of the MSI file format itself: Custom Actions Abuse, abandoned credentials, privileged child processes.
You may have read about vulnerabilities in MSI files before:
- 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
These are great articles if you are just getting familiar with finding vulnerabilities inside MSI files. Our article can also serve as a great starting point for learning more about this topic. In addition, we have developed a tool called MyMSIAnalyzer that will make it easier to find vulnerabilities inside MSI files. You should read this article if you want to learn more about the insides of the MSI format and how the tool works.
MSI File Format
The MSI format itself is somewhat similar to SQL databases. Inside the MSI file there are tables with various data. There is a relationship between the tables. And this table is analyzed and used while installing MSI file.
I note that there are a lot of tables. We are interested in only a few of them. The full list of tables is described here.
- Component Table — a special table inside which resources used by the application (images, shortcuts, icons, etc.) are located;
- Each resource is associated with a specific functionality. Therefore, there is a Feature Table, which is linked to the Components Table through the FeatureComponents Table;
- File Table — a table that specifies which files should be installed on the system;
- Directory Table — table that contains information about the folder structure of the program to be installed;
- Installation Actions — table that contains actions to be performed during MSI file installation (create a shortcut, create a registry key, write a value);
- Custom Actions — actions that need to be performed during the installation process, however, they cannot be performed through Windows Installer API, so third-party programs, DLL files, cmd commands are used.
Collecting MSI files for analysis
Manually
The easiest way to locate all MSI files is to look in the C:\Windows\Installer folder. Here you will definitely find all MSI files of programs installed on your computer.
Inside the folder you can find MSI files and other folders. Other folders often store various resources that the MSI file needs. Their name is GUID. This GUID can be seen in the IdentifiyingNumber field of the installed software product.
You can examine the installed programs and make a mapping using these commands:
wmic product get identifyingnumber,name,vendor,version
You can also use Powershell and add a filter by software.
Get-WmiObject -class Win32_Product | ? { $_.Name -like "*Office*" } | select IdentifyingNumber,Name
Tools
Of course, it is more convenient to use automated tools to gather information and MSI files itself.
- https://github.com/mandiant/msi-search — This tool can be used to search for msi files, then download them and then analyze them directly on the attacker’s machine to detect privilege escalation vectors (can be analyzed for privilege escalation vectors using, for example, our MyMSIAnalyzer tool :) );
- https://github.com/1njected/CMLoot — Great for extracting MSI files from SCCM. For example, from Distribution Points;
PS> Invoke-CMLootInventory -SCCMHost sccm01.domain.local -Outfile sccmfiles.txt
PS> Invoke-CMLootDownload -InventoryFile .\sccmfiles.txt -Extension msi
- https://github.com/shelltrail/cmloot — python version of CMLoot.
Web
You can find files for analysis on the internet as well. For example, you can use Google Dorks:
ext:msi "download"
Or use special resources with a list of MSI files:
Searching for vulnerabilities
Abandoned credentials
It’s the simplest option. Inside MSI files, it is possible to find leftover passwords, API keys, endpoints and other data that may be of interest to us as attackers.
We have dedicated a CredFinder class in MyMSIAnalyzer for credential discovery. Searching for credentials works to the point of simplicity. It checks all properties of the MSI file and tries to find sensitive information by keywords.
Since MSI format is close to SQL format, you can get all properties with one query. However, if you need a portable option or don’t know how to compile CSharp projects yet, you can use a Powershell script with same logic:
$installerPath = "C:\Windows\Installer"
$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
}
Behavioral analysis
MSI Repair Mode
Of course, inside MSI credentials can be found quite rarely. Most often only when analyzing MSI files that were stolen from SCCM. So if we are looking for a privilege escalation vector, we need to analyze the behavior of the MSI file.
And here we need to familiarize ourselves with an unusual functionality: the MSI file repair mechanism.
MSI’s repair mechanism allows a Windows system to reinstall either the entire product or individual components of the product. In effect, fix the program if something went wrong during use or installation.
This functionality is most conveniently utilized using the CLI tool msiexec.
In addition, MSI Custom Actions, which were created by the developer of the MSI file, are invoked in recovery mode. Here too, there may be a vulnerability. If Custom Actions or the entire MSI file is misconfigured, the recovery process is performed on behalf of the NT AUTHORITY\SYSTEM user, which allows us to escalate privileges.
For example, if the developer has set Custom Actions to run cmd.exe, then during a normal installation cmd.exe will be run as the current user, but during recovery it will be run as the system user.
Also through Custom Actions can run some graphical applications on behalf of the system, from which you can make an analog of Kiosk Bypass, get out to explorer.exe and run cmd.exe from it. cmd.exe will be launched on behalf of the system.
How to detect it?
Let’s start by checking the entire MSI file. There are only two things we need to monitor:
- Presence of a GUI interface, if we want to promote via explorer.exe escape
- The name of the user on whose behalf the MSI file is run in recovery mode, if we want to examine the file for other vulnerabilities, such as DLL Hijacking
The easiest way to detect such MSI files is to use the GuiFinder tool:
.\GuiFinder.exe --folder C:\Temp
If you find yourself running from the NT AUTHORITY\System and the presence of a graphical interface, you can attempt to perform an escape from the environment as described above.
What about custom actions?
Custom Actions can also be executed on behalf of the NT AUTHORITY\SYSTEM. To do so, they must be configured with the Impersonate=“no” option. For example, as here
<?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>
This will cause Custom Actions to be run on behalf of the NT AUTHORITY\SYSTEM. We created a ActionAnalyzer class to analyze Custom Actions.
First, we also highlighted keywords whose presence within Custom Actions will result in privilege escalation. After all, it will be easy to abuse this functionality.
The tool then checks that Custom Actions will in principle be called. To do this, they must be in the call sequence between InstallExecuteSequence and InstallFinalize.
The validation of these indices is done a little later. After getting the indexes, we extract all Custom Actions and check for the most important parameter Impersonate: NO
After making sure that the Custom Action is executed on behalf of the system and is within the correct action sequence, a keyword check is performed
Lets run the tool.
The tool will then bring up some interesting CustomActions. And you can start finding ways to abuse them. For example, perform DLL Sideloading, launch a file from User Writable Paths, find another vulnerability. I encourage you to study this article and this. It covers the most common ways to abuse CustomActions.
You can learn how to use our tool and hone your skills on the following vulnerabilities:
- CVE-2023–26077 (MSI Installer DLL Hijacking)
- CVE-2023–21800 (Symlink Abuse)
- CVE-2023–26078 (Escape to cmd.exe)
Custom Actions Overwriting
There is an even more interesting vector. We can find a CustomAction that runs on behalf of the system. However, we may not be able to abuse it. In that case, we can try to overwrite it! If the permissions on the MSI file allow, of course. In some cases, administrators override the default DACL, which will result in elevated privileges.
To find this vector, we created a Writer class.
Diff
MSI files both contain vulnerabilities and fixes them! So we needed a convenient way to implement diff of two files to analyze patches.
The simplest way is to use msidiff, its syntax is self-explanatory
Conclusion
MSI files are used quite often in the Windows infrastructure. Often an improper approach to developing or deploying such files will lead to the possibility of privilege escalation on the host.