ADPWD-005: Password Complexity Requirement

Platform
Active Directory
Category
AD Password & Lockout Policies
Severity
High
Zero Trust pillar
Identity (weight 3)
Golden fixtures
3
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check reads two locations. First, the domain-wide policy via the Get-ADDefaultDomainPasswordPolicy primitive, which translates to the PasswordProperties bit field on the domainDNS object (DC=<domain>). The DOMAIN_PASSWORD_COMPLEX flag (0x00000001) of PasswordProperties indicates complexity is enforced; if the bit is clear, complexity is disabled. The check also captures DOMAIN_PASSWORD_NO_ANON_CHANGE (0x02), DOMAIN_PASSWORD_NO_CLEAR_CHANGE (0x04), DOMAIN_LOCKOUT_ADMINS (0x08), DOMAIN_PASSWORD_STORE_CLEARTEXT (0x10), and DOMAIN_REFUSE_PASSWORD_CHANGE (0x20) for context. Second, the check enumerates every msDS-PasswordSettings object (Fine-Grained Password Policies) under CN=Password Settings Container,CN=System,DC=<domain> and reads msDS-PasswordComplexityEnabled. A FAIL is raised when the domain-level DOMAIN_PASSWORD_COMPLEX bit is clear, or when any PSO applied to a populated msDS-PSOAppliesTo group reports msDS-PasswordComplexityEnabled = FALSE. The check additionally captures the precedence (msDS-PasswordSettingsPrecedence) so the operator knows which PSO wins for overlapping memberships.

Why it matters

Disabling complexity removes the only built-in keyspace constraint Windows applies to user-chosen passwords. Empirical password-crack telemetry from Hashicorp, Specops, and the Have I Been Pwned corpus consistently shows that without complexity the modal user password is between 8 and 10 characters, all lowercase, dictionary-derived, often the company name with a digit suffix. Against an offline NTDS.dit dump, these passwords fall to a single-GPU Hashcat run in seconds, not hours. The blast radius is every account that authenticates with a password: human users, service accounts that have not been migrated to gMSAs, break-glass accounts, and any local accounts synced from AD. NIST SP 800-63B does deprecate periodic rotation and arbitrary composition rules, but it explicitly retains the requirement to block known-breached passwords (the equivalent control), which Windows complexity provides only weakly and which Azure AD Password Protection or a custom password filter DLL provides properly. Disabling complexity without deploying a banned-list filter is a net regression, not a NIST modernization.

Attack path

Step 1: Acquire hashes. The attacker obtains NTDS.dit and SYSTEM hive via DCSync (mimikatz lsadump::dcsync /all), via a backup, or via shadow copy on a domain controller (vssadmin create shadow, copy NTDS.dit and SYSTEM). They extract NT hashes with secretsdump.py -ntds NTDS.dit -system SYSTEM LOCAL. Step 2: Offline crack. The attacker runs hashcat -m 1000 ntds.hashes rockyou.txt -r rules/best64.rule against the dump. With complexity disabled, the typical recovery rate exceeds 60 percent within the first ten minutes on a single RTX 4090; another 15 to 20 percent falls to targeted wordlists derived from the company name, season-year patterns (Summer2024, Winter2025), and sports-team variants. Step 3: Lateral movement. Recovered cleartext is sprayed against any externally exposed endpoint that accepts password authentication: Outlook on the Web, ADFS, Citrix, VPN portals, RDGW, Azure AD/Entra ID Hybrid Sign-In. Because complexity was disabled at the domain level, recovered cleartext for low-privilege users frequently matches help-desk, finance, and contractor accounts that did not require a separate strong-password policy. Step 4: Privilege escalation. The same wordlist is replayed against service accounts via Kerberoasting (Rubeus kerberoast). Service-account passwords cracked from RC4 TGS tickets combine with the weak-complexity environment to yield Domain Admin or Tier 0 service identities. Without complexity, the typical Kerberoast crack rate against a 1000-SPN environment exceeds 25 percent of all eligible accounts. Step 5: Persistence. The attacker rotates one cracked account into a Golden Ticket via the krbtgt hash (also extracted in step 1) and retains long-term access. The original password-complexity failure remains as the root cause: every credential rotation post-incident produces equally weak passwords until the policy is reversed.

How Guerrilla assesses it

Guerrilla binds to the domain naming context and calls the ADSI IADsContainer interface against the domainDNS object to read the PasswordProperties integer (equivalent to the pwdProperties LDAP attribute). The DOMAIN_PASSWORD_COMPLEX bit (0x1) is tested with a bitwise AND. The check then issues an LDAP search (objectClass=msDS-PasswordSettings) under CN=Password Settings Container,CN=System,DC=<domain> and reads msDS-PasswordComplexityEnabled, msDS-PasswordSettingsPrecedence, and msDS-PSOAppliesTo for every PSO. PSOs are correlated with their target groups to compute effective coverage: a PSO with complexity disabled that applies only to an empty group is still surfaced as a warning but ranked lower than one applied to a populated group. The check also queries HKLM\SYSTEM\CurrentControlSet\Control\Lsa\NoLMHash and HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters on each DC for context, since environments that disable complexity frequently also relax adjacent settings. Findings are emitted with the originating LDAP DN, the raw PasswordProperties bitmask, and the list of in-scope user accounts that inherit the failing policy.

Recommended value

Complexity enabled. Ideally supplemented with Azure AD Password Protection or custom banned word lists for defense against common patterns

Remediation

Verify complexity is enabled in the Default Domain Policy: Computer Configuration > Policies > Windows Settings > Security Settings > Account Policies > Password Policy > 'Password must meet complexity requirements' = Enabled. Consider deploying Azure AD Password Protection for additional banned password enforcement

Fixture-proven verdicts

Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.

Verdict scenarios for ADPWD-005
ScenarioExpected verdict
cleanPASS
known-badFAIL
throttledNot Assessed

Framework mappings

NIST SP 800-53
IA-5(1)
CIS Benchmark
1.1.5
ANSSI
R34
CIS AD Benchmark
5.2.2
MITRE ATT&CK
T1110.001, T1110.003