ᛉ Yggdrasil

Active Directory

Active Directory — LDAP Search Query

15 Sep 2026 · 2,909 words · 13 min

Contents

Covers raw LDAP filters, attribute queries, and tool-specific syntax for AD enumeration. Tools: ldapsearch, bloodyAD, PowerView, crackmapexec, ldapdomaindump, certipy, windapsearch, python-ldap


1. LDAP Basics & Syntax

Filter Syntax

(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

Search Scopes

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)

Common Base DNs

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 Base Command

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)

2. Authentication Modes

# 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 ...

3. User Enumeration

All Users

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

Enabled Users Only

# UAC bit 2 (0x2) = ACCOUNTDISABLE. Filter out accounts where bit 2 is set.
'(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'

Users with Description Field Set (often contains passwords)

'(&(objectClass=user)(description=*))'

Users with Passwords That Never Expire

# UAC bit 0x10000 = DONT_EXPIRE_PASSWORD
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))'

Users with Password Not Required

# UAC bit 0x20 = PASSWD_NOTREQD
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))'

Locked Out Users

# UAC bit 0x10 = LOCKOUT
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=16))'

Users Who Haven't Logged In (stale/dormant)

# 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

Find User by Username / Email

'(&(objectClass=user)(sAMAccountName=john.doe))'
'(&(objectClass=user)(mail=john.doe@domain.local))'
'(&(objectClass=user)(displayName=*John*))'

Users with a Specific Group Membership

'(&(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))'

Users with SID History (migration artifacts / privilege escalation)

'(&(objectClass=user)(sIDHistory=*))'

All User Attributes for a Specific Account

ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
  -b 'DC=domain,DC=local' \
  '(sAMAccountName=administrator)'
# No attribute list = return all attributes

4. Computer Enumeration

All Computers

ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
  -b 'DC=domain,DC=local' \
  '(objectClass=computer)' \
  sAMAccountName dNSHostName operatingSystem operatingSystemVersion lastLogon

Domain Controllers

# 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

Read-Only Domain Controllers (RODC)

# primaryGroupID = 521
'(&(objectClass=computer)(primaryGroupID=521))'

Computers by OS

'(&(objectClass=computer)(operatingSystem=*Server*))'
'(&(objectClass=computer)(operatingSystem=*Windows 10*))'
'(&(objectClass=computer)(operatingSystem=*Windows 11*))'
# Older / unpatched
'(&(objectClass=computer)(operatingSystem=*2008*))'
'(&(objectClass=computer)(operatingSystem=*XP*))'

Stale Computer Accounts (not logged in > 90 days)

'(&(objectClass=computer)(lastLogonTimestamp<=<FILETIME_90_DAYS_AGO>)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'

5. Group Enumeration

All Groups

ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
  -b 'DC=domain,DC=local' \
  '(objectClass=group)' \
  sAMAccountName description member

Group Members (including nested)

# 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)'

Groups That a User Belongs To

'(&(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)'

Groups with No Members (zombie groups)

'(&(objectClass=group)(!(member=*)))'

High-Value / Privileged Groups (quick check)

# 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)))'

6. Domain / Forest Enumeration

Domain Info

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

MachineAccountQuota (can unprivileged users create machine accounts?)

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

Domain Functional Level

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

Forest Enumeration

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

7. Privileged Accounts & Groups

Users with AdminCount=1 (Protected by AdminSDHolder)

'(&(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

Service Accounts (common naming patterns)

'(&(objectClass=user)(|(sAMAccountName=svc_*)(sAMAccountName=*service*)(sAMAccountName=*svc*)))'

Accounts with Sensitive Attributes (not delegatable)

# UAC bit 0x100000 = NOT_DELEGATED
'(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=1048576))'

8. SPNs & Kerberoastable Accounts

All Accounts with SPNs (Kerberoastable)

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

High-Value Kerberoastable (admin accounts with SPN)

'(&(objectClass=user)(servicePrincipalName=*)(adminCount=1)(!(sAMAccountName=krbtgt)))'

9. ASREPRoastable Accounts

Accounts with Kerberos Pre-Auth Disabled

# 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>

10. Password Policy & Lockout

Default Domain Password Policy

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

Fine-Grained Password Policies (PSOs)

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'

11. Trust Relationships

All Domain Trusts

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)

SID Filtering Status

# If trustAttributes does NOT have 0x4 (QUARANTINED_DOMAIN) = SID filtering disabled = SID history attack possible
ldapsearch ... '(objectClass=trustedDomain)' trustAttributes

12. ACL / DACL Queries

Read nTSecurityDescriptor (raw DACL)

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'
}

Who Has Rights Over a Specific Object

# 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!'

13. ADCS / PKI Queries

List All Certificate Templates

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)

List Enrollment Services (CAs)

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

NTAuthCertificates (Trusted CA Certs)

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

Templates Allowing Low-Priv Enrollment

# 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

14. LAPS

Check if LAPS is Deployed (schema extension present)

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

Read LAPS Passwords (requires read access to ms-Mcs-AdmPwd)

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

Find Who Can Read LAPS (who has access to ms-Mcs-AdmPwd)

# LAPSToolkit (PowerShell)
Find-LAPSDelegatedGroups
Find-AdmPwdExtendedRights
Get-LAPSComputers

15. gMSA Accounts

Find All gMSA Accounts

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

Who Is Allowed to Retrieve gMSA Password

# 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>

16. Delegation Queries

Unconstrained Delegation (Computers + Users)

# 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)))'

Constrained Delegation (msDS-AllowedToDelegateTo)

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))'

Resource-Based Constrained Delegation (RBCD)

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 (Impacket — all delegation types at once)

findDelegation.py domain.local/attacker:Pass123! -dc-ip <DC_IP>

17. AdminSDHolder & Protected Users

Users Protected by AdminSDHolder (adminCount=1)

'(&(objectClass=user)(adminCount=1))'

Members of Protected Users Group

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

Check AdminSDHolder Template ACL

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!'

18. GPO & OU Enumeration

All GPOs

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

All OUs

ldapsearch -H ldap://<DC_IP> -D 'attacker@domain.local' -w 'Pass123!' \
  -b 'DC=domain,DC=local' \
  '(objectClass=organizationalUnit)' \
  name distinguishedName gPLink managedBy

19. BloodHound Ingestor Queries

Python Ingestor (remote — preferred)

# 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 (Windows)

.\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

20. Unauthenticated / Null Session Queries

Test for Null Bind

ldapsearch -H ldap://<DC_IP> -x \
  -b '' -s base '(objectClass=*)' namingContexts defaultNamingContext

# If it returns results → null bind allowed

Enumerate via Null Session (if 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>

LDAP Signing Check

# 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>

21. Tool-Specific Syntax Reference

bloodyAD

# 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!'

windapsearch

# 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

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 module

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

PowerView Quick Reference

# 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

22. Filter Cheat Sheet

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))

UAC Bitmask Reference

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)

LDAP Matching Rules (OIDs)

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

← Active Directory top ↑