by Mitja Kolsek, the 0patch Team
[Update 2/9/2021: February 2021 Windows Updates included an official fix for this vulnerability and assigned it CVE-2021-1727. According to our guidelines, this micropatch is no longer FREE, but part of a PRO subscription.]
On December 26, security researcher Abdelhamid Naceri published a blog post with a number of 0days in various security products and a local privilege escalation 0day in Windows Installer. We were mostly interested in the latter.
Abdelhamid provided a proof-of-concept (the GitHub repository is disabled at the time of this writing) which allowed us to quickly reproduce the issue on Windows 10 v2004, but we were having difficulties reproducing it on other Windows 10 versions and older Windows systems. It took us a while to troubleshoot the underlying problem with reproduction and come January 2021 Patch Tuesday, it turned out this vulnerability wasn't patched by Microsoft. Having successfully reproduced the issue by then on all Windows versions back to Windows 7, we decided to create a micropatch to protect Windows users waiting for the official patch. (The micropatch would also be the only available patch for Windows 7 without Extended Security Updates (ESU), or Windows 7 with only the first year of ESU.)
The Vulnerability
This vulnerability is a bypass of Microsoft's fix for CVE-2020-16902 (described by Abdelhamid in detail here), which was itself a bypass of Microsoft's fixes for CVE-2020-0814 and CVE-2020-1302 (also found by Abdelhamid), both of which were a bypass of Microsoft's fix for CVE-2019-1415 (found by SandboxEscaper and described here).
Confusing? Well, some things aren't easy to fix, and Windows Installer is a pretty complex beast that can break a leg if you fix its arm, and then break its tail when you fix the leg. So you want to be careful when fixing.
The core of this vulnerability, and all others listed above, is in tricking Windows Installer into using attacker's own rollback script (a *.rbs file) instead of the rollback script created by msiexec.exe during the installation. See, when installing an MSI package, Windows Installer gradually builds up a rollback script in case the installation should fail at some point, and all changes made up to that point would have to be reverted. But if a local non-admin attacker manages to replace that rollback script with one that "reverts" some system registry value such that it will point to attacker's executable..., well, we get a local privilege escalation.
The proof-of-concept is using a rollback script that changes the value of HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Fax\ImagePath to c:\Windows\temp\asmae.exe, which results in the Fax Service using attacker's asmae.exe when the service is launched. This service was used because any user is allowed to launch it, and it's running as Local System.
As far as this particular 0day goes, Microsoft's fix - which it bypasses - was attempting to block the planting of a malicious rollback script by first determining if it was safe to use the default c:\Config.Msi folder for storing the rollback script, and if not safe, using a different folder, c:\Windows\Installer\Config.Msi, instead. Abdelhamid noticed a logical flaw in this fix, forced Windows Installer to keep using c:\Config.Msi, and then performed the same steps as in his CVE-2020-16902 proof-of-concept to elevate himself to Local System.
Our Micropatch
We confess we do not understand why Microsoft decided to add more complexity with their fix for CVE-2020-16902 when they could have just unconditionally use the c:\Windows\Installer\Config.Msi folder for the callback script and completely avoid numerous attack vectors that c:\Config.Msi is exposed to. Maybe they didn't want to clutter the Windows folder.
Be it as it may, we decided that if Microsoft deemed c:\Windows\Installer\Config.Msi folder to be acceptable for hosting the rollback script under some attacker-controllable conditions, it shouldn't break anything if we forced Windows Installer to always use it for rollback scripts. It is running as Local System so permissions shouldn't be a problem, and a local attacker can't touch this folder in any relevant way.
And here it is, the single-instruction micropatch that fixes this 0day by changing the logic of Microsoft's fix for CVE-2020-16902 such that it now always decides to use c:\Windows\Installer\Config.Msi folder:
MODULE_PATH "..\Affected_Modules\msi.dll_5.0.19041.746_64bit\msi.dll"
PATCH_ID 538
PATCH_FORMAT_VER 2
VULN_ID 6912
PLATFORM win64
patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0xc2bcc
N_ORIGINALBYTES 5
JUMPOVERBYTES 0
code_start
mov ebx,1 ; use C:\Windows\installer\Config.Msi instead of C:\Config.Msi
code_end
patchlet_end
We created this micropatch for the following Windows versions:
- Windows 10 v20H2, 32bit and 64bit, updated with January 2021 updates
- Windows 10 v2004, 32bit and 64bit, updated with January 2021 updates
- Windows 10 v1909, 32bit and 64bit, updated with January 2021 updates
- Windows 7, 32bit and 64bit, with ESU, updated with January 2021 updates
- Windows 7, 32bit and 64bit, without ESU, updated with January 2020 updates
What about Windows Servers? Fortunately, Windows Servers have a default security policy preventing non-admin users from launching any installations, which successfully prevents exploitation of this vulnerability. Nevertheless, our Windows 7 micropatches will also work on Windows Server 2008 R2, updated to January 2020 (without ESU), or to January 2021 (with ESU) should their system configuration allow non-admin installations.