ADPWD-011: Duplicate Password Hashes

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

What it checks

The check obtains the NT hash for every enabled user (and optionally computer) account in the domain and groups them by hash value. Any hash that appears two or more times across distinct accounts is reported as a duplicate cluster. Hashes are sourced from one of three places, in order of preference: - A live DCSync replication (MS-DRSR IDL_DRSGetNCChanges with the DS-Replication-Get-Changes and DS-Replication-Get-Changes-All extended rights) against a domain controller. - An offline copy of NTDS.dit plus the SYSTEM hive, parsed with DSInternals Get-ADDBAccount. - A vendor-provided exported hash list (for example the output of secretsdump.py or Get-ADReplAccount) supplied to the cmdlet. For every cluster the check records the hash (typically truncated in output for safety), the count of accounts sharing it, the sAMAccountName and DN of each member, and whether the cluster spans privileged groups (Domain Admins, Enterprise Admins, members of AdminSDHolder-protected groups), service accounts, or regular users. The well-known empty-password hash (31d6cfe0d16ae931b73c59d7e0c089c0) is flagged separately because it indicates accounts with no password at all and overlaps with ADPWD checks for PASSWD_NOTREQD.

Why it matters

Password reuse silently multiplies the blast radius of every credential compromise in the environment. The realistic attack scenarios fall into three buckets: - Bulk-provisioned accounts. Help desk scripts, M&A onboarding, or lab rebuilds frequently set every new user to a single seasonal password (Welcome2025!, CompanyName1!). One cracked hash from an offline NTDS dump reveals the password for hundreds of users at once, including any that later got promoted into privileged groups without their password being changed. - Service account sprawl. A team stands up dozens of svc-* accounts with the same password because the runbook says to. When one of those services logs in interactively on a workstation and the hash is harvested with mimikatz sekurlsa::logonpasswords, the attacker can pass-the-hash to every other service account in the cluster, often hopping straight to Tier-0. - Admin reuse. An administrator uses the same password for their daily account and their privileged DA account. The hashes collide. Phishing the daily account effectively phishes the DA account, defeating the tier model. Duplicate hashes also indicate a deeper governance problem: the password reset workflow does not enforce uniqueness, the bulk provisioning tooling has no entropy source, or shared credentials are being treated as acceptable. Fixing the duplicates without fixing the workflow guarantees they will reappear.

Attack path

1. Initial foothold. The attacker compromises one user, typically through phishing, an exposed service, or a stolen laptop with cached credentials. 2. Hash extraction. With local admin on any domain-joined host the attacker dumps LSASS (mimikatz sekurlsa::logonpasswords, nanodump, comsvcs.dll MiniDump). With Domain Admin or a principal holding GetChanges + GetChangesAll, they DCSync the full NT hash set (secretsdump.py -just-dc, mimikatz lsadump::dcsync /all, or Get-ADReplAccount from DSInternals). 3. Offline cracking. The hashes are loaded into hashcat (-m 1000 NTLM) against rockyou, HIBP top-N, or a tuned wordlist plus rule. Bulk-provisioned passwords (Welcome1, Summer2025!, the company name plus a digit) fall in seconds because they are short, predictable, and shared. 4. Cluster pivot. The attacker sorts the recovered plaintext by frequency. A single recovered password that decrypts 200 accounts is immediately weaponized: any of those 200 accounts can be used for lateral movement, mail access, VPN login, or as a foothold into systems with different ACLs. 5. Tier escalation. If the cluster contains a privileged account (Domain Admin who reused their daily password, a service account in a Tier-0 group, or a helpdesk account with PrincipalsAllowedToDelegateToAccount on a sensitive resource), the attacker now has Tier-0 from a single phish. 6. Persistence. The attacker creates additional accounts that match the duplicate-password pattern so they blend in, or sets their own implants to use the shared password, knowing it survives partial remediation cycles.

How Guerrilla assesses it

Guerrilla calls into DSInternals (Get-ADReplAccount over MS-DRSR for live collection, or Get-ADDBAccount for offline NTDS.dit parsing) to enumerate the NT hash for every enabled principal. The hash list is reduced to a Group-Object on the hash column, and any group with Count greater than one is emitted as a finding. The check normalizes the NT hash to a 32-character hex string before grouping so that case or formatting variation does not split clusters. The empty-password hash 31d6cfe0d16ae931b73c59d7e0c089c0 is explicitly highlighted because it correlates with PASSWD_NOTREQD and the UF_PASSWD_NOTREQD bit in userAccountControl. The check also cross-references each cluster with adminCount = 1 and membership in protected groups so that clusters containing Tier-0 principals are escalated. Collection requires either DCSync rights (a Tier-0 operation, logged as Event ID 4662 with the GetChanges / GetChangesAll GUIDs on the domain object) or physical access to a DC backup with the SYSTEM hive. Guerrilla never writes plaintext hashes to disk; only the hash hash (a SHA-256 of the NT hash) plus cluster membership is persisted in the report.

Recommended value

No clusters of accounts sharing identical password hashes. Each account should have a unique password

Remediation

Extract and compare NT hashes using DCSync-capable tools (DSInternals) with appropriate authorization. Identify clusters of accounts sharing hashes. Force password changes on all accounts in duplicate clusters. Implement password filters to prevent common passwords and consider deploying Azure AD Password Protection

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-011
ScenarioExpected verdict
cleanPASS
known-badFAIL
no-dataNot Assessed

Framework mappings

NIST SP 800-53
IA-5(1)
CIS AD Benchmark
5.5.2
MITRE ATT&CK
T1110.002, T1078.002