Attacker Value
High
(3 users assessed)
Exploitability
High
(3 users assessed)
User Interaction
None
Privileges Required
Low
Attack Vector
Local
12

CVE-2021-41379

Disclosure Date: November 10, 2021
Exploited in the Wild
Add MITRE ATT&CK tactics and techniques that apply to this CVE.
Credential Access
Techniques
Validation
Validated
Validated
Validated
Validated
Defense Evasion
Techniques
Validation
Validated
Validated
Validated
Validated
Validated
Lateral Movement
Techniques
Validation
Validated
Privilege Escalation
Techniques
Validation
Validated

Description

Windows Installer Elevation of Privilege Vulnerability

Add Assessment

1
Ratings
Technical Analysis

The variant of CVE-2021-41379 that was released as a zero-day exploit is a local privilege escalation issue that is the result of a few issues with msiexec.exe. See the Rapid7 analysis for more details.

0
Technical Analysis

The patch bypass for this vulnerability is now being exploited in the wild as noted at https://blog.talosintelligence.com/2021/11/attackers-exploiting-zero-day.html. I have not labeled this bug as exploited in the wild though as the code noted below by @kevthehermit is an exploit for a variant of this bug, not this bug itself, however it is important to note that the bugs are related and no patch exists yet for the variant at the time of writing (November 24th 2021).

CVSS V3 Severity and Metrics
Base Score:
7.8 High
Impact Score:
5.9
Exploitability Score:
1.8
Vector:
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector (AV):
Local
Attack Complexity (AC):
Low
Privileges Required (PR):
Low
User Interaction (UI):
None
Scope (S):
Unchanged
Confidentiality (C):
High
Integrity (I):
High
Availability (A):
High

General Information

Vendors

  • Microsoft

Products

  • Windows,
  • Windows Server,
  • Windows 10 Version 1909 for 32-bit Systems,
  • Windows 10 Version 1909 for x64-based Systems,
  • Windows 10 Version 1909 for ARM64-based Systems,
  • Windows 10 Version 21H1 for x64-based Systems,
  • Windows 10 Version 21H1 for ARM64-based Systems,
  • Windows 10 Version 21H1 for 32-bit Systems,
  • Windows Server 2022,
  • Windows Server 2022 (Server Core installation),
  • Windows 10 Version 2004 for 32-bit Systems,
  • Windows 10 Version 2004 for ARM64-based Systems,
  • Windows 10 Version 2004 for x64-based Systems,
  • Windows Server, version 2004 (Server Core installation),
  • Windows 10 Version 20H2 for x64-based Systems,
  • Windows 10 Version 20H2 for 32-bit Systems,
  • Windows 10 Version 20H2 for ARM64-based Systems,
  • Windows Server, version 20H2 (Server Core Installation),
  • Windows 11 for x64-based Systems,
  • Windows 11 for ARM64-based Systems

Exploited in the Wild

Reported by:

Additional Info

Technical Analysis

Description

On November 9, 2021, Microsoft published details on CVE-2021-41379, a vulnerability that allows low privileged Windows users to delete protected files. Microsoft credited Abdelhamid Naceri for discovering this issue. On November 21, Naceri published an exploit that allows low privileged users to overwrite protected files, resulting in privilege escalation to SYSTEM. Naceri stated that the exploit targets a variation of CVE-2021-41379 that Microsoft did not fix. The exploit therefore targets a zero-day vulnerability. Microsoft has not issued a security bulletin for this issue, but, when they do, it will likely be scored as CVSSv3 7.8.

The zero-day exploit abuses a few issues to escalate privileges. A crafted “msi” installer, when installed, causes msiexec.exe to write to a user controlled directory without checking for junctions or symlinks. msiexec.exe also fails to impersonate the low privileged user when doing so. This allows the attacker to trick msiexec.exe into altering the permissions of any file on the system. The zero-day exploit uses this trick to change the permissions on a service binary, overwrites the binary, and then starts the service to obtain SYSTEM privileges.

This issue has reportedly been exploited quite widely across multiple sectors in a variety of countries. At the time of writing, the issue remains unfixed so there is little reason to expect exploitation to abate.

Affected products

