Windows Fundamentals · intermediate · ~11 min

The Windows privilege model: UAC and tokens

- Explain how a Windows **access token** (SID + group SIDs + privileges) decides what a process may do - Identify the high-value privileges (`SeImpersonatePrivilege`, `SeDebugPrivilege`, `SeBackupPrivilege`) and *why* they matter - Describe **integrity levels** and **UAC** as defence-in-depth layers (and their limits) - Apply **least privilege** to service accounts and detect risky privilege assignments - Recognize the difference between a **primary** and an **impersonation** token

Overview

On Windows, what a process may do is decided by its access token, not merely by the username behind it. The token is the unit of authorization — understanding it explains both how privilege-escalation findings work and, more importantly, how to prevent and detect them.

This lesson builds on Users and groups: those accounts and groups become SIDs inside a token. It's an intermediate lesson because the payoff is defensive judgement — knowing why a low-privileged service account holding one extra privilege can be equivalent to full SYSTEM, and how to stop that.

Everything here is for hosts you own or are authorized to assess.

Why it matters

Most Windows privilege-escalation on real engagements isn't a memory-corruption exploit — it's abuse of an over-privileged token: a service account that shouldn't have SeImpersonatePrivilege, or a backup operator role handed out too widely. Defenders who understand the token model can remove those privileges before they're abused and can spot the event-log signs when someone tries.

It's also foundational for hardening: least privilege on Windows literally means shrinking tokens.

Core concepts

1. The access token

Definition. When you log on, Windows builds a token attached to every process you start. It carries:

  • Your SID (a unique security identifier for the account),
  • your group SIDs,
  • a set of privileges (named rights like SeDebugPrivilege).

Windows checks the token, not the name, on every security decision.

2. Privileges that are keys to SYSTEM

A few privileges are effectively equivalent to full control, which is why they belong only on tightly-controlled accounts:

Privilege Why it's powerful Who should rarely have it
SeImpersonatePrivilege Can impersonate other tokens (basis of "potato" techniques) General service accounts
SeDebugPrivilege Open any process, including SYSTEM's Non-admin users
SeBackupPrivilege Read any file (e.g. the SAM/NTDS credential stores) Broad user groups

Dangerous assumption: "it's just a low-privileged service account, so it's safe." If it holds SeImpersonatePrivilege, it may be one step from SYSTEM.

3. Integrity levels and UAC (defence in depth)

Every process also has an integrity level: Low, Medium, High, System. A Medium-integrity process can't modify a High-integrity one — a containment layer.

UAC (User Account Control) is why an admin runs at Medium integrity by default and must elevate (consent) to get a High-integrity token. It's a valuable friction/defence layer, but not a hard security boundary — treat "admin = trusted" and design least privilege accordingly.

System   (SYSTEM services)          highest
High     (elevated admin)   <-- UAC elevation gets you here
Medium   (normal user / un-elevated admin)
Low      (sandboxed, e.g. browser tab)   lowest

4. Primary vs impersonation tokens

A primary token is what a process runs with. An impersonation token lets a thread temporarily act as another security context (used legitimately by services). Impersonation is the mechanism SeImpersonatePrivilege abuses — which is why granting it casually is dangerous.

Knowledge check:

  1. Why does Windows check the token instead of the username on each action?
  2. A service account holds SeBackupPrivilege. What sensitive files could it read, and why is that risky?
  3. Is UAC a hard security boundary? What should you assume instead?

Syntax notes

