Releases: StrongWind1/NTDSWolf
v0.4.1
Unifies the generic fallback decoder with the v0.4.0 _unmapped passthrough, so dissect's internal columns are never surfaced and every class has a consistent shape.
Changed
- The generic fallback decoder (used for object classes without a specialised decoder) no longer dumps a flat
as_dict()at the top level. That leaked dissect's internal structural columns (Obj,Time,CNT, ...) because its column-exclusion list had the wrong casing, and it dropped every top-level attribute on objects with a single undecodable attribute (e.g. a schemaattributeID). It now adds no class-specific fields and relies on the same robust_unmappedpassthrough every class uses, so generic objects have the identical shape (common attributes +_unmapped) and dissect internals are never surfaced.
Install
uv tool install git+https://github.com/StrongWind1/NTDSWolf@v0.4.1Full changelog: https://github.com/StrongWind1/NTDSWolf/blob/main/CHANGELOG.md · Docs: https://strongwind1.github.io/NTDSWolf/
v0.4.0
Makes "dump everything" the default — every object now carries a complete _unmapped raw-attribute passthrough, bringing attribute coverage to parity with, and beyond, ntdissector.
Added
- Every object now carries an
_unmappedfield in the structured formats (NDJSON/JSON/CSV): a raw passthrough of every stored LDAP attribute and linked attribute the curated decoders did not already parse, so nothing in the database is dropped (NTDSWolf's primary goal). Values are kept verbatim when printable ASCII (0x20-0x7E) and hex-encoded otherwise; dissect's internal structural columns and already-curated attributes are excluded. Enumeration is per-attribute and falls back to the raw value, so a single undecodable attribute (e.g. a schemaattributeIDwith no OID mapping) no longer drops the rest. This brings attribute coverage to parity with, and beyond, ntdissector. The hashcat and pwdump outputs are unaffected.
Install
uv tool install git+https://github.com/StrongWind1/NTDSWolf@v0.4.0Full changelog: https://github.com/StrongWind1/NTDSWolf/blob/main/CHANGELOG.md · Docs: https://strongwind1.github.io/NTDSWolf/
v0.3.0
Reworks the credential output formats and brings the secretsdump-compatible pwdump/hashcat output to byte-for-byte parity.
Breaking: the John the Ripper format and the no-op
--rawflag are removed, and the hashcat/pwdump output filenames change. See Removed / Changed below.
Added
--hashcat-usernameselects the username field in hashcat output lines:sam(sAMAccountName, the default),upn,rid, orsid.- Structured output (NDJSON/JSON/CSV) now captures the previous-password and service Kerberos key sets from
supplementalCredentials-- theKERB_STORED_CREDENTIAL_NEWOldCredentials/OlderCredentials/ServiceCredentialsarrays -- underkerberosOld/kerberosOlder/kerberosService, alongside the currentkerberoskeys. These were previously dropped, yet every computer account (and any password-changed user) carries them. The hashcat and pwdump outputs are unchanged: they still emit only the current key set, matching secretsdump. - Every credentialed object now includes
supplementalCredentialsRaw: the complete decodedsupplementalCredentialsstructure verbatim -- every package (including the legacyPrimary:Kerberosand thePackageslist), the default salt and iteration count, and all four key arrays, with byte values hex-encoded and nothing curated away.
Changed
- Reworked the hashcat output into per-class
username:hashfiles forhashcat --username(ntlm_<type>_current.txt,ntlm_<type>_history.txt,lm_<type>_current.txt,lm_<type>_history.txt), split by object class, hash type, and age. LM hashes are emitted as their two 8-byte halves (mode 3000). Kerberos keys are no longer written to the hashcat output -- they are pass-the-key material, not hashcat-crackable hashes. - The pwdump format now emits secretsdump's "newer pwdump" file set, byte-for-byte compatible with
impacket-secretsdump -outputfile:hashes.ntds(username:rid:lm:nt:::with inlineusername_historyNlines),hashes.ntds.kerberos(username:<etype>:<key>, lowercase etypes, no RC4), andhashes.ntds.cleartext(username:CLEARTEXT:<password>).
Removed
- The John the Ripper output format (
--format john); usehashcatorpwdump. - The
--rawflag, which never had any effect. The completeness it implied is now always on viasupplementalCredentialsRaw(see Added).
Fixed
- The pwdump
hashes.ntds.kerberosfile omitted thedec-cbc-crc(DES-CBC-CRC) andrc4_hmacKerberos keys on Windows Server 2008 databases, which store five KeyTypes insupplementalCredentials(2016+ store three). The writer now keys on the numeric Kerberos KeyType, mirroringimpacket'sKERBEROS_TYPEtable exactly (including the0xFFFFFF74RC4 marker and thedec-cbc-crcspelling), sohashes.ntds.kerberosis byte-identical to secretsdump across Server 2008-2022. - Password history (
ntPwdHistory/lmPwdHistory) was silently dropped for every account, sohashes.ntdswas missing all_historylines. dissect returns the blob wrapped in a one-element list (which failed anisinstance(bytes)check), and the AES PEK layer was PKCS7-unpadded, stripping the trailing block secretsdump keeps. History is now decrypted faithfully andhashes.ntdsis byte-identical tosecretsdump -historyacross the RC4 and AES eras (Windows Server 2008-2022). The AES padding block is kept for exact parity (secretsdump emits it as a history entry); because it is not a real password, NTDSWolf logs a stderrWARNINGnaming each account whose history decrypts to more hashes than itsSecretLengthdeclares. - Removed the redundant
--exclude-deletedflag;--include-deletedis now a single switch (deleted objects are excluded by default).
Install
uv tool install git+https://github.com/StrongWind1/NTDSWolf@v0.3.0Full changelog: https://github.com/StrongWind1/NTDSWolf/blob/main/CHANGELOG.md · Docs: https://strongwind1.github.io/NTDSWolf/
v0.2.0
First public release of NTDSWolf — a pure-Python offline NTDS.dit parser and credential extractor for Active Directory forensics, penetration testing, and security auditing.
Added
- Kerberos keys (AES256/AES128/RC4/DES), WDigest, cleartext, and NTLM-Strong-NTOWF extraction, surfaced from dissect's decoded
supplementalCredentials. Verified against real databases (Windows Server 2012/2016/2019). - Kerberos keys are written to
kerberos_keys.txt(principal:etype:key) in the hashcat and pwdump outputs for pass-the-key use. - Per-class decoder registry is now the live decode path (replacing the simplified inline decoder).
- Working
--workers Nmultiprocessing extraction (fork-based), verified to produce byte-identical output to single-threaded. - Inter-realm trust keys: decrypt
trustAuthIncoming/trustAuthOutgoingand derive each trust account's RC4-HMAC (= NT hash) and AES-256/AES-128 keys (Kerberos string-to-key with the<REALM>krbtgt<FLATNAME>salt). Both-direction keys are written tokerberos_keys.txt. Verified against a real inter-forest trust. - LAPS extraction: v1 plaintext (
ms-Mcs-AdmPwd), v2 cleartext (msLAPS-Password), and v2 encrypted (msLAPS-EncryptedPassword) decrypted offline through the MS-GKDI / DPAPI-NG chain (adds thedpapi-ngdependency, which provides the offline root-key derivation and CMS parsing the online-only RPC path lacks). Verified to reproduce the live LAPS password. - gMSA / dMSA managed passwords derived entirely offline from the KDS root key +
msDS-ManagedPasswordId+ account SID (MS-GKDI). The 256-bytemanagedPasswordself-verifies (its MD4 is the account's NT hash). Standalone (sMSA), group (gMSA), and delegated (dMSA, Server 2025) accounts route to credential-aware decoders; their NT hash + Kerberos keys round-trip-authenticate against a live DC. msDS-KeyCredentialLinkparsing for Windows Hello for Business / FIDO2 / shadow-credential keys.
Changed
- Lowered the minimum supported Python from 3.14 to 3.11, widening the install base; CI now tests the full 3.11-3.14 range. Two 3.14-only constructs were made portable:
overridenow imports fromtyping-extensions(a new, lightweight dependency), and the unparenthesized multi-exceptionexceptclauses (PEP 758) are parenthesized. - Removed the impacket runtime dependency. The three primitives it provided -- Kerberos AES string-to-key (RFC 3961/3962), per-RID DES key derivation ([MS-SAMR] 2.2.11.1.2-2.2.11.1.3), and the LAPS v2 timestamp header -- are now implemented directly from their specifications and validated against the RFC 3962 Appendix B test vectors. This also drops flask, ldap3, pyasn1, pyopenssl, and six from the install footprint.
- Output is now cross-validated as byte-identical to impacket-secretsdump on Windows Server 2008R2/2016/2022 (RC4 and AES eras).
- No-password accounts (e.g. Guest) are emitted with the empty NT hash, matching impacket.
- Structured output filenames now use a documented friendly-name map (
user->users.ndjson,trustedDomain->trusts.ndjson) with a sanitized fallback for uncommon classes, replacing the naiveobjectClass + "s"pluralization (which produced names likedHCPClasss). --extractnow filters the hash formats (hashcat/john/pwdump) as well as the structured ones, so a users-only run no longer leaks machine-account hashes.
Fixed
--extractplural names (users,groups) andallnow select correctly instead of silently matching nothing.- SID RID endianness: the last sub-authority is read big-endian, fixing both garbage RIDs and the NT hashes that depend on the RID for DES un-obfuscation.
- A malformed
--systemhive no longer crashes boot-key resolution.
Install
uv tool install git+https://github.com/StrongWind1/NTDSWolf@v0.2.0Full changelog: https://github.com/StrongWind1/NTDSWolf/blob/main/CHANGELOG.md · Docs: https://strongwind1.github.io/NTDSWolf/