Analyze an NTDS.dit / pwdump for password reuse, weak/cracked passwords, and — with an optional BloodHound export — which of those accounts are actually live. A faster, batteries-included take on Pipal for AD credential audits, built for output that reads clearly in a screenshot and drops straight into a report.
Pure Python standard library. No dependencies.
A raw NTDS dump tells you the hashes but not the story. hashstat turns it into the
findings you actually report:
- Reuse — how many accounts share a password, the biggest clusters, and who is in
them (admins, service accounts, tier-crossing
a_user↔userpairs). - Weak — which passwords fell to a wordlist (reads John's pot), and the overlap of shared and weak.
- Live risk — join a BloodHound
users.jsonand disabled accounts are excluded by default, so your reset list is only real, usable accounts. adminCount / SPN get tagged. - Hand-off lists — cracked accounts, LM-enabled accounts, no-password accounts, and disabled accounts, each exportable as CSV and redactable for sharing.
No install needed — it's a single file:
./hashstat.py <NTDS_FILE>Input is a standard pwdump / secretsdump line (a leading SMB <ip> 445 <HOST> NetExec
banner is tolerated):
domain\user:rid:lmhash:nthash:::
Optionally install as a command:
pip install . # provides the `hashstat` entrypoint# everything, using John's cracked pot + BloodHound enrichment
./hashstat.py ntds.dit -a --bloodhound users.json
# offline demo against the bundled synthetic sample (no John needed)
./hashstat.py sample/ntds.dit.sample -a --potfile sample/ntds.dit.sample.pot --bloodhound sample| Flag | Shows |
|---|---|
-o, --overview |
account/domain census + affected total (reuse OR weak) |
-r, --reuse |
shared-password clusters (cracked plaintext shown inline) |
-p, --privileged |
the "security story": admin / service / tier-crossing reuse |
-w, --weak |
clusters whose shared password was also cracked |
-c, --cracked |
cracked-password stats |
-u, --cracked-users |
per-user cracked list (reset hand-off) |
-l, --lm-users |
accounts with an LM hash enabled |
-b, --blank-users |
accounts with NO password (blank NT hash) |
-D, --disabled-users |
disabled accounts (needs --bloodhound) |
-g, --groups |
full reuse-group membership, categorized |
-y, --hygiene |
username==password, LM, blanks (+ positives) |
-a, --all |
every analysis section |
The overview renders in several styles via --view (default plain):
./hashstat.py ntds.dit --view tree # grouped Scope / Credentials / Risk rollup
./hashstat.py ntds.dit --view bars # horizontal bars, grouped so small risk counts stay visible
./hashstat.py ntds.dit --view bars-pct # every metric as a % of analyzed accounts
./hashstat.py ntds.dit --view domains # per-domain distribution bars
./hashstat.py ntds.dit --view sankey # a 2D flow diagram (needs a ~100-col terminal)
./hashstat.py ntds.dit --view all # show them all
./hashstat.py ntds.dit -v # -v is shorthand for --view all (safe to cluster, e.g. -av)Comma-separate to combine, e.g. --view tree,domains. -v takes no value — use the
long --view NAME to pick a single view.
hashstat doesn't crack — it reads results you already have, from John or hashcat,
for both NT and LM:
# John: crack NT and/or LM, then just run -- hashstat calls `john --show` for both
john --format=nt --wordlist=rockyou.txt ntds.dit
john --format=lm --wordlist=rockyou.txt ntds.dit
./hashstat.py ntds.dit -a # auto: john --show (NT+LM) + hashcat's potfile
# hashcat: crack, then point at (or auto-find) its potfile
hashcat -m 1000 nt_hashes rockyou.txt # NT
hashcat -m 3000 lm_hashes rockyou.txt # LM (per 7-char half)
./hashstat.py ntds.dit -a # auto-finds ~/.local/share/hashcat/hashcat.potfile
./hashstat.py ntds.dit -a --potfile hashcat.potfile # or point at any john/hashcat potfileWhen a password is recovered only from its LM hash it's UPPERCASE (LM is
case-insensitive); those accounts are counted as cracked and tagged LM in the -u
list. A true-case NT crack always wins when both exist.
./hashstat.py ntds.dit -a --bloodhound users.json # users file (sibling groups.json auto-found)
./hashstat.py ntds.dit -a --bloodhound ./bloodhound/ # or a dir containing the BloodHound jsonJoins on the SID's RID (falling back to sAMAccountName) and pulls enabled, admincount,
hasspn, pwdneverexpires, pwdlastset, lastlogontimestamp, passwordnotreqd. If a
BloodHound groups file is present (in the dir, or a sibling of the users file), it also
resolves exact Domain Admin / Enterprise Admin / Administrators membership (following
nested groups).
Disabled accounts are excluded from analysis by default and surface under -D instead
(review for deletion, not reset). Use --include-disabled to analyze them too.
With enrichment the overview also reports ntdsaudit-style account-hygiene stats for the active set — no-password-required, non-expiring password, stale password (>90d / >1yr), unused account (>90d / >1yr), adminCount, SPN, and LM-hash counts.
# reset hand-off list, live accounts only, as CSV
./hashstat.py ntds.dit -u --bloodhound users.json --csv > reset_list.csv
# accounts to delete rather than reset
./hashstat.py ntds.dit -D --bloodhound users.json --csv > delete_list.csv
# redact passwords + hashes (stable pw-NN aliases) — safe to screenshot/share
./hashstat.py ntds.dit -a -s--csv follows the selected list (-u/-l/-b/-D, else cracked). -s/--screenshot
replaces every password and NT hash with a stable alias so a shared screenshot still shows
which accounts share a secret without revealing it.
The repo ships a fully synthetic, fictional (ACME) dataset so you can try every feature offline — no real credentials, nothing to generate:
sample/ntds.dit.sample— 5,000 users (+ machine accounts) with real NT & LM hashessample/ntds.dit.sample.pot— John potfile covering every passwordsample/ntds.dit.sample.bloodhound.users.json— matching BloodHound users export (with disabled accounts)sample/ntds.dit.sample.bloodhound.groups.json— BloodHound groups (Domain/Enterprise/builtin Admins)
Passwords come from a public wordlist so john cracks them all.
Real engagement dumps must never be committed. .gitignore blocks NTDS/SAM/secrets/
kerberos files, cracked-credential lists, and John pots; only the synthetic sample/
files are whitelisted. Keep it that way.
Account-hygiene stat set inspired by dionach/ntdsaudit.
