During a customer engagement I identified a local escalation of privilege vulnerability (CVE-2021-26273) in a remote monitoring and management (RMM) tool: NinjaRMM Agent. The vulnerability allowed a non-administrative user to become ”NT Authority\SYSTEM”.
Since the RMM tool was deployed on most of the customer’s systems, the newfound vulnerability, in combination with lateral movements, made it easy to compromise any of the customer’s most critical systems.
Post-discovery, I went into talks with NinjaRMM who identified the vulnerability stemming from a tool in their software; EXEMSI MSI Wrapper which allows a software vendor to “wrap” an EXE-file in an MSI-file which allows easier deployment. The MSI Wrapper itself and systems with it installed are not vulnerable, but any MSI-files created with the tool could be (CVE is pending).
I have spent additional time identifying and contacting other software vendors using MSI Wrapper to ensure they have awareness and mitigated the vulnerability in their newest deployments.
I also discovered an additional vulnerability (CVE-2021-26274) in the NinjaRMM Agent, not nearly as interesting, but a vulnerability, nonetheless.
Both vulnerabilities of NinjaRMM Agent are described in this blogpost. The local privilege escalation vulnerability exploitation steps will vary depending on how the software vendor customizes the MSI-file and how the MSI-file is deployed.
CVEs registered
NinjaRMM Agent
Affected versions
EXEMSI MSI Wrapper prior to version 10.0.50 and at least since version 6.0.91
NinjaRMM Agents prior to version 5.0.4.0, since version 4.0.0
Timeline
NinjaRMM
2021/01/13: Vulnerability discovered during customer engagement.
2021/01/18: Contacted NinjaRMM via phone call – was told they would return via e-mail.
2021/01/22: Received no response. Contacted NinjaRMM CSO via LinkedIn.
2021/01/23: Discovered second vulnerability.
2021/01/25: Contacted by NinjaRMM CSO.
2021/01/27: Vulnerability confirmed and mitigation in progress.
2021/01/28: NinjaRMM patched all deployed NinjaRMM Agents.
EXEMSI MSI Wrapper
2021/01/27: Potential vulnerability discovered based on information from NinjaRMM.
2021/01/27: Contacted EXEMSI via phone call.
2021/02/03: Confirmed mitigation in updated version provided by vendor.
CVE-2021-26273 – Windows Installer Local Privilege Escalation
Description
The NinjaRMM Agent version 5.0.909 Windows Installer executes an EXE-file as ”NT Authority\SYSTEM” from the directory “%TEMP%\MW-<GUID>\” with the name “<GUID>-<ORGANIZATION SPECIFIC STRING>-<version>-windows-installer.exe”.
Default permissions of both the directory and the executable file grants non-administrative users write access.
Due to the weak permissions, an attacker could place the executable file before the Windows Installer, lock the file for write access, and wait for the installer to execute the file as ”NT Authority\SYSTEM”.
This type of vulnerability, how to exploit and mitigate it is also described in the following resources:
A responsible disclosure webinar held by my colleague Anders Kusk and Lasse Trolle Borup, which describes the strange behaviour of the Windows Installer API.
A blog post by my colleague Anders Kusk: The many pitfalls of Windows MSI - Privilege escalation in Windows 7/8.1/10/Server and a range of third-party products.
SandboxEscaper’s Chasing polar bears: part one and part two.
Walkthrough
The Author property of files in C:\Windows\Installer reveals that a NinjaRMM software has a Windows Installer file:
The identified file is NinjaRMM Agent:
The Windows Installer can be executed with msiexec.exe by a non-administrative user:
msiexec.exe /fa C:\Windows\Installer\<name>.msi
During execution, SysInternals Process Monitor was used to monitor actions of the process. It was identified that an .exe is created by the executing non-administrative user (seen by the property Integrity: Medium):
And later the same file is executed by SYSTEM without impersonation (SYSTEM also does other operations on the file, but none which affect this demonstrated exploit):
A tip is: “If you do file operations on Windows on unprotected directories, you must do it with an impersonated token [instead of the primary token] or else you risk a file manipulation attack”[1]
Inspecting permissions of the directory and executable reveals that it is indeed unprotected (our non-administrative user has Full control):
So how do we do this “file manipulation attack”? Since the non-administrative user has write permission to the directory and file, we can exploit the race condition by placing our own executable file (or symbolic link) before the installer, lock the file for writing, and wait for the installer to execute the file.
However, the directory name in which the file resides, contains a GUID unique to each execution which we need to know before placing our file. The directory’s name is:
“%TEMP%\MW-<RANDOM GUID>”
The file’s name also contains a GUID but was concluded to be static when tested on multiple systems with the same installer. Executing the installer once gives you this name when inspecting the “%TEMP%\MW-<RANDOM GUID>\” directory. The file’s name is:
“<STATIC GUID>-< ORGANIZATION SPECIFIC STRING>-<VERSION>-windows-installer.exe”.
To develop the exploit, I used PowerShell. The code below performs the following logic:
Disclaimer: PowerShell is slow for race conditions + the code can be optimized in multiple ways to increase chances of “winning”.
Load an executable file in memory (I will use cmd.exe), ready to be placed into the directory as the executable file.
Continuously check for the directory containing a random GUID.
Create the executable file.
If successful, lock the file for writing, to protect it from modification from the legitimate NinjaRMM Agent Windows Installer.
Pauses the script to wait for the Windows Installer to execute the executable.
[byte[]] $exeBytes = (Get-Content -Encoding Byte -Path C:\Windows\System32\cmd.exe) -split ' ' $dir = $null $exe = "883f27ea-79a5-4c31-8fe9-7fe32cccc582-<ORGANIZATION SPECIFIC STRING>-4.5.6152-windows-installer.exe" Write-Host "exe loaded, launch installer now." while(1) { $dir = Get-Item "C:\Users\John Doe\AppData\Local\Temp\MW-*" if ($dir) { $exePath = $dir.FullName + "\" + $exe try { [System.IO.File]::WriteAllBytes($exePath, $exeBytes) $fileStream = [System.IO.File]::Open($exePath, "Open", "Read", "Read") Read-Host "Press return when done/if you get shell (to release file lock)." $fileStream.Close() } catch { Read-Host "Lost race condition." } return } }
The exploit is demonstrated on our Improsec YouTube channel:
The exploit is also be seen by relating the numbers in the list below to numbers seen in the screenshot:
The exploit code being executed.
Executing the NinjaRMM Agent Windows Installer.
The Ninja RMM Agent Windows Installer executing.
The executable file (cmd.exe) opened by Windows Installer as “NT Authority\SYSTEM”.
Inspecting a Process Monitor capture from a successful exploit we see:
PowerShell querying for the randomly named directory.
MsiExec creating the directory.
PowerShell finding the directory.
Powershell successfully creating our file (copy of cmd.exe).
MsiExec failing in creating the installer file.
Later on Process Monitor will show MsiExec.exe executing the file.
CVE-2021-26274 – Insecure Default Permissions on NinjaRMM Agent ProgramData directory
Description
The directory “C:\ProgramData\NinjaRMMAgent”, created during NinjaRMM Agent installation, allows “BUILTIN\Users” to write to the folder and subfolders:
Since the NinjaRMM Agent service, running as “NT Authority\SYSTEM”, creates, writes to, and deletes logfiles in this directory, it would be possible to redirect the actions to local arbitrary paths. This could result in loss of integrity on system-critical files stored in C:\Windows, leading to denial of service.
No proof-of-concept was made for this vulnerability, but again I refer to SandboxEscaper’s blogs and for tools to exploit I recommend James Forshaw’s symboliclink-testing-tools.
[1] https://www.cyberark.com/resources/threat-research-blog/follow-the-link-exploiting-symbolic-links-with-ease