Internal Network & Active Directory · beginner · ~10 min
By the end of this lesson you will be able to: - Name the four core Active Directory (AD) object types — users, groups, computers, and organizational units (OUs) — and describe what each represents. - Explain what an **attribute** is and read the security-relevant attributes on a user object (`memberOf`, `description`, `servicePrincipalName`, `userAccountControl` flags, `pwdLastSet`). - Identify the **high-value groups** (Domain Admins, Enterprise Admins, and the "almost-admin" groups) that defenders must protect and attackers seek. - Explain **transitive (nested) group membership** and trace how a user inherits rights through a chain of nested groups. - Recognize **risky account flags** (SPN set, Kerberos pre-authentication disabled, password-never-expires) and explain why each is a misconfiguration worth auditing. - Perform **authorized, read-only enumeration** as reconnaissance, apply the ethics/authorization rules that govern it, and **verify** that a remediation actually removed a finding.
Security objective. The asset you are learning to protect is the directory metadata inside Active Directory — the accounts, groups, machine records, and the attributes hanging off them. The threat is an attacker who has gained any authenticated foothold (a phished password, a weak service-account password) and now reads that metadata to find a path to privilege. By the end you will be able to detect the object-level misconfigurations that hand attackers that path — over-privileged accounts, dangerous flags, and secrets leaked into text fields — and prevent them before an incident.
In the prerequisite What is Active Directory? you learned that Active Directory is the central directory service most organizations use to manage who can log in and what they can touch. This lesson zooms in on the contents of that directory: the objects it stores.
Think of AD as a large, structured database. Almost everything in the environment is represented as an object: every employee account, every security group, every laptop and server, and the containers used to organize them. Each object is described by a set of named properties called attributes — much like rows and columns in a table, or fields in a struct.
Why does this matter for security? Because the directory is, by design, broadly readable. Any authenticated user — even a brand-new, unprivileged account — can query most objects and attributes. That means the first step of nearly every AD security assessment (and every real attack) is enumeration: listing objects and reading their attributes to build a map of the environment.
That map answers the questions that decide everything that follows:
description.From a defender's seat, the same enumeration is how you find and fix these problems before someone else exploits them. This lesson stays at the conceptual level — what the objects are and what to look for. The mechanics of querying AD over LDAP and the authentication protocols behind it (Kerberos and NTLM authentication) come in the next lessons.
Almost every AD attack path begins with object enumeration, which is exactly why defenders need to understand objects just as well as attackers do.
For attackers (in an authorized test): enumeration is reconnaissance that requires no exploitation. Reading attributes can hand over a privilege-escalation route on a plate — a service account with a weak password, an admin whose password never changes, or a literal credential typed into a description field. None of that requires firing a single exploit; it is just reading data the directory willingly returns.
For defenders: the same visibility is a gift. If you can enumerate your own directory, you can audit it: find over-privileged accounts, empty out leaked secrets, tighten group membership, and remove dangerous flags. Most catastrophic AD breaches trace back to a small misconfiguration that routine enumeration would have surfaced months earlier.
It also matters because AD is everywhere. The overwhelming majority of medium and large enterprises run Windows domains for identity. A single domain often governs thousands of accounts and machines, so one weak object can compromise the whole organization. Understanding objects is the foundation for the higher-level attacks and defenses you will study later (Kerberoasting, password spraying, AS-REP roasting, and attack-path analysis). Skipping it means treating those later techniques as magic instead of as the logical consequence of readable, misconfigured objects.
Active Directory stores everything as objects, and every object is described by attributes (named properties, like sAMAccountName or description). We will teach the four object types, then the groups and flags that carry the most security weight.
Definition. An AD object is a single entry in the directory representing a real-world thing — a person's account, a group, a machine, or a container.
The four you will meet most:
| Object | Represents | Why it matters |
|---|---|---|
| User | A login account (person or service) | Holds credentials, group memberships, and risky flags |
| Group | A collection that grants rights | Membership = privilege; nesting hides inherited rights |
| Computer | A domain-joined machine | Has its own account; some have local admin reach |
| OU (organizational unit) | A container for organizing objects | Used to apply Group Policy and delegate control |
How it works internally. Objects live in a hierarchical tree. OUs are containers that can hold users, computers, and other OUs. Each object has a unique distinguished name (DN) describing its full path, for example CN=Jane Doe,OU=Finance,DC=corp,DC=local. Attributes hang off each object as name/value pairs.
When OUs matter / when they don't. OUs are about organization and policy targeting — they are not security groups, and placing an account in an OU does not grant it a permission. A common beginner mistake is to confuse "in the Finance OU" with "a member of a Finance group." They are different concepts: OUs organize, groups authorize.
Domain: corp.local
|
+-- OU: Finance
| +-- User: jane.doe (attributes: sAMAccountName, memberOf, description, ...)
| +-- Computer: FIN-PC-07
|
+-- OU: IT
| +-- User: svc_backup (a SERVICE account that logs in as a program)
|
+-- Group: Domain Admins (most powerful group in the domain)
Knowledge check: In your own words, what is the difference between an OU and a group? (Answer: an OU is a container for organizing objects and targeting Group Policy; a group is what actually grants rights. Being in an OU never grants a permission by itself.)
Definition. Attributes are the fields that describe an object. Reading them is the whole point of enumeration.
Security-relevant attributes on a user include:
sAMAccountName — the short logon name (e.g., jane.doe).memberOf — the groups this account belongs to.description / info — free-text fields that sometimes contain passwords or hints (a real and common leak).servicePrincipalName (SPN) — present on accounts that run services; an SPN makes an account a Kerberoasting target.userAccountControl — a bitfield holding flags like password never expires and do not require Kerberos pre-authentication.lastLogon / pwdLastSet — timing data that reveals stale or rarely changed accounts.Pitfall. Treating description as harmless. Admins frequently type onboarding notes or even passwords there because it is convenient — and every authenticated user can read it.
Knowledge check: Which single attribute would you read first to find out whether an account is over-privileged? (Answer: memberOf — but only once you resolve it transitively, because nested groups do not appear in the direct list.)
Definition. A group is an object that bundles rights. Add a user to the group and the user gains the group's permissions.
How nesting works. Groups can contain other groups, and membership is transitive: if Group A is a member of Group B, then every member of A effectively belongs to B and inherits B's rights. This is powerful and dangerous, because the inheritance can be several layers deep and is easy to overlook.
Domain Admins
^
| (member)
Helpdesk-Admins <-- a group, not a person
^
| (member)
jane.doe <-- inherits Domain Admins rights, even though she is
NOT listed directly in Domain Admins
When to use nesting: legitimate administration uses it to manage rights at scale (e.g., a regional admin group nested into a global one). When it bites: auditors who only check direct membership of Domain Admins miss users who are admins through a chain. Always resolve membership transitively.
Pitfall. Reporting "Domain Admins has 3 members" by reading the group's direct member list, when nesting actually grants the rights to dozens of accounts.
Knowledge check (predict the result): Given the diagram above, is jane.doe a Domain Admin? Why or why not? (Answer: yes, effectively — her membership in Helpdesk-Admins, which is nested into Domain Admins, grants her Domain Admin rights even though her name is not in the Domain Admins direct list.)
Definition. Groups whose members can take full or near-full control of the domain or forest.
Pitfall. Protecting only Domain Admins while leaving Backup Operators or DnsAdmins wide open. Defenders must treat the almost-admin groups as Tier-0 too.
Three conditions (mostly bits inside userAccountControl, plus the presence of an SPN) turn an ordinary account into an attack surface:
| Flag / attribute | What it means | Why it is risky |
|---|---|---|
| SPN is set | Account runs a Kerberos service | Enables Kerberoasting — its service ticket can be requested by any user and cracked offline |
Pre-authentication disabled (DONT_REQ_PREAUTH) |
Account skips Kerberos pre-auth | Enables AS-REP Roasting — a crackable hash returned without any password attempt |
| Password never expires | Password is set once, forever | A leaked or weak password stays valid indefinitely |
Pitfall. Assuming these flags are exotic. They are extremely common in real domains because they were set years ago "to make something work" and never revisited. Routine enumeration is how you find them.
Knowledge check (find the misconfiguration): A service account has an SPN, password never expires, and a 9-year-old pwdLastSet. Name two distinct risks. (Answer: (1) the SPN makes it Kerberoastable — any user can request its ticket and crack the password offline; (2) with password-never-expires and a 9-year-old password, that password is almost certainly weak by modern standards and has never rotated, so a crack yields long-lived access.)
Entry point Trust boundary Asset
----------- -------------- -----
Any authenticated user --> (low-priv account can --> Directory metadata
(phished/weak password) read most attributes) (memberships, SPNs,
flags, descriptions)
|
v misconfig found
Privilege escalation --> Domain Admins (game over)
The key insight: the trust boundary between "any user" and "reads sensitive metadata" is very thin. That is why minimizing what objects expose is a real control, not paranoia.
Knowledge check (authorization): Why must every technique below run only in an authorized lab? (Answer: even read-only enumeration of a directory you do not own or have written permission to test is unauthorized access under most computer-misuse laws and engagement rules — the read/write distinction does not make it legal.)
This is a concept lesson, so there is no programming syntax. Instead, learn the shape of an object and the naming conventions you will see constantly when reading AD data.
Object: user
DN: CN=svc_sql,OU=IT,DC=corp,DC=local <- full path (distinguished name)
Attributes (name : value):
sAMAccountName : svc_sql <- short logon name
memberOf : CN=Domain Admins,... <- transitive memberships count too
servicePrincipalName : MSSQLSvc/db01:1433 <- presence => Kerberoasting target
description : "DB svc - see vault" <- NEVER store secrets here
userAccountControl : 0x10200 <- bitfield holding account flags
Key conventions:
DC = domain component, OU = organizational unit, CN = common name.sAMAccountName is the everyday logon name; computer accounts end in $ (e.g., FIN-PC-07$).memberOf lists groups, but to get the true privilege you must resolve nested groups transitively.userAccountControl is a number where individual bits are flags; tools decode it for you into readable names like PASSWORD_NEVER_EXPIRES and DONT_REQ_PREAUTH, so you rarely parse the raw hex by hand.Active Directory stores everything as objects, and each object has attributes (named properties). Enumerating these objects is the first move once you can query the directory.
description (which sometimes holds passwords!), servicePrincipalName, last logon, and flags like "password never expires."Enumeration tells you:
description field, GPO files).This map drives every later attack. Tools query AD over LDAP, which is covered in the next lesson.
Because no programming is involved, the example is a realistic read-only enumeration session. It is shown in the INSECURE (what an attacker/what a misconfigured directory exposes) -> SECURE (remediation) -> VERIFY (prove the fix) shape.
The insecure state here is a directory that leaks a secret and grants admin through nesting. Reproduce it only in your own lab domain controller (an isolated VM). Setting up the bad state:
# AUTHORIZED LAB ONLY. Creates an intentionally-vulnerable state to study.
# Do NOT run against any directory you do not own / are not authorized to test.
Set-ADUser -Identity svc_sql -Description "DB service acct pw: <lab-placeholder-P@ss>"
# add a user to Domain Admins indirectly, through a nested group:
Add-ADGroupMember -Identity "Helpdesk-Admins" -Members jane.doe
Add-ADGroupMember -Identity "Domain Admins" -Members "Helpdesk-Admins"
Now the read-only enumeration an assessor (or attacker) would run — it queries, it changes nothing:
# Read-only enumeration of objects/attributes. Assets touched: directory metadata.
# 1) Members of the crown-jewel group, resolving nesting transitively.
Get-ADGroupMember -Identity "Domain Admins" -Recursive |
Select-Object name, objectClass
# 2) Accounts with an SPN set (potential Kerberoasting targets).
Get-ADUser -Filter { servicePrincipalName -like "*" } `
-Properties servicePrincipalName, pwdLastSet |
Select-Object sAMAccountName, servicePrincipalName, pwdLastSet
# 3) Accounts whose password never expires.
Get-ADUser -Filter { passwordNeverExpires -eq $true } `
-Properties passwordNeverExpires |
Select-Object sAMAccountName
# 4) Credentials accidentally left in the description field.
Get-ADUser -Filter { description -like "*" } -Properties description |
Where-Object { $_.description -match "pass|pwd|secret" } |
Select-Object sAMAccountName, description
Expected output (shape, not exact values). A short table per query, e.g.:
sAMAccountName servicePrincipalName pwdLastSet
-------------- -------------------- -----------
svc_sql MSSQLSvc/db01:1433 1/3/2017 ...
Query 1's recursive result would include jane.doe even though she is not a direct member of Domain Admins. Query 4 would surface the svc_sql description leak.
# AUTHORIZED LAB ONLY. Fix each finding found above.
# Fix the leak: move the real secret to a vault, blank the description.
Set-ADUser -Identity svc_sql -Description "DB service acct - secret in vault"
# Fix over-privilege: remove the nested path to Domain Admins.
Remove-ADGroupMember -Identity "Domain Admins" -Members "Helpdesk-Admins" -Confirm:$false
# Reduce standing risk on the service account (rotate + require expiry, or use a
# group Managed Service Account so AD rotates the password automatically).
Set-ADUser -Identity svc_sql -PasswordNeverExpires $false
# Re-run the SAME read-only checks. A remediated directory returns EMPTY results.
# (a) jane.doe should no longer appear as an effective Domain Admin:
Get-ADGroupMember -Identity "Domain Admins" -Recursive |
Where-Object { $_.name -eq "jane.doe" } # expect: no output
# (b) no description should match a secret pattern:
Get-ADUser -Filter { description -like "*" } -Properties description |
Where-Object { $_.description -match "pass|pwd|secret" } # expect: no output
# (c) confirm the flag is cleared (should now be False):
(Get-ADUser svc_sql -Properties passwordNeverExpires).passwordNeverExpires
Why VERIFY matters. A fix you do not re-test is a hope, not a control. Empty results from (a) and (b), and False from (c), prove the finding is gone. This same before/after pattern is how a report's "retest" section is written.
Edge cases to expect. Some attributes are empty or hidden if your account lacks read rights on them; very large domains may return thousands of rows (page or filter with a tighter -Filter and -Properties); and passwordNeverExpires reported by the module already decodes the underlying userAccountControl bit for you, so you do not parse the raw number by hand.
Defender's version. A blue-teamer runs the enumeration queries on a schedule and alerts when a new account gains an SPN, when crown-group membership changes, or when a description matches a secret pattern. Same enumeration, opposite intent.
Walking through the enumeration and verification step by step:
| Step | Command | What happens | What you learn |
|---|---|---|---|
| 1 | Get-ADGroupMember "Domain Admins" -Recursive |
Sends an LDAP query for the group's members; -Recursive expands nested groups |
The true admin set, including users who are admins only through nesting |
| 2 | Get-ADUser -Filter { servicePrincipalName -like "*" } |
Returns every user object that has any SPN value | Which accounts are Kerberoasting candidates |
| 3 | Get-ADUser -Filter { passwordNeverExpires -eq $true } |
The module reads userAccountControl, decodes the flag, and matches |
Accounts whose password risk is permanent |
| 4 | `... description -like "*" ... -match "pass | pwd | secret"` |
| V | `... -Recursive | Where name -eq jane.doe` (empty) | Re-runs step 1 after the fix and looks for the removed user |
Tracing step 1 in detail. Suppose the domain has the chain jane.doe -> Helpdesk-Admins -> Domain Admins.
Administrator and Helpdesk-Admins).-Recursive, the query follows Helpdesk-Admins down and resolves its members, so jane.doe now appears in the result.jane.doe is an effective Domain Admin. Reading only direct membership would have hidden that fact — which is exactly the kind of blind spot enumeration is meant to remove.Tracing the verification. After Remove-ADGroupMember breaks the Helpdesk-Admins -> Domain Admins link, the recursive query no longer has a path from jane.doe up to Domain Admins, so she drops out of the result. The Where-Object { $_.name -eq "jane.doe" } filter therefore returns nothing — the empty result is the evidence that the over-privilege finding is closed.
Why the results are produced. None of the enumeration commands change state; they read attributes the directory exposes to authenticated users. The value comes entirely from interpreting the attributes correctly (transitive membership, decoded flags, free-text leaks) and from re-reading them after remediation to confirm the change.
Mistake 1 — Reading only direct group membership.
Get-ADGroupMember -Recursive) and report the full effective set.Mistake 2 — Confusing OUs with groups.
memberOf (groups), not which OU contains them.Mistake 3 — Ignoring "almost-admin" groups.
Mistake 4 — Assuming the directory is private.
description, but only admins can see the directory."description/info for accidental leaks.Mistake 5 — Calling it fixed without re-testing.
Things that commonly go wrong while enumerating, and how to reason about them:
"Access denied" or empty attribute values.
"Cannot find a module / command not recognized."
A query returns thousands of rows.
-like "*") in a large domain.-Filter, request only the attributes you need with -Properties, and page the results instead of dumping everything.Membership numbers do not match between tools.
Verification query still returns the finding.
Questions to ask when results look wrong:
userAccountControl number?Security & safety
Authorization and ethics (read first). Enumeration touches a live identity system. Run these techniques only against systems you own or are explicitly, in-writing authorized to test — a personal lab domain controller, an isolated VM, or a sanctioned engagement with a signed scope. Never enumerate a third-party domain. Even though enumeration is read-only, unauthorized querying of someone else's directory is still unauthorized access.
Authorization checklist (before any lab work):
Threat model (single-domain AD):
Entry point Trust boundary Asset
----------- -------------- -----
Any authenticated user --> (low-priv account can --> Directory metadata
(phished/weak password) read most attributes) (memberships, SPNs,
flags, descriptions)
|
v misconfig found
Privilege escalation --> Domain Admins (game over)
The key insight: the trust boundary between "any user" and "reads sensitive metadata" is very thin. That is why minimizing what objects expose is a real control.
Defensive practices (at least as important as the offensive view):
description and info for anything resembling a secret; move real secrets into a password vault.Detection and logging. Defenders should baseline objects and alert on change. Log: timestamp, the actor (who queried/changed), the source host, the target object (DN), the result, and the security decision (allowed/denied), plus a correlation id to tie related events together. Watch specifically for: a new account gaining an SPN, membership changes to crown groups, accounts toggling passwordNeverExpires or pre-auth, and bulk/broad attribute reads (a signature of enumeration). Never log: passwords, Kerberos tickets or hashes, session cookies, private keys, or the leaked secret string you found — log only that a match occurred and where.
How false positives arise. Legitimate administration also reads AD in bulk (backup software, sync connectors, IAM tools, an authorized assessor). Baseline these known service identities and source hosts so their activity does not flood the alert queue; alert on deviation from the baseline, not on enumeration in the abstract.
Testing your fix (mitigation verification). After removing a leaked password from a description or trimming a group, re-run the same read-only enumeration and confirm the finding is gone — the description no longer matches the secret pattern, or the user no longer appears in the recursive Domain Admins membership. An empty result is your proof. Then restore the lab snapshot when finished.
Concrete authorized real-world use. Internal penetration testers and red teams begin almost every engagement by enumerating AD objects: they map crown-group membership, list SPN accounts to plan Kerberoasting, and search description fields for leaked credentials — all under a signed scope. On the defensive side, blue teams and identity-governance tools run continuous AD audits that flag the very same conditions — over-privileged accounts, stale service accounts, dangerous flags — so they can be fixed before an incident. Attack-path analysis tools build a graph of these objects and relationships to show the shortest route from any user to Domain Admins, which defenders use to cut the most dangerous edges first.
Professional best-practice habits
Beginner rules:
description/info as public.Advanced practices:
Work through these in order; each one builds on the last. Do every task only in your own authorized lab (an isolated VM domain controller), and snapshot before you start so you can reset afterward.
Beginner 1 — Classify the objects.
FIN-PC-07$ -> Output: "Computer object (the $ suffix marks a machine account)."$; OUs contain other objects; groups grant rights.Beginner 2 — Read one user's attributes.
sAMAccountName, memberOf, description, and whether passwordNeverExpires is set.description.passwordNeverExpires for you.Intermediate 1 — Resolve transitive membership.
Administrator, Helpdesk-Admins -> Recursive adds jane.doe.Intermediate 2 — Hunt risky flags.
passwordNeverExpires, and rank them by pwdLastSet (oldest = highest risk).sAMAccountName, the risky condition, and pwdLastSet.Challenge — Audit, remediate, and verify (defensive conclusion).
description and add a user to Domain Admins via a nested group. Then (a) write enumeration that detects both findings, (b) remediate them, and (c) re-run the enumeration to prove the findings are gone.memberOf (resolved transitively, because nested groups inherit rights), servicePrincipalName (Kerberoasting target), the userAccountControl flags password-never-expires and pre-auth-disabled (AS-REP roasting), and description (a common credential leak).Get-ADGroupMember -Recursive for transitive membership; Get-ADUser -Filter { servicePrincipalName -like "*" } for SPNs; Get-ADUser -Filter { passwordNeverExpires -eq $true } for the flag; re-run the same query after a fix to VERIFY.