Inspect (don't abuse) token privileges on a host you own:

whoami /priv          # lists the current token's privileges + state (Enabled/Disabled)
whoami /groups        # group SIDs in the token
whoami /all           # SID, groups, and privileges together

In PowerShell, Get-LocalGroupMember and (for services) checking each service's logon account tell you which accounts carry which rights.

Lesson

Windows decides what a process may do from its access token, not just from its username.

Access tokens

When you log on, Windows builds a token. The token carries:

  • Your SID (security identifier — a unique ID for your account).
  • Your group SIDs.
  • A set of privileges (named rights such as SeDebugPrivilege, SeImpersonatePrivilege, and SeBackupPrivilege).

Every process you start carries a copy of this token.

Some privileges are effectively keys to the SYSTEM account:

  • SeImpersonatePrivilege → enables "potato" attacks that impersonate SYSTEM. Common on service accounts.
  • SeBackupPrivilege → read any file, for example the SAM or NTDS database.
  • SeDebugPrivilege → open any process, including SYSTEM's.

Integrity levels

Processes also have an integrity level: Low, Medium, High, or System.

This is a defence-in-depth layer. A Medium-integrity process cannot modify a High-integrity one, even when both run as the same user. (Browsers use this idea to run sandboxed tabs at Low integrity.)

UAC

User Account Control (UAC) gives admins a standard (Medium) token by default. The elevated (High) token is only used after a consent prompt.

UAC is a convenience and a speed-bump, not a strong security boundary — Microsoft states this directly, and many bypasses exist.

So report a UAC bypass as escalation within admin, not as crossing a trust boundary.

Why it matters

Windows privilege escalation is often about token privileges. The classic line of reasoning is: "I'm a low-privilege service account, but I hold SeImpersonatePrivilege, so I can become SYSTEM."

Enumerating whoami /priv is a first move.

Code examples

A defensive audit: on a host you own, list the privileges the current token holds and flag the dangerous ones, then show the hardening action (remove an unneeded privilege from an account via Group Policy / secpol.msc).

# audit-token-privileges.ps1 — run on a host you own.
# Show the current token's privileges and highlight high-risk ones.
$danger = 'SeImpersonatePrivilege','SeDebugPrivilege','SeBackupPrivilege',
          'SeRestorePrivilege','SeTakeOwnershipPrivilege','SeTcbPrivilege'

$priv = whoami /priv | Select-String 'Se\w+Privilege' |
        ForEach-Object { ($_ -split '\s+')[0] }

foreach ($p in $priv) {
  $flag = if ($danger -contains $p) { 'HIGH-RISK' } else { 'ok' }
  '{0,-28} {1}' -f $p, $flag
}
# Hardening: remove a privilege from an account via User Rights Assignment
# (secpol.msc -> Local Policies -> User Rights Assignment), granting it ONLY
# to accounts that truly need it (least privilege).

What it does. It reads the current token's privileges (whoami /priv), then labels any that appear in the high-risk list. The comment points to the fix: privileges are assigned through User Rights Assignment, so hardening means auditing who holds the dangerous ones and removing them from accounts that don't need them.

Expected output. A list of privilege names each tagged ok or HIGH-RISK — a quick, defensible inventory you can act on.

Line by line

Step What happens Why it matters
$danger = … Defines the high-risk privilege set The things to hunt for
whoami /priv | Select-String … Extracts privilege names from the token Reads the actual authorization state
foreach … if ($danger -contains $p) Tags each as HIGH-RISK or ok Turns raw data into a finding
comment: User Rights Assignment Points to the remediation Least privilege = remove unneeded rights

The habit: inventory the token → flag the dangerous privileges → remove the ones that aren't justified.

Common mistakes

Mistake 1 — "low-priv account = safe". Wrong: ignoring a service account because it isn't an admin. Why wrong: one privilege like SeImpersonatePrivilege can bridge to SYSTEM. Fix: audit privileges, not just group membership; remove what isn't needed.

Mistake 2 — treating UAC as a wall. Wrong: assuming a Medium-integrity admin can't reach High. Why wrong: UAC is a consent/friction layer, not a hard boundary. Fix: apply least privilege and monitoring; don't rely on UAC alone.

Mistake 3 — broad backup/debug rights. Wrong: granting SeBackupPrivilege/SeDebugPrivilege to wide groups for convenience. Why wrong: those rights can read credential stores or any process memory. Fix: grant them only to specific, controlled accounts; review regularly.

Recognize it: if you can't justify why an account holds a dangerous privilege, that's the finding.

Debugging tips

  • whoami /priv shows a privilege as Disabled — it's still held; many privileges are enabled on demand, so "Disabled" is not "safe."
  • An action fails with Access is denied despite being admin — you're probably in a Medium-integrity (un-elevated) process; relaunch elevated.
  • Not sure which account runs a service — check its logon account (Get-CimInstance Win32_Service | Select Name,StartName); that account's token is what matters.

Questions to ask: Which token is this action using? Which privileges does it hold (not just have enabled)? Is this account's privilege set justified by least privilege?

Memory safety

Security & safety — detection & hardening.

  • Harden: apply least privilege via User Rights Assignment; keep SeImpersonate/SeDebug/SeBackup off general service accounts; run services as low-privileged, purpose-built accounts (or virtual/gMSA accounts).
  • Detect: monitor security events for privilege assignment and special-privileges logon (e.g. event 4672 "special privileges assigned to new logon"), and sensitive-privilege use (4673/4674). A service account suddenly logging on with SYSTEM-equivalent privileges is a signal.
  • Never log credential material even when auditing backup/debug rights.
  • False positives: admins and some legitimate services hold these rights — baseline the expected holders so alerts focus on the unexpected.

Real-world uses

  • Windows hardening / CIS benchmarks center on User Rights Assignment — i.e. shrinking tokens.
  • Blue teams alert on 4672/4673 to catch privilege abuse early.
  • Secure service design uses least-privileged or group-managed service accounts precisely to avoid dangerous privileges.

Beginner habits: read whoami /all; never grant a privilege "just to make it work." Advanced habits: enforce least privilege with tiered admin models and just-in-time elevation; monitor sensitive-privilege events centrally; prefer gMSA over static service accounts.

Practice tasks

Beginner 1 — Read your token. Objective: on your own VM, run whoami /all and identify your SID, two group SIDs, and one privilege; say what that privilege allows. Concepts: tokens, SIDs, privileges.

Beginner 2 — Rank the danger. Objective: given SeImpersonatePrivilege, SeChangeNotifyPrivilege, and SeBackupPrivilege, rank them by risk and justify the top one in one sentence. Concepts: high-value privileges.

Intermediate 1 — Privilege audit script. Objective: adapt the audit script to flag high-risk privileges in the current token and print a count of how many are HIGH-RISK. Concepts: token inspection, defensive audit. Constraint: your own host.

Intermediate 2 — Detection mapping. Objective: for "a service account gains SYSTEM-equivalent privileges," name the Windows event id(s) a defender would watch and what a false positive might look like. Concepts: detection, event 4672/4673.

Challenge — Least-privilege service plan. Objective: for a fictional in-house service that only needs to read a folder and write a log, specify the account type and the exact privileges it should (and should not) hold, plus how you'd verify. Requirements: defensive; least privilege; no exploitation. Concepts: everything in this lesson.

Summary

  • A Windows access token (SID + group SIDs + privileges) — not the username — decides what a process may do.
  • SeImpersonatePrivilege, SeDebugPrivilege, SeBackupPrivilege are effectively keys to SYSTEM; keep them off general accounts.
  • Integrity levels and UAC are defence-in-depth layers, not hard boundaries — design least privilege anyway.
  • Harden via User Rights Assignment; detect abuse via events 4672/4673.
  • The defensive mindset: audit tokens, justify every dangerous privilege, remove the rest.

Next: continue into the privilege-escalation lessons, where these tokens are the thing attackers target and defenders lock down.