Dumping NTDS.dit and cracking every password in the domain
How domain hashes get extracted from NTDS.dit with secretsdump, how to feed the NT hashes to hashcat, map them back to users, and detect a DCSync.
Dumping NTDS.dit is the endgame. Once you have every password hash in the domain, the engagement stops being about access and starts being about what the passwords tell you. And they always tell you something.
The domain's hashes live in NTDS.dit, the Active Directory database, which sits on every domain controller. The hashes inside it are encrypted with the boot key, which you derive from the SYSTEM registry hive. So you need two things: the database and the hive, or the replication rights to skip both.
Getting the hashes out
Impacket's secretsdump.py is the tool. If you have an account with replication rights (Domain Admins, or anything granted the Get-Changes-All extended right), do a DCSync and pull everything remotely:
secretsdump.py -just-dc -dc-ip 10.0.0.10 contoso.local/administrator@10.0.0.10
-just-dc tells it to use the directory replication service to request the secrets, exactly the way one DC syncs from another. You never log into the box. If you would rather skip the krbtgt and trust keys, -just-dc-ntlm gives you only the NT hashes.
The other path is offline, from a copy of the files. If you can get a shadow copy of the DC's volume (via vss or ntdsutil "activate instance ntds" "ifm" "create full c:\temp"), you pull ntds.dit and the SYSTEM hive and point secretsdump at the local files:
secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL
Either way the output is one line per account in this format:
contoso.local\jsmith:1104:aad3b435b51404eeaad3b435b51404ee:64f12cddaa88057e06a81b54e73b949b:::
That is user:rid:lmhash:nthash:::. The RID is the relative identifier, the aad3b435... is the empty LM placeholder, and the field you care about is the NT hash.
Cleaning it up before you crack
Two things to strip first.
Machine accounts. Every computer in the domain has an account ending in $, and its password is 120 random characters that rotate automatically. Cracking those is pointless, so drop every line where the username ends in $.
The empty LM column. Unless you are on an ancient domain, every account shows the same aad3b435b51404eeaad3b435b51404ee because LM hashes have not been stored by default since Server 2008. LM only matters on genuinely old domains, and if you do find real LM hashes there, they crack trivially with mode 3000. Otherwise ignore the column entirely.
What you want is the NT hash column, isolated, for user accounts only.
Feeding hashcat
The NT hash goes to hashcat mode 1000. If you ever need a refresher on which mode matches which NTLM hash format, the hashcat mode lookup walks through it. Keep the user:hash lines intact and use --username so hashcat ignores the username field for cracking but keeps it for the output:
hashcat -m 1000 --username ntds.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
NT hashes are unsalted and fast, so a full domain dump cracks at billions per second on a single GPU. The first pass with rockyou and a rule set will usually clear a third to half of a typical enterprise overnight. Then escalate: bigger wordlists, mutated company-specific terms, masks for the obvious patterns.
When you want to read results back later, do not re-run the crack. Use the potfile:
hashcat -m 1000 --username --show ntds.txt
That prints user:hash:plaintext for everything already in the pot, so you map cracked passwords straight back to the accounts that used them.
What the cracked set tells you
This is where the value is, and it is rarely about any single account. It is about reuse.
Sort the cracked passwords by frequency. You will find the same password on dozens of accounts, almost always the help-desk reset value (Welcome1, Company2024!) that nobody changed. You will find service accounts sharing a password with their owner's personal account. You will find the domain admin's password is one character off the password you cracked from a workstation local admin three steps ago. The reuse map is the real loot, because it shows you which credentials unlock which tiers, and it is what you hand the client as the finding that actually changes behavior.
The defender's side
Detect the DCSync. The replication request shows up as event ID 4662 (an operation on a directory object) referencing the replication control access rights, specifically the GUIDs for Get-Changes (1131f6aa-...) and Get-Changes-All (1131f6ad-...). Legitimately, only domain controllers replicate. So a 4662 with those GUIDs sourced from anything that is not a DC is a DCSync in progress. Alert on it, hard.
Structurally, the fix is the administrative tiering model. Tier 0 (the DCs and the accounts that can touch them) stays isolated from the workstations and servers where credentials get harvested. If the only accounts with replication rights are tightly held tier-0 identities that never log into lower tiers, the path to a DCSync stops existing.
Control physical and backup access to the DC too. An attacker who can grab a VM snapshot, a backup, or a shadow copy of the disk gets ntds.dit and the SYSTEM hive with no replication rights and no detection. Treat DC backups as tier-0 secrets, because that is exactly what they are.
And the one that limits the damage after a dump: long, unique passwords. A domain where the answer to "how many accounts cracked overnight" is single digits is a domain that did password policy and reuse hygiene right. Most are not that domain yet.