← All field notes
Evidence HandlingQuick reference

Parsing NetExec NTDS and NetNTLM Output

What the colon-delimited fields in NTDS and NetNTLM files represent, and how to extract usernames or cracking input without mixing the formats.

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.

Source references