🛡️ Methodology Checklist

  • Enumerate password policy BEFORE spraying: net accounts /domain
  • Check lockout threshold and observation window
  • Get Fine-Grained Password Policies (PSOs): Get-DomainFGPasswordPolicy
  • Build userlist from: NULL session enum, Kerbrute, LinkedIn
  • Deduplicate and validate list: remove disabled accounts
  • Calculate safe spray frequency: 1 attempt per (lockout_window - 5 min)
  • Document policy before and spray timing for report

🎯 Operational Context

Use when: Before any password spraying — extract the domain password policy to calculate safe spray intervals and lockout thresholds. Think Dumber First: One lockout is a failed pentest. Run nxc smb [DC] --pass-pol before any spray. Extract user list from LDAP, not brute force. Never spray more than 1 password per 30 minutes without confirming the observation window. Skip when: Fine-grained password policies (PSOs) may apply to sensitive accounts — enumerate per-account policy too.


⚡ Tactical Cheatsheet

CommandTactical Outcome
rpcclient -U "" -N [DC_IP]getdompwinfoPull password policy via RPC null session
nxc smb [DC_IP] -u [USER] -p [PASS] --pass-polPull password policy authenticated via SMB
enum4linux-ng -P [DC_IP] -oA outputAutomated password policy extraction to JSON/YAML
ldapsearch -H ldap://[DC_IP] -x -b "DC=[DOMAIN],DC=[TLD]" -s sub "*" | grep -m 1 -B 10 pwdHistoryLengthLDAP anon bind — pull policy attributes
net accountsPull password policy from domain-joined Windows host
Get-DomainPolicyPowerView — full policy dump
enum4linux -U [DC_IP] | grep "user:" | cut -f2 -d"[" | cut -f1 -d"]"Extract user list via SMB null session
rpcclient -U "" -N [DC_IP]enumdomusersList all domain users via RPC null session
nxc smb [DC_IP] -u [USER] -p [PASS] --usersEnumerate users with badpwdcount and badpwdtime
ldapsearch -h [DC_IP] -x -b "DC=[DOMAIN],DC=[TLD]" -s sub "(&(objectclass=user))" | grep sAMAccountName: | cut -f2 -d" "LDAP anon bind — extract all user sAMAccountNames
./windapsearch.py --dc-ip [DC_IP] -u "" -UWindapsearch — anonymous LDAP user extraction
kerbrute userenum -d [DOMAIN] --dc [DC_IP] [USER_LIST]Validate usernames via Kerberos pre-auth (no lockout)

🔬 Deep Dive & Workflow

Why Policy Enumeration Comes First

Spraying without knowing the lockout threshold is an engagement-ending mistake. A single over-aggressive run can lock out hundreds of accounts, trigger SOC alerts, and halt business operations. Always retrieve:

MetricWhy It Matters
Lockout ThresholdMax attempts — stay 1-2 below this number
Lockout DurationTime to wait between spray rounds
Observation WindowWindow in which failed attempts are counted
Min Password LengthMinimum password to attempt
Complexity RequirementWhether uppercase/symbol required

Default AD trivia: New domain default minimum password length is 7. Most production environments configure 8+.

Policy Retrieval by Access Level

Unauthenticated (null session — legacy misconfiguration):

rpcclient -U "" -N [DC_IP]
rpcclient $> getdompwinfo
 
enum4linux-ng -P [DC_IP] -oA enum_output

Unauthenticated (LDAP anonymous bind):

ldapsearch -H ldap://[DC_IP] -x -b "DC=INLANEFREIGHT,DC=LOCAL" -s sub "*" | grep -m 1 -B 10 pwdHistoryLength

Authenticated:

nxc smb [DC_IP] -u [USER] -p [PASS] --pass-pol

From domain-joined Windows:

net accounts
Get-DomainPolicy  # requires PowerView

User List Building — Method Selection

ContextToolNotes
Null session availablerpcclient enumdomusers / enum4linux -UNo creds needed
LDAP anon bindldapsearch / windapsearch -u ""No creds needed
Authenticatednxc smb --usersShows badpwdcount — critical for safe spraying
Kerberos onlykerbrute userenumNo lockout; generates Event ID 4768 not 4625

The badpwdcount Check

Before spraying, always run nxc --users to check badpwdcount per user. Remove any account within 1-2 attempts of the lockout threshold from your target list. Failed login attempts are tracked per DC — for accurate counts, query the PDC Emulator FSMO role holder.

Operational Safety Rules

  • If policy cannot be retrieved: assume threshold = 3, attempt max 1-2 passwords, wait 60+ minutes between rounds
  • Log every spray: accounts targeted, DC IP, timestamp, passwords attempted
  • STATUS_ACCOUNT_LOCKED_OUT / error 1909 = stop immediately

🛠️ Troubleshooting & Edge Cases

ProblemCauseFix
nxc —pass-pol returns blankNull session blockedUse credentialed: nxc smb [DC] -u [USER] -p [PASS] --pass-pol
Policy shows ‘lockout threshold: 0’Lockout disabledConfirm with net accounts /domain from inside — still limit spray rate to avoid detection
User list from ldapdomaindump is emptyNo LDAP accessUse rpcclient -U '[USER]%[PASS]' [DC] -c 'enumdomusers'
Spray triggers lockout despite following policyFine-grained PSO appliesCheck for PSOs: Get-ADFineGrainedPasswordPolicy -Filter * or dsquery * -filter "(objectClass=msDS-PasswordSettings)"
User list has disabled accountsLDAP returns all objectsFilter: grep -v '66050|66082|514|546' users.txt — these UAC values indicate disabled

📝 Reporting Trigger

Finding Title: Domain Password Policy Permits Targeted Password Spraying Impact: A lockout threshold ≥5 attempts or observation window >30 minutes allows an attacker to spray common passwords across all domain accounts without triggering lockouts, enabling credential compromise at scale. Root Cause: Default or weak domain password policy. No fine-grained password policies for privileged accounts. Absence of anomalous authentication alerting. Recommendation: Set lockout threshold to 3-5 attempts with 15-minute observation window. Implement fine-grained PSOs for privileged accounts with stricter settings. Deploy anomalous authentication alerts via Microsoft Sentinel or Defender for Identity.