An official affected product list has not yet been published. However, CVE-2021-41379 is known to affect:

  • Windows 7 / 8.1 / 10 / 11
  • Windows Server 2008 / 2012 / 2016 / 2019 / 2022

Rapid7 has successfully tested this new variant on newer Windows versions, but has had less success on older Windows. However, that does not directly rule them out as they might simply require a special twist. At this stage, it is probably safe to assume the affected versions are similar.

Rapid7 analysis

At the time of publication, this zero-day exploit will be almost two weeks old. However, there are only scant, or frankly incorrect, details regarding how the exploit actually works. As such, this analysis is going to focus on the mechanics of the attack, and less on the specific bits of code within msiexec.exe / msi.dll that allow this behavior. At this stage of exploitation in the wild, an attacker/defender-oriented analysis is worth more than a vulnerability-hunter oriented analysis.

Successful exploitation of this issue happens in four parts:

Generation of an MSI that will trigger bad behavior.
Preparing a directory for MSI installation.
Inducing an error state.
Racing to introduce a junction and a symlink to trick msiexec.exe to modify the attacker specified file.

We’ll examine each of these four sections and then discuss specifically how Naceri’s InstallerFileTakeOver exploit pops a SYSTEM terminal.

Generating an MSI

The first step of this attack is generating an MSI. As Naceri noted in their write-up, a number of anti-virus products are flagging the MSI dropped by their exploit. While that certainly catches use of one exploit in the wild, you’ll see it’s trivial to generate a new MSI.

test_pkg_vt

Naceri provided a very helpful hint when they shared a .aip file in their repository. This file is used by Advanced Installer to generate installers. To generate your own, follow the simple layout of:

- Application Folder/
    - Some exe
    - Directory/ 
	- Some exe

Trial and error showed that additional files or different file types elicited different behaviors from msiexec.exe. As such, sticking with this simple layout is preferable. To generate the MSI for this analysis, the binary of choice was calc.exe.

new_msi.png

To understand later analysis, it’s important to note that the directory structure created by this MSI is:

- Application Folder/
	- teeswift.jpg (calc.exe)
	- shakeitoff/
		- lockfile.jpg (calc.exe)

Using meld, we can quickly visualize the minor changes between Nicera’s .aip and ours:

installer_compare

The changes are fairly minor. But the msi we generate isn’t detected by any AV on VirusTotal.

new_msi_vt

The MSI, as generated, produces a specific behavior that we’ll be able to exploit. But before we get to that behavior, we have to lay some groundwork.

Preparing the Install Directory

The exploit uses MsiInstallProductA to install the MSI. MsiInstallProductA is called using, at least, two properties:

  • ACTION=ADMIN
  • TARGETDIR=

The first property, ACTION=ADMIN instructs the Windows Installer to perform an administrative installation. The second property informs the installer where to install the MSI’s files. For this attack, it’s important to induce an error state that prevents the installer from running correctly. We achieve this first by creating the entire directory structure and then telling the installer to install in the created location. In our proof of concept, the directory structure creation function looks like this:

bool Exploit::create_temp_files()
{
    std::cout << "[+] Create the temp directory structure we'll install into" << std::endl;
    if (!std::filesystem::create_directories(m_tmp_base_path + m_tmp_inner_path))
    {
        return false;
    }

    if (!std::filesystem::create_directories(m_tmp_inner_tmp))
    {
        return false;
    }

    std::ofstream teeswift(m_tmp_base_path + m_tmp_outter_file);
    if (!teeswift.is_open())
    {
        return false;
    }
    teeswift.close();

    std::ofstream lockfile(m_tmp_base_path + m_tmp_inner_path + "\\" + m_tmp_lock_file);
    if (!lockfile.is_open())
    {
        return false;
    }
    lockfile.close();
    return true;
}

And the install function is called like so (note that REBOOT=ReallySuppress is just to ensure the MSI doesn’t trigger a reboot):

    bool install_msi(const std::string& p_msi_path, const std::string& p_install_path)
    {
        MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

        std::string properties("ACTION=ADMIN REBOOT=ReallySuppress TARGETDIR=");
        properties.append(p_install_path);
        std::cout << "[+] MSI install: " << properties << " " << p_msi_path << std::endl;
        int result = MsiInstallProductA(p_msi_path.c_str(), properties.c_str());
        std::cout << "[+] MsiInstallProductA return value: " << result << std::endl;
        return (result == 1603);
    }

