Windows Fundamentals · beginner · ~11 min
**What you will learn** - Explain how Windows identifies every account with a **SID** (Security Identifier) and why names are only labels on top of it. - Read a SID: distinguish the domain/machine portion from the trailing **RID**, and recognise well-known SIDs like `S-1-5-18` (SYSTEM) and RID **500** (built-in Administrator). - Tell **local** accounts (SAM database) apart from **domain** accounts (Active Directory), and know which built-in groups grant real power. - Enumerate group membership safely with `whoami`, `net`, and PowerShell **on a machine you own or are authorized to test**. - Apply the defensive view: which memberships to monitor, what to log, and how to detect suspicious changes to privileged groups.
Security objective. The asset protected here is administrative control of a Windows machine or domain — the ability to read any file, change any setting, or move to other computers. The threat is privilege escalation and lateral movement: an attacker (or a curious insider) who lands as a low-privileged user and tries to reach SYSTEM on one host or Domain Admin across the network. In this lesson you learn to read Windows identity correctly so you can both understand how escalation targets are chosen and, more importantly, detect and prevent unauthorized membership in high-value groups.
This lesson has no prerequisites — it is a foundation for the Windows and Active Directory tracks. Everything else (NTFS permissions, tokens, Kerberos) is built on the idea introduced here: Windows makes access-control decisions about SIDs, not names.
A SID looks like S-1-5-21-3623811015-3361044348-30300820-1013. Windows stores permissions against that string. If an administrator renames Administrator to Frank, the SID is unchanged, so the account keeps every permission it had. This single fact — identity is the SID, not the label — is why defenders track SIDs in logs and why the name of an account tells you almost nothing about its power.
The next lesson, NTFS permissions and ACLs (win-ntfs-permissions), shows how those SIDs appear inside file and folder access-control lists.
In authorized professional work this knowledge sits on both sides of the fence:
Administrators and Domain Admins, and should they be?" Group-membership drift — an unexpected account added to a privileged group — is one of the highest-signal indicators of compromise. Monitoring is done by SID because renaming an account does not change it.Because the same enumeration commands are used to defend and to assess, the professional difference is authorization and intent: you run them only on systems you own or have explicit written permission to test, and you prefer prevention and detection over exploitation.
Each concept below is taught on its own: a definition, a plain explanation, how it works, when it applies, and a pitfall.
S-1-5-21-…-1104."S-1-5-21-A-B-C-500 as: S = it is a SID; 1 = revision; 5 = the NT Authority; 21-A-B-C = the machine or domain identifier; 500 = the RID, which picks the specific account within that machine/domain.Administrators.Administrator does nothing to its power because RID 500 is unchanged. "We renamed the admin account" is weak security by itself.S-1-5-18 is SYSTEM (the operating system's own account). Locally it is more powerful than Administrator. S-1-5-19/S-1-5-20 are LocalService / NetworkService (limited service accounts). S-1-1-0 is Everyone.Administrator only controls its own PC. A Domain Admins member controls (by default) every machine in the domain — the crown jewels.MACHINE\Administrator (local) with DOMAIN\Administrator (domain). They are different principals with different SIDs and very different blast radius.Administrators instantly makes it an admin — no reboot needed for new logons.Backup Operators can read/write protected files and is a classic overlooked escalation path.THREAT MODEL — Windows identity on one host (authorized lab)
[ Low-priv user login ] <-- entry point / foothold
| builds access token (user SID + group SIDs)
v
+-------------------------------------------------+
| TRUST BOUNDARY: standard user -> local admin |
| crossed by: membership in Administrators, |
| abusing a SYSTEM service, |
| weak service/file permissions |
+-------------------------------------------------+
|
v
[ SYSTEM S-1-5-18 ] = full local control <-- asset (local)
| reuse creds / harvest domain token
v
+-------------------------------------------------+
| TRUST BOUNDARY: one host -> the domain |
| crossed by: Domain Admin credentials found on |
| the host, lateral movement |
+-------------------------------------------------+
v
[ Domain Admins ] = control of every domain host <-- asset (domain)
Assets: local admin/SYSTEM control; domain-wide control.
Entry: an authenticated low-priv session.
Boundaries: standard-user->admin, and single-host->domain.
Knowledge check
Domain Admins membership? (Control of every machine in the domain.)The core built-in commands are read-only when used as shown. Run them only on a machine you own or are authorized to test.
whoami /user # your account name + your SID
whoami /groups # every group SID in your access token
whoami /priv # privileges your token currently holds
net user # list local user accounts (SAM)
net localgroup # list local groups
net localgroup Administrators # who is a local administrator
PowerShell (Windows 10/11, Server 2016+) gives structured output:
Get-LocalUser # local accounts as objects
Get-LocalGroupMember Administrators # members of the local admins group
Annotated: whoami /user prints one line ending in the SID; the final -500 (if present) means the built-in Administrator. Get-LocalGroupMember returns each member's Name, SID, and PrincipalSource (Local vs ActiveDirectory) — the SID column is the one to record for logs, because it survives renames.
Windows access control is built on security principals — users, groups, and computers. Each principal is identified by a SID.
A Security Identifier (SID) is the real identity of an account, for example S-1-5-21-…-1001.
Names are only labels. Permissions are stored against the SID, not the name.
The last part of a SID is the RID (Relative Identifier). It distinguishes one account from another. The built-in Administrator is always RID 500.
S-1-5-18) — the operating system itself; more powerful than Administrator locally.Enumerating who is in Administrators and Domain Admins, and which accounts are local versus domain, is step one of Windows post-exploitation.
The goal of most escalation is to become SYSTEM locally, or Domain Admin in the domain.
You ultimately track SIDs, not names, because a renamed account keeps its original SID.
The example is a small, read-only PowerShell audit that any defender or authorized tester can run. It follows an INSECURE-STATE → SECURE-STATE → VERIFY shape: first it reveals a risky configuration, then shows the remediation, then re-checks that the fix took effect. No exploitation is performed.
This represents the starting state of a lab VM where an ordinary account was wrongly granted local admin. Reproduce it only inside a throwaway VM you own.
# LAB SETUP (throwaway VM only). Creates the risky state to detect.
# 'labuser' is a stand-in low-priv account that should NOT be admin.
New-LocalUser -Name 'labuser' -Password (Read-Host -AsSecureString 'pw') -FullName 'Lab User'
Add-LocalGroupMember -Group 'Administrators' -Member 'labuser' # <-- the misconfiguration
# Inventory: who really holds local admin, with SIDs and source.
Get-LocalGroupMember -Group 'Administrators' |
Select-Object Name, SID, PrincipalSource, ObjectClass |
Format-Table -AutoSize
# Flag any *user* (not a group/service) that is a local admin.
Get-LocalGroupMember -Group 'Administrators' |
Where-Object { $_.ObjectClass -eq 'User' -and $_.PrincipalSource -eq 'Local' }
# Remediation: revoke the unnecessary admin rights. Least privilege.
Remove-LocalGroupMember -Group 'Administrators' -Member 'labuser'
# The audit must now REJECT 'labuser' as admin (returns nothing) ...
$stillAdmin = Get-LocalGroupMember -Group 'Administrators' |
Where-Object { $_.Name -like '*labuser' }
if ($stillAdmin) { Write-Host 'FAIL: labuser still admin' -ForegroundColor Red }
else { Write-Host 'PASS: labuser is not a local admin' -ForegroundColor Green }
# ... and must still ACCEPT the legitimate built-in Administrator (RID 500).
Get-LocalGroupMember -Group 'Administrators' |
Where-Object { $_.SID -like 'S-1-5-*-500' } |
ForEach-Object { Write-Host "PASS: RID-500 admin present -> $($_.SID)" -ForegroundColor Green }
Expected output. Step 2 lists the built-in Administrator and labuser (the problem). After step 3, step 4 prints PASS: labuser is not a local admin and PASS: RID-500 admin present -> S-1-5-21-…-500. The verification proves the remediation removed the bad membership while keeping the legitimate one.
Remove-LocalUser -Name 'labuser' # delete the stand-in account
Then revert the VM snapshot so the environment is clean for the next exercise.
Walking through the audit-and-fix example:
New-LocalUser + Add-LocalGroupMember — lab setup only. This deliberately creates the insecure state: an ordinary account (labuser) placed in Administrators. In real defensive work you never create this; you find it.Get-LocalGroupMember -Group 'Administrators' — reads the members of the local admins group as objects. Piping to Select-Object Name, SID, PrincipalSource, ObjectClass surfaces the four facts that matter: the label, the immutable identity, whether it is Local or ActiveDirectory, and whether it is a User or Group.Where-Object filter — narrows to local user admins. Groups in Administrators are often expected (e.g. Domain Admins); a lone local user is the classic drift to flag.Remove-LocalGroupMember — the remediation. It revokes membership; the account still exists but no longer inherits admin rights into new tokens.$stillAdmin should now be empty, proving the bad state is rejected. The second check confirms the RID-500 account is still present, proving the fix did not over-correct and remove legitimate access.| Step | Admins group contains | Audit verdict |
|---|---|---|
| After setup | Administrator (RID 500), labuser | FAIL — extra local-user admin |
| After remediation | Administrator (RID 500) | PASS — only expected admins |
| RID-500 check | Administrator present | PASS — legitimate access intact |
The SID column is the load-bearing detail: even if labuser were later renamed, matching on its SID would still identify it in logs.
Administrator to Frank, so attackers can't find the admin." → WHY wrong: power lives in RID 500/the SID, not the name; enumeration finds RID 500 regardless of label. → CORRECTED: disable or tightly control the built-in account and enforce least privilege; treat renaming as cosmetic, not a control. → Recognise/prevent: audit by SID (S-1-5-*-500), not by name.MACHINE\Administrator and DOMAIN\Administrator as the same account. → WHY wrong: they are different principals with different SIDs and vastly different blast radius (one host vs the whole domain). → CORRECTED: always note the scope/prefix and the PrincipalSource. → Recognise/prevent: check the SID prefix — domain SIDs share the domain identifier; local SIDs share the machine identifier.S-1-5-18) outranks Administrator, and services run as SYSTEM. → CORRECTED: monitor what runs as SYSTEM and protect service configurations. → Recognise/prevent: inventory services and their run-as identity.Administrators and Domain Admins. → WHY wrong: groups like Backup Operators, Account Operators, and Server Operators grant near-admin capability. → CORRECTED: include all sensitive built-in groups in reviews. → Recognise/prevent: keep a documented list of privileged groups and audit each.Get-LocalGroupMember fails with a translation error (a member SID cannot be resolved to a name). This is common when a domain account was added then deleted, or the DC is unreachable. Fall back to net localgroup Administrators, which shows the raw entries, and record the SID rather than the name.net user shows fewer accounts than expected. net user lists SAM (local) accounts only; domain accounts will not appear. Confirm whether the box is domain-joined with systeminfo | findstr /i domain before concluding an account is "missing."whoami /groups doesn't show a group you just added yourself to. Group membership is baked into the token at logon. Log off and back on (or start a new session) to get a fresh token, then re-check.Get-Local* cmdlets are unavailable. They ship in the Microsoft.PowerShell.LocalAccounts module (Windows 10/Server 2016+). On older systems use net commands instead.hostname)? Am I looking at local or domain scope (PrincipalSource)? Is the account identified by a name that could have been renamed — should I be matching on SID? Do I actually have permission to be running this here?Security & safety: detection and logging for identity changes.
The highest-value defensive signal in this topic is a change to privileged group membership. Configure auditing and monitor these Windows Security events:
Administrators).Domain Admins).What to log for each event: timestamp (UTC), the actor SID and account performing the change, the target account SID that was added/removed, the group SID affected, the source host, the result (success/failure), and a correlation id to tie the change to a session or ticket. Logging the SID — not just the name — is essential because renames don't change it.
What to NEVER log: passwords or password hashes, Kerberos tickets or NTLM secrets, session tokens/cookies, private keys, or unnecessary personal data. An account audit needs identities and decisions, not credentials.
Events that signal abuse: a new or unexpected account appearing in Administrators/Domain Admins; a disabled privileged account suddenly re-enabled; group changes outside a change-management window; a burst of 4672 special-privilege logons from an unusual host.
How false positives arise: legitimate onboarding, break-glass admin use, backup software running as a service account, or IT automation that manages groups. Reduce noise by allow-listing known automation SIDs and correlating changes with approved change tickets — investigate the unexplained deltas, not every change.
Authorized real-world use case. A security team runs a weekly privileged-access review: an automated read-only job enumerates Administrators on every server and Domain Admins in the domain, records each member's SID and PrincipalSource, and diffs it against last week's baseline. Any new member triggers a ticket asking "who approved this, and is it still needed?" This is exactly the audit pattern from the code example, scaled up.
Professional best-practice habits
| Beginner | Advanced | |
|---|---|---|
| Scope | One host you own; whoami, net localgroup |
Whole domain; automated, scheduled baselining |
| Focus | Read SIDs, find local admins | Detect drift, tier admin access, alert in a SIEM |
| Output | A manual inventory | Diffed reports + tickets + dashboards |
Always operate within written authorization; the same commands are defensive when run on assets you own and unauthorized when run elsewhere.
All tasks are lab-only: use a Windows VM you own or a provided training range. Never run against systems outside your written scope.
Authorization checklist (complete before any task):
whoami /user. Identify the machine/domain portion and the RID.Get-LocalGroupMember -Group 'Administrators' (or net localgroup Administrators). Record each member's Name and SID.PrincipalSource.-500 and -501.Administrators membership to a baseline file. Add a stand-in account to the group (lab state), then re-enumerate and diff against the baseline to flag the new member. Include the SID in your report.Compare-Object compares two membership lists.Administrators, Backup Operators, and (if domain-joined in your lab) Domain Admins. For each member record Name, SID, PrincipalSource, and whether it is expected. Map which Security event IDs would fire if someone were added to each group.S-1-5-18 = SYSTEM, which outranks Administrator locally.MACHINE\Administrator ≠ DOMAIN\Administrator.Administrators, Domain Admins, and the often-forgotten Backup Operators/Account Operators — are what to inventory and monitor.whoami /user, whoami /groups, net localgroup Administrators, Get-LocalGroupMember.