NTDS password records and captured NetNTLM challenge responses are different credential material. Both use colons, but the fields are not interchangeable.
| Source | Typical saved artifact | What it contains |
|---|---|---|
| NetExec or Impacket NTDS dump | *.ntds |
Account name, RID, LM hash, NT hash, and sometimes account status |
ntlmrelayx -of <PREFIX> |
Files with NTLM or NTLMv2 suffixes | Complete network challenge-response records |
| NetExec terminal or log output | Protocol, host, port, and status prefixes around a result | Display output that should not be parsed as a clean NTDS record |
The commands below operate on a saved NetExec or Impacket artifact, not copied terminal output.
Inspect the file first
NetExec currently stores NTDS exports under its logs/ntds directory and gives the file an .ntds suffix. Locate the file, then inspect several rows before selecting fields:
find ~/.nxc/logs/ntds -type f -name '*.ntds'
head -n 3 <NETEXEC_NTDS_FILE>
Work on a protected copy of the evidence and keep the original unchanged.
Read an NTDS row
A current NetExec or Impacket NTDS row has this shape:
<DOMAIN>\<ACCOUNT>:<RID>:<LM_HASH>:<NT_HASH>::: (status=<STATUS>)
With awk -F:, the colon is the field separator:
| awk field | NTDS value | Useful for |
|---|---|---|
$1 |
DOMAIN\account |
Account inventories and username files |
$2 |
RID | Correlating the record with the account SID |
$3 |
LM hash | Legacy password-hash analysis |
$4 |
NT hash | Hashcat mode 1000 or authorized pass-the-hash validation |
The old generic example printed $2, which extracts the RID from an NTDS row. It does not extract a username or an NT hash.
Produce an account list
This prints the account key from every NTDS row:
awk -F: '{ print $1 }' <NETEXEC_NTDS_FILE> > accounts.txt
For an enabled human-account list, omit disabled rows, machine accounts ending in $, and password-history records. !seen[$1]++ prints only the first row for each remaining account key:
awk -F: '
$0 !~ /\(status=Disabled\)/ &&
$1 !~ /\$$/ &&
$1 !~ /_history[0-9]+$/ &&
!seen[$1]++ { print $1 }
' <NETEXEC_NTDS_FILE> > enabled_user_accounts.txt
Some tools expect a bare username rather than DOMAIN\username. This removes the domain prefix from the first field:
awk -F: '{ account=$1; sub(/^.*\\/, "", account); print account }' \
enabled_user_accounts.txt > usernames.txt
Use the domain-qualified file when duplicate names can exist across domains. A bare username list loses that context.
Produce NT-hash input
The fourth NTDS field is the NT hash. This writes one hash per enabled human account for Hashcat mode 1000:
awk -F: '
$0 !~ /\(status=Disabled\)/ &&
$1 !~ /\$$/ &&
$1 !~ /_history[0-9]+$/ &&
length($4) == 32 &&
!seen[$4]++ { print $4 }
' <NETEXEC_NTDS_FILE> > users.ntlm
hashcat -m 1000 users.ntlm <WORDLIST>
Deduplicating on $4 avoids testing the same password hash repeatedly, but it removes the account-to-hash mapping. Preserve the original evidence or create a separate DOMAIN\user:hash file when attribution is needed. The NTDS Hash Filter handles those output formats and validates records more carefully than a short awk command.
Keep NetNTLM captures intact
A NetNTLM capture is a network challenge response, not the NT hash stored in NTDS. Hashcat uses mode 5500 for NetNTLMv1 and mode 5600 for NetNTLMv2. The complete captured line is the cracking input; extracting $1, $2, or $4 destroys required fields.
For a NetNTLMv2 capture saved as NETLMV2_ntlmv2, keep the first capture for each username, exclude machine accounts such as MACHINE$, and print the complete capture line:
awk -F: '$1 !~ /\$/ && !seen[$1]++' NETLMV2_ntlmv2 > unique_netntlm.txt
Because the condition has no action, awk prints $0, preserving the fields required by Hashcat. !seen[$1]++ keeps only the first occurrence for each username; later captures for that username are discarded.
Verify the reduction
Count the source and result and inspect the first few derived rows before using them:
wc -l <SOURCE_FILE> <DERIVED_FILE>
head -n 3 <DERIVED_FILE>
If the row shape differs from the examples above, stop and check the installed NetExec, Impacket, or capture-tool version instead of changing field numbers until the output looks plausible.
Protect derived files
Parsing does not make a dump safe. Keep the source and derived files out of Git, use restrictive permissions, and remove working copies according to the assessment’s evidence-retention rules.