However, the exploit does not immediately call MsiInstallProductA after setting up the install directory. The attacker first needs to take steps to induce the error state.

Inducing the Error State

The attack requires the MSI installation to fail. The attacker can ensure that happens by holding a handle open to one of the files created in the previous step. The installer won’t be able to access the file since the attacker is holding it open. The specific error induced should be 1603.

In our proof of concept, we launch a thread before calling MsiInstallProductA and the first thing the thread does is grabs shakeitoff\lockfile.jpg:

    std::cout << "[+] Grabbing handle to lock " << m_tmp_base_path + m_tmp_inner_path + "\\" + m_tmp_lock_file << std::endl;
    m_lock_handle = CreateFileA((m_tmp_base_path + m_tmp_inner_path + "\\" + m_tmp_lock_file).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, 0);
    if (m_lock_handle == INVALID_HANDLE_VALUE)
    {
        std::cerr << "[-] Failed to get a handle to the rbf file" << std::endl;
        return;
    }

That’s sufficient to induce the error state. In procmon the initial error looks like so:

proc_mon_error
The result of the error state is that the msiexec.exe drops rollback files (.rbf) into the \shakeitoff directory we created in the previous step. Note below that msiexec.exe is writing to the directory as SYSTEM.

system

Now that msiexec.exe is writing to the directory of our choosing, it’s a race to implement redirection logic.

Racing to file manipulation

msiexec.exe will try to write a couple of rbf files to the shakeitoff directory and alter file permissions on them. If the attacker can overwrite the expected file path with a junction and symlink, then they can trick msiexec.exe into modifying a file that the symlink points to.

There is a fair amount of file manipulation in the proof of concept, but the most important steps are:

  • Create a new directory (\cb_directory)
  • Turn \cb_directory\ into a directory junction that points to \BaseNamedObjects\Restricted
  • Move \shakeitoff\ to another name
  • Move \cb_directory\ to \shakeitoff
  • Drop a symlink for the expected .rbf in \BaseNamedObjects\Restricted\ that points to the attacker chosen file.
  • That’s it. msiexec.c will write through the symlink.

As mentioned, there are a lot more moving parts, but here are some of the highlights pulled out of procmon. The first is renaming the directory junction to shakeitoff:

junction_rename

Then msiexec.exe applying a DACL to the targeted file (C:\Program Files(x86)\lol) that allows the attacker to modify it.

dacl

And finally, the attacker modifying the file.

user_write

That’s the whole attack! The attacker is free to overwrite or introduce arbitrary files anywhere on the system.

Popping SYSTEM Shell

Naceri’s exploit pops a shell for the attacker. Their exploit does everything we discussed above except they specifically overwrite a program named elevation_service.exe that is part of Microsoft Edge’s update mechanism. After overwriting the executable, the exploit starts the MicrosoftEdgeElevationService which executes their code with SYSTEM privileges. They then have some additional logic to pop a shell for the user.

Indicators of Compromise

As mentioned in the Rapid7 blog, this attack generates event logs that defenders can look for to determine if they’ve been exposed to this attack. Specifically, event ID 1033 will indicate that MsiInstaller failed with error status 1603. That is the error that is required for the attack to be performed (e.g. msiexec.exe fails because the attacker is holding open a required file).

1033

Similarly, Event ID 11306 will indicate which file triggered the error state. That may help track down other malicious files.

11306

Defenders can also check the signature of elevation_service.exe to detect Naceri’s exploit. The binary should be signed by Microsoft Corporation. Naceri’s exploit overwrites the binary and therefore removes any type of signature.

There is little else to do until Microsoft puts out guidance or a patch. Unfortunately, it seems that defenders cannot rely on AV to detect this attack. While Naceri’s exploit gets flagged by Windows Defender and others AV, our simple proof of concept does not. Which indicates that these services are flagging the exploit and not the behavior.

Guidance

Monitor system event logs for signs of exploitation. Continue monitoring Microsoft bulletins for a potential fix or remediation guidance. Otherwise, practice good network hygiene and remember that attackers can only use this atack once they have a presence within your network.