Everything in Active Directory — every user, computer, group, policy, and trust — is an entry in a database, and that database is exposed over LDAP (Lightweight Directory Access Protocol). When you enumerate a domain, you are running LDAP queries. When an attack reads whether an account is Kerberoastable, or writes a Shadow Credential, it is reading or writing an LDAP attribute. Understanding LDAP is understanding how AD stores and exposes the very things attacks target.
The directory as a tree
LDAP data is a hierarchy. At the top is the domain, and beneath it are containers and organizational units holding objects. Every object sits at a path, and that path is its Distinguished Name (DN), read from the object up to the root:
CN=John Doe,OU=Staff,OU=London,DC=corp,DC=target,DC=local
| Component | Meaning |
|---|---|
| CN (Common Name) | The object's own name |
| OU (Organizational Unit) | A container used for structure, policy, and delegation |
| DC (Domain Component) | A piece of the domain name; the DCs together name the domain root |
| RDN (Relative DN) | The leftmost component — the object's name relative to its parent |
Objects, classes, and the schema
Every object is an instance of an object class (user, computer, group, organizationalUnit…) defined in the schema. The schema is the master template that says which attributes an object of each class may have. It is forest-wide and rarely changes, which is why Schema Admins membership is a red flag — modifying the schema affects every domain in the forest.
An object is really just a bag of attributes, and the attributes are where the security-relevant information lives. Reading them is enumeration; writing them is, in many cases, the attack.
The attributes that matter
| Attribute | Why an attacker cares |
|---|---|
| sAMAccountName | The logon name — the account identifier you spray, roast, and authenticate as |
| userAccountControl (UAC) | A bitfield of account flags — pre-auth disabled, delegation trust, disabled, password-not-required, and more |
| servicePrincipalName (SPN) | Present means the account is Kerberoastable |
| memberOf / member | Group membership — the basis of privilege and of nested-group analysis |
| adminCount | Set to 1 on accounts that are or were privileged (protected by AdminSDHolder) |
| msDS-AllowedToDelegateTo | Constrained delegation targets — see Delegation |
| msDS-AllowedToActOnBehalfOfOtherIdentity | Resource-based constrained delegation (RBCD) config |
| msDS-KeyCredentialLink | Where a Shadow Credential is written |
| ms-MCS-AdmPwd | The LAPS local-admin password, in cleartext to anyone with the read right |
| description / info | Free-text fields that regularly contain passwords |
| ntSecurityDescriptor | The object's ACL — who can do what to it (see ACLs & DACLs) |
Search filters
LDAP queries use a parenthesised, prefix-notation filter language. It looks odd at first but is simple once you see the pattern: the operator comes before its operands.
| Filter | Matches |
|---|---|
(objectClass=user) | All user objects |
(&(objectClass=user)(servicePrincipalName=*)) | Users that have an SPN — Kerberoastable accounts |
(userAccountControl:1.2.840.113556.1.4.803:=4194304) | Accounts with pre-auth disabled (AS-REP roastable) |
(userAccountControl:1.2.840.113556.1.4.803:=524288) | Accounts trusted for delegation |
(adminCount=1) | Protected / privileged accounts |
(&(objectClass=user)(description=*pass*)) | Passwords hiding in description fields |
The strange 1.2.840.113556.1.4.803 is the OID for a bitwise-AND
matching rule — it means "this specific bit in userAccountControl is set". Those
UAC bit filters express most of the interesting security questions ("is pre-auth
off?", "is this account trusted for delegation?"), which is why they appear
throughout the tooling.
Why any user can read so much
By default, the Authenticated Users group has read access to the overwhelming majority of the directory. This is deliberate — applications, logon scripts, address books, and Windows itself rely on being able to look things up. The consequence is that a single low-privilege credential is enough to enumerate users, groups, computers, SPNs, delegation settings, and ACLs across the domain.
This is why the OSINT-to-foothold transition is so sharp on an internal engagement: the moment you hold one valid domain credential, LDAP hands you a near-complete map of the domain. Enumeration is not an exploit; it is the designed read access, which is exactly why tools like ldapdomaindump, windapsearch, and BloodHound are so productive.
LDAP transport and its security relevance
| Form | Port / note |
|---|---|
| LDAP | 389 — plaintext; queries and simple-bind credentials are exposed on the wire |
| LDAPS | 636 — LDAP over TLS |
| Global Catalog | 3268 / 3269 — the forest-wide partial index, for cross-domain searches |
| Channel binding / signing | When enforced, blocks LDAP relay; when off, enables RBCD and Shadow Credential relays |
The write side is where LDAP stops being enumeration and becomes attack. Adding an SPN to an account, writing msDS-KeyCredentialLink, or setting the RBCD attribute are all LDAP writes — and whether you can perform them is decided by the object's ACL, which is itself just another attribute. That is the bridge to ACLs & DACLs.
The takeaway
LDAP is the lens through which the entire directory is read and written. Objects are bags of attributes; attributes hold the security-relevant facts; filters let you ask precise questions; and default read access means one credential exposes almost everything. Every enumeration tool is an LDAP query wrapped for convenience, and several of the highest-impact attacks are single LDAP writes to the right attribute. Learn the attributes in the table above and most of the AD attack surface becomes legible on sight.