This chapter covers LDAP and Active Directory enumeration, a critical skill for the PT0-002 exam's Reconnaissance and Enumeration domain (Objective 2.2). You will learn how to discover users, groups, computers, and other objects in LDAP directories, particularly Microsoft Active Directory. Approximately 10-15% of exam questions touch on enumeration techniques, and LDAP/AD enumeration is a core component. Mastering these techniques is essential for identifying attack paths and privilege escalation vectors during penetration tests.
Jump to a section
Imagine a large corporation with thousands of employees, each with a name, department, phone extension, email, and office location. The company maintains a central phone directory—a massive binder sorted alphabetically and by department. When you need to find someone's extension, you call the receptionist and say, 'I need the phone number for Jane Doe in Accounting.' The receptionist opens the binder, looks under 'D' for Doe, then filters by department 'Accounting,' and reads back the number. If you instead ask, 'List everyone in Accounting who has a desk on the third floor,' the receptionist flips to the department section, finds Accounting, then scans each entry for floor number '3,' and reads out all matching names and extensions. LDAP works exactly like this receptionist. The directory is a tree structure (DIT) with entries for users, groups, printers, etc. A client sends an LDAP search request with a base DN (where to start looking), a scope (how deep to search), and a filter (criteria like 'objectClass=user' and 'department=Accounting'). The LDAP server processes the query, traverses the tree, applies the filter, and returns matching entries with requested attributes. Just as the receptionist cannot modify the binder unless authorized, LDAP operations like Add, Delete, and Modify require authentication and permissions. The analog of the binder's index is the directory's indexing mechanisms that speed up searches. Anonymous queries are like a visitor asking for a publicly listed number—limited information. Authenticated queries get more details, like an employee calling for internal directory access.
What is LDAP and Why Does It Exist?
Lightweight Directory Access Protocol (LDAP) is an open, vendor-neutral protocol for accessing and maintaining distributed directory information services over an IP network. It is defined in RFCs 4510-4519. LDAP was developed as a lighter-weight alternative to the X.500 Directory Access Protocol (DAP), which ran over the OSI protocol stack. LDAP runs directly over TCP/IP, making it simpler to implement and deploy. Directories are specialized databases optimized for read-heavy, search-intensive workloads, unlike relational databases which are designed for complex transactions. LDAP directories store information about users, groups, devices, applications, and policies in a hierarchical tree structure called the Directory Information Tree (DIT).
Active Directory (AD) is Microsoft's implementation of an LDAP directory service for Windows domain networks. While AD uses LDAP as its primary access protocol, it also extends LDAP with additional features like Kerberos authentication, Group Policy, and schema extensions. AD is the most common LDAP directory encountered in enterprise environments, making it a primary target for penetration testers.
How LDAP Works Internally
LDAP is a client-server protocol. The client establishes a TCP connection to the LDAP server (default port 389 for LDAP, 636 for LDAPS – LDAP over SSL/TLS). After connection, the client sends an LDAP message, which can be a Bind Request (authentication), Search Request, Compare Request, Add Request, Delete Request, Modify Request, or Abandon Request. The server processes the request and returns one or more LDAP messages.
Directory Information Tree (DIT)
The DIT is a hierarchical structure with entries arranged in a tree. Each entry has a Distinguished Name (DN) that uniquely identifies it. For example: CN=John Doe,OU=Users,DC=example,DC=com. Components of a DN include:
- DC (Domain Component): e.g., DC=example,DC=com
- OU (Organizational Unit): e.g., OU=Users
- CN (Common Name): e.g., CN=John Doe
- Other: L (locality), ST (state), O (organization), etc.
LDAP Search Operation
The most common operation for enumeration is the Search. A Search Request includes:
- baseObject: The DN of the entry where the search starts (e.g., DC=example,DC=com).
- scope: One of:
- baseObject (0): Search only the base entry itself.
- singleLevel (1): Search entries one level below the base (but not the base itself).
- wholeSubtree (2): Search the base and all subordinate entries recursively.
- derefAliases: How to handle aliases (0 = never dereference, 1 = dereference in searching, 2 = dereference when locating the base, 3 = always dereference).
- sizeLimit: Maximum number of entries to return (0 means no limit, but server may enforce its own). Default is typically 1000 for AD.
- timeLimit: Maximum time in seconds for the search (0 means no limit).
- typesOnly: If true, return only attribute names, not values.
- filter: An LDAP filter string that specifies matching criteria (e.g., (&(objectClass=user)(department=Engineering))).
- attributes: List of attribute names to return (e.g., cn, mail, memberOf). If empty, all attributes are returned.
LDAP Filters
Filters use a prefix notation. Common filter types:
Equality: (attribute=value) e.g., (cn=John Doe)
Presence: (attribute=*) e.g., (objectClass=*)
Greater-or-equal: (attribute>=value)
Less-or-equal: (attribute<=value)
Approximate: (attribute~=value) (not widely supported)
Substring: (attribute=prefix*suffix) e.g., (cn=John*)
And: (&(filter1)(filter2))
Or: (|(filter1)(filter2))
Not: (!(filter))
LDAP Data Interchange Format (LDIF)
LDIF is a plain text format for representing LDAP entries and operations. It is used for importing/exporting directory data. Example:
dn: CN=John Doe,OU=Users,DC=example,DC=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: John Doe
sn: Doe
givenName: John
mail: jdoe@example.comActive Directory Specifics
Active Directory extends the base LDAP schema with additional object classes and attributes. Key object classes:
- user: Represents a user account. Important attributes: sAMAccountName, userPrincipalName, memberOf, badPwdCount, lockoutTime, pwdLastSet.
- group: Represents a group. Attributes: member (list of member DNs), groupType (security/distribution, global/universal/domain local).
- computer: Represents a computer account. Attributes: dNSHostName, operatingSystem, servicePrincipalName.
- domainDNS: Represents a domain.
- organizationalUnit: Represents an OU.
Default LDAP Ports - LDAP (non-SSL): TCP 389 - LDAPS (LDAP over SSL): TCP 636 - Global Catalog (GC): TCP 3268 (non-SSL), 3269 (SSL) – The Global Catalog is a read-only, partial replica of all objects in a forest, used for searching across domains.
Anonymous Bind and NULL Sessions
In older Windows versions (pre-Windows 2000), anonymous LDAP binds were allowed, enabling NULL session enumeration. Modern AD by default restricts anonymous binds. However, unauthenticated access may still be possible if the domain is configured with RestrictAnonymous set to 0 or if the anonymous account has been granted specific permissions. Penetration testers should always attempt anonymous binds.
Common Enumeration Queries
Using tools like ldapsearch (OpenLDAP), adfind, PowerView, or BloodHound, testers can extract valuable information.
Example ldapsearch commands:
Anonymous bind:
ldapsearch -x -H ldap://10.0.0.1 -b "DC=example,DC=com" "(objectClass=*)"Authenticated bind:
ldapsearch -x -H ldap://10.0.0.1 -D "CN=administrator,CN=Users,DC=example,DC=com" -W -b "DC=example,DC=com" "(objectClass=user)" sAMAccountNameEnumerate all users:
ldapsearch -x -H ldap://10.0.0.1 -D "DOMAIN\\username" -W -b "DC=example,DC=com" "(&(objectClass=user)(objectCategory=person))" sAMAccountName userPrincipalName mailEnumerate all groups:
ldapsearch -x -H ldap://10.0.0.1 -D "DOMAIN\\username" -W -b "DC=example,DC=com" "(objectClass=group)" cn memberEnumerate domain admins:
ldapsearch -x -H ldap://10.0.0.1 -D "DOMAIN\\username" -W -b "DC=example,DC=com" "(&(objectClass=group)(cn=Domain Admins))" memberUsing adfind (Windows tool):
Adfind -h 10.0.0.1 -u DOMAIN\\username -up password -b "DC=example,DC=com" -f "objectClass=user" sAMAccountNamePowerView (PowerShell):
Get-DomainUser -Domain example.com | Select sAMAccountName
Get-DomainGroupMember -Identity "Domain Admins"Security Considerations
LDAP Injection: Similar to SQL injection, an attacker can inject LDAP filter syntax to bypass authentication or extract data. Penetration testers should test for LDAP injection in web applications that construct LDAP filters from user input.
LDAP Channel Binding and Signing: To prevent relay attacks, AD supports LDAP channel binding (requiring the client to provide evidence of the TLS channel) and LDAP signing (signing LDAP messages). Testers should check if these are enforced.
SMB NULL Sessions: While not LDAP, NULL sessions over SMB (using net use \\target\ipc$ "" /u:"") can also yield enumeration data via SAMR (Security Account Manager Remote) protocol, which is often tested alongside LDAP enumeration.
Interaction with Related Technologies
Kerberos: LDAP is used to look up service principal names (SPNs) for Kerberos authentication. The attribute servicePrincipalName on computer accounts stores SPNs.
DNS: AD integrates with DNS; domain controllers register SRV records that clients use to locate LDAP servers.
Group Policy: Group Policy Objects (GPOs) are stored in the LDAP directory under CN=Policies,CN=System,DC=example,DC=com.
SMB: Many AD enumeration tools also use SMB for RPC calls (e.g., net group). LDAP and SMB enumeration often complement each other.
Identify LDAP Service
Use port scanning to discover LDAP services. LDAP typically runs on TCP 389 (plain) and TCP 636 (SSL). Active Directory also exposes the Global Catalog on TCP 3268 (plain) and 3269 (SSL). Use Nmap to scan: `nmap -p 389,636,3268,3269 -sV <target>`. The service banner often reveals the LDAP implementation (e.g., Microsoft AD, OpenLDAP). Also check for LDAP over UDP (port 389), though less common. If you find port 389 open, note that AD may also have SMB (445) and Kerberos (88) running. Enumeration often starts with an anonymous bind to see if unauthenticated access is allowed.
Attempt Anonymous Bind
Try an anonymous LDAP bind using `ldapsearch -x -H ldap://<target> -b "<domainDN>" "(objectClass=*)"`. If successful, you can retrieve all objects. Modern AD typically denies anonymous binds unless configured otherwise. If anonymous fails, try a null bind (empty credentials) or use a low-privilege domain account if you have one. On older Windows versions or misconfigured domains, anonymous binds may work. If you get a 'strong authentication required' error, the server requires SASL authentication (e.g., NTLM, Kerberos). You may need to use `-Y GSSAPI` for Kerberos or provide credentials.
Enumerate Domain Information
Retrieve the root DSE (DSA-Specific Entry) by querying with base DN empty and scope base: `ldapsearch -x -H ldap://<target> -b "" -s base`. This returns information about the LDAP server, including supported LDAP versions, naming contexts (domains), root domain naming context, configuration naming context, and schema naming context. For AD, you'll see `defaultNamingContext` (e.g., DC=example,DC=com), `schemaNamingContext`, `configurationNamingContext`, and `rootDomainNamingContext`. This data guides further enumeration.
Enumerate Users and Groups
Use authenticated bind (or anonymous if allowed) to enumerate all users: `ldapsearch -x -H ldap://<target> -D "DOMAIN\\user" -W -b "DC=example,DC=com" "(&(objectClass=user)(objectCategory=person))" sAMAccountName userPrincipalName`. For groups: `ldapsearch ... "(objectClass=group)" cn member`. Extract membership of privileged groups like 'Domain Admins', 'Enterprise Admins', 'Account Operators'. Note attributes like `badPwdCount`, `lockoutTime`, `pwdLastSet` to identify weak accounts. Use `adfind` or `PowerView` for more efficient enumeration. Also enumerate computers: `(objectClass=computer)` to get OS versions and DNS hostnames.
Map Trust Relationships
AD trusts with other domains can be enumerated via LDAP. Query the trusted domain objects: `ldapsearch ... -b "CN=System,DC=example,DC=com" "(objectClass=trustedDomain)"`. Attributes include `trustPartner`, `trustDirection` (inbound, outbound, bidirectional), `trustType` (e.g., Windows NT, Kerberos realm), and `trustAttributes`. This information is critical for lateral movement and cross-domain attacks. Also check the configuration partition: `CN=Partitions,CN=Configuration,DC=example,DC=com` for cross-refs to other domains. BloodHound automatically maps trusts via LDAP queries.
Scenario 1: Internal Penetration Test of a Large Enterprise
A pentester is engaged to assess a Fortune 500 company with 50,000+ users across multiple AD domains in a single forest. The tester is given a low-privilege domain account. Using ldapsearch and PowerView, they enumerate all users, groups, computers, and trust relationships. They discover that the 'Account Operators' group has GenericAll permissions over a key OU containing service accounts. By modifying the servicePrincipalName attribute of a service account, they perform a Kerberoasting attack. They also find a transitive trust to a child domain that allows them to escalate to Enterprise Admin via the ExtraSids attack. The enumeration phase takes two days but yields a full attack path. The key lesson: thorough LDAP enumeration often reveals misconfigured permissions and trust relationships that are the backbone of AD attacks.
Scenario 2: External Penetration Test with Anonymous LDAP
A tester targets a company that exposes an LDAP server on the internet (port 389) for a custom application. The tester performs an anonymous bind and dumps the entire directory, including user email addresses, phone numbers, and organizational structure. This information is used to craft spear-phishing emails. The company had not realized that anonymous binds were enabled. The tester recommends disabling anonymous binds or restricting access via firewall rules. This scenario highlights the risk of misconfigured LDAP access.
Scenario 3: Post-Exploitation Enumeration via LDAP
After gaining a foothold on a workstation, the tester uses PowerView to enumerate AD without touching the domain controller directly (by using the workstation's LDAP connection). They discover that the current user has WriteOwner permission on a group that is nested into 'Domain Admins'. By modifying the group's owner and then adding themselves to the group, they escalate privileges. This attack relies on LDAP modification operations. The tester also uses BloodHound to visualize the attack path. The takeaway: LDAP enumeration is not just for initial recon; it is critical during lateral movement and privilege escalation.
The PT0-002 exam tests LDAP and Active Directory enumeration under Objective 2.2: 'Given a scenario, enumerate and analyze the target.' Specific sub-objectives include:
- 2.2.1: Discover hosts and services (LDAP service on 389, 636, 3268, 3269).
- 2.2.2: Enumerate users, groups, and computers via LDAP.
- 2.2.3: Identify trust relationships.
- 2.2.4: Enumerate permissions and ACLs (e.g., using dsacls or Get-ObjectAcl).
Common Wrong Answers & Why Candidates Choose Them: 1. 'Anonymous binds are always disabled in modern AD.' Reality: While default is restricted, many environments have legacy settings or third-party applications that enable anonymous binds. Always attempt it. 2. 'LDAP only runs on port 389.' Reality: LDAPS (636) and Global Catalog (3268/3269) are also common. The exam expects you to know all four ports. 3. 'You need administrative credentials to enumerate AD.' Reality: A low-privilege domain user can enumerate most objects. The exam tests that you can enumerate with standard user rights. 4. 'LDAP queries cannot be used to enumerate trust relationships.' Reality: Trusted domain objects are stored in the System container and can be queried via LDAP.
Specific Numbers & Terms:
- Ports: 389 (LDAP), 636 (LDAPS), 3268 (GC), 3269 (GC SSL).
- LDAP filter syntax: (&(objectClass=user)(objectCategory=person)).
- Distinguished Name components: CN, OU, DC, O, L.
- Default sizeLimit in AD: 1000 entries per query (you may need to page results).
- LDAP message types: BindRequest, BindResponse, SearchRequest, SearchResultEntry, SearchResultDone.
Edge Cases:
- If a query returns more than 1000 objects, AD returns only the first 1000 with a cookie for paging. Use -E pr=1000/noprompt in ldapsearch or set -P in adfind.
- LDAP referrals: When querying a domain controller, it may return a referral for objects in other domains. You must follow the referral or use the Global Catalog.
- The memberOf attribute is a back-link; it may not be fully populated if the group membership cache is stale.
How to Eliminate Wrong Answers: - If a question asks for the port used by LDAP over SSL, eliminate 389, 3268, 3269. Only 636 is correct. - If a question asks about enumerating all objects in a forest, the Global Catalog (3268/3269) is the correct answer because it contains partial replicas of all domains. - If a question describes an anonymous bind failing, look for options that suggest using a valid domain account or attempting NTLM authentication.
LDAP runs on TCP 389 (plain) and 636 (SSL); Active Directory Global Catalog uses 3268 (plain) and 3269 (SSL).
Anonymous binds are often restricted but always worth testing; use null credentials first.
LDAP filters use prefix notation: `(&(objectClass=user)(objectCategory=person))`.
The default result size limit in AD is 1000 entries; use paging to retrieve more.
Enumerate trust relationships by querying `objectClass=trustedDomain` in the System container.
Low-privilege domain users can enumerate most AD objects; no admin rights needed.
Tools: ldapsearch, adfind, PowerView, BloodHound, dsquery.
LDAP injection attacks can bypass authentication or extract data; test web apps that use LDAP.
The root DSE query (`-b "" -s base`) reveals domain naming contexts and server capabilities.
Global Catalog is best for forest-wide enumeration; it contains partial attributes of all objects.
These come up on the exam all the time. Here's how to tell them apart.
LDAP (389)
Unencrypted communication; data sent in cleartext.
Default port TCP 389.
Vulnerable to sniffing and man-in-the-middle attacks.
Often used for internal directory access within trusted networks.
Less overhead than LDAPS; no TLS handshake.
LDAPS (636)
Encrypted communication using SSL/TLS.
Default port TCP 636.
Protects against sniffing and tampering.
Required for secure access over untrusted networks (e.g., internet).
Additional overhead due to TLS handshake; may require certificate management.
Mistake
LDAP enumeration only works with administrative credentials.
Correct
Any authenticated domain user can enumerate most AD objects, including users, groups, computers, and their attributes. Only some sensitive attributes (e.g., password hashes) require elevated privileges.
Mistake
The default LDAP port for Active Directory is 636.
Correct
The default LDAP port is 389. LDAPS (port 636) is used when SSL/TLS is enabled, but it is not the default. AD also uses 3268 for Global Catalog without SSL.
Mistake
Anonymous LDAP binds are always blocked in modern Windows domains.
Correct
While domain controllers running Windows Server 2008 and later restrict anonymous binds by default, third-party applications or legacy settings may still allow them. Always test anonymous bind during enumeration.
Mistake
LDAP queries can only return 1000 results at a time and cannot exceed that.
Correct
The default page size is 1000, but you can use paging (e.g., `-E pr=1000/noprompt` in ldapsearch) to retrieve all results in batches. The server may also have a maximum limit, but paging circumvents it.
Mistake
The Global Catalog is only used for authentication, not enumeration.
Correct
The Global Catalog is a read-only, partial replica of all objects in a forest. It is ideal for enumeration across multiple domains because it contains a subset of attributes for every object in the forest.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
LDAP is a protocol for accessing directory services. Active Directory is Microsoft's directory service that implements LDAP as its primary access protocol. AD extends LDAP with additional features like Kerberos, Group Policy, and a custom schema. When you query AD using LDAP, you are using the LDAP protocol to read/write objects in the AD database.
Use `ldapsearch -x -H ldap://<target> -b "<domainDN>" -s sub "(objectClass=*)"`. The `-x` flag indicates simple authentication (no SASL). If the server allows anonymous binds, you will get results. If you get an 'Inappropriate authentication' error, the server requires authentication. Some servers require an empty DN and password: `-D "" -w ""`.
The Global Catalog (GC) is a read-only, partial replica of all objects in an Active Directory forest. It is hosted on domain controllers and listens on TCP 3268 (non-SSL) and 3269 (SSL). To query the GC, use port 3268 and set the base DN to the root domain of the forest (e.g., `DC=example,DC=com`). The GC returns a subset of attributes for each object, which is sufficient for most enumeration tasks across domains.
Query the System container: `ldapsearch -x -H ldap://<target> -D "DOMAIN\\user" -W -b "CN=System,DC=example,DC=com" "(objectClass=trustedDomain)"`. This returns trusted domain objects with attributes like `trustPartner`, `trustDirection`, and `trustType`. You can also use `Get-DomainTrust` in PowerView.
Active Directory has a default size limit of 1000 entries per LDAP query. To retrieve more, you must use paging. In `ldapsearch`, use `-E pr=1000/noprompt` to enable paging with a page size of 1000. In `adfind`, use `-P` to enable paging. In PowerView, paging is handled automatically.
Yes. The domain password policy is stored in the domain object's attributes. Query the domain root: `ldapsearch ... -b "DC=example,DC=com" -s base minPwdLength lockoutThreshold lockoutDuration`. You need appropriate permissions to read these attributes. Alternatively, use `net accounts /domain` or PowerView's `Get-DomainPolicy`.
LDAP injection occurs when user input is incorporated into an LDAP filter without proper sanitization. An attacker can inject filter syntax to alter the query. For example, inputting `*)(objectClass=*))` into a username field could return all users. To test, try injecting `*)(uid=*))(|(uid=*` and observe if the application returns unexpected data. Use tools like `ldapsearch` to craft payloads.
You've just covered LDAP and Active Directory Enumeration — now see how well it sticks with free PT0-002 practice questions. Full explanations included, no account needed.
Done with this chapter?