Skip to content

Feature/trust-keys (TDO secrets dump) - #1321

Open
Goultarde wants to merge 8 commits into
Pennyw0rth:mainfrom
Goultarde:feature/trust-keys
Open

Feature/trust-keys (TDO secrets dump)#1321
Goultarde wants to merge 8 commits into
Pennyw0rth:mainfrom
Goultarde:feature/trust-keys

Conversation

@Goultarde

Copy link
Copy Markdown
Contributor

Description

Exposes impacket secretsdump's trust key extraction (fortra/impacket#2207) through NetExec's smb --ntds.

Adds two new flags:

  • --trust-keys: in addition to the usual NTDS account secrets, dumps Trusted Domain Object (TDO) secrets and derives, for each trust direction (Incoming/Outgoing), the inter-realm Kerberos keys (AES256, AES128) and the RC4 (NT) hash, for both the current and the previous trust password.
  • --just-trust-keys: same extraction, but dumps ONLY the trust keys and skips account enumeration entirely (faster, quieter, no NTDS account secrets).

Also fixes two pre-existing bugs in smb.py's NTDS output handling that surfaced while wiring this in:

  • The status-stripping logic in add_hash() blindly dropped the last space-separated word of every secret line (meant to strip the trailing "Enabled"/"Disabled" on account lines), which truncated trust key lines since their direction label ((Incoming, previous)) also contains spaces. Now only strips the last word when it's actually a status.
  • --enabled silently dropped all trust key lines entirely, since they have no account "Enabled"/"Disabled" status to match against. Trust keys are now always shown with --enabled, except previous-password trust keys (trust equivalent of history), which are excluded like disabled/history entries are.

Dependency: requires impacket built from a commit that includes fortra/impacket#2207 (already the case since NetExec pulls impacket from git+https://github.com/fortra/impacket HEAD in pyproject.toml; poetry.lock needs to be refreshed to a commit at or after the merge).

This change was implemented with the assistance of Claude Code (Sonnet 5): it wrote the flag wiring, the fixes to add_hash(). I reviewed and directed each change.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Deprecation of feature or functionality
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)
  • This PR was created with the assistance of AI (Claude Code, Sonnet 5: implementation wiring and bug fixes, feature design and testing done by me, see Description)

Setup guide for the review

Tested against a Windows Server 2022 (build 20348) Domain Controller in a domain (serval.int) with multiple trusts (incoming, outgoing, bidirectional, and a one-way external trust). Authenticated with -k (Kerberos).

  • Bug fix (status-stripping / --enabled): run --ntds --trust-keys (or --just-trust-keys) against a DC with at least one trust configured; without the fix, trust key lines show truncated (e.g. dev.serval.int (Incoming, with the hash missing) and disappear entirely when --enabled is added.
  • New feature: requires DS-Replication-Get-Changes rights (Domain Admin or equivalent) on the target DC, same privileges as any DCSync/--ntds dump. No additional GPO or registry changes needed. Both the online DRSUAPI path and --ntds vss were exercised.

Commands used:

netexec smb $DC_IP -u $USER -p $PASSWORD -k --ntds --trust-keys
netexec smb $DC_IP -u $USER -p $PASSWORD -k --ntds --just-trust-keys
netexec smb $DC_IP -u $USER -p $PASSWORD -k --ntds --trust-keys --enabled

Screenshots (if appropriate):

netexec smb $DC_IP -u $USER -p $PASSWORD -k --ntds --trust-keys
image
netexec smb $DC_IP -u $USER -p $PASSWORD -k --ntds --just-trust-keys
image
netexec smb $DC_IP -u $USER -p $PASSWORD -k --ntds --just-trust-keys --enabled
image

Checklist:

  • I have ran Ruff against my changes (poetry: poetry run ruff check ., use --fix to automatically fix what it can)
  • I have added or updated the tests/e2e_commands.txt file if necessary (new modules or features are required to be added to the e2e tests)
  • If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
  • I have linked relevant sources that describes the added technique (blog posts, documentation, etc)
  • I have performed a self-review of my own code (not an AI review)
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)

Expose impacket secretsdump's trust key extraction (fortra/impacket#2207)
through NetExec's --ntds: dumps Trusted Domain Object secrets and derives
inter-realm Kerberos (AES256, AES128) and RC4 keys for each trust direction.

Also fixes the account-line status stripping in add_hash(), which blindly
dropped the last space-separated word of every secret line (meant to strip
the trailing "Enabled"/"Disabled" on account lines) and was truncating the
trust key lines, which contain spaces but no status suffix.
Like --trust-keys but skips account enumeration entirely (implied --just-dc
behavior in impacket), emitting only the trust keys. Useful when only the
inter-realm keys are needed, for a faster and quieter dump.
--just-trust-keys reused the regular NTDS dump summary ("NTDS hashes",
"added to the database", grep-disabled hint), which is meaningless
when only trust keys are dumped (no accounts are enumerated). Show a
summary specific to that mode instead.
Trust key lines never contain "Enabled"/"Disabled" (they have no account
status), so the --enabled filter silently dropped them entirely. Detect
trust key lines and always show them regardless of --enabled.

@NeffIsBack NeffIsBack left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi and thanks for the PR!

Does rc4_hmac refer to the nt hash? Maybe we should align it with the original ntds output, also in respect to dumping the kerberos keys only when --kerberos-keys is specified.

Comment thread nxc/protocols/smb.py Outdated
printUserStatus=True,
trustKeys=self.args.trust_keys,
justTrustKeys=self.args.just_trust_keys,
domainFQDN=self.domain,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That must be self.targetDomain

@NeffIsBack NeffIsBack added the enhancement New feature or request label Jul 19, 2026
@Goultarde

Goultarde commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

Hi, wdym by "Maybe we should align it with the original ntds output"? Do you mean deleting the rc4_hmac label? (cause I hardcoded it on the impacket side too)

For --kerberos-keys: you're right, I forgot to gate the AES derivation behind justNTLM in impacket, it always dumped RC4+AES256+AES128 for trust keys regardless of -just-dc-ntlm. I'm opening a PR for that on impacket now, will link it here once it's up.

For now, i'm changing self.domain into self.targetDomain.

@Goultarde

Copy link
Copy Markdown
Contributor Author

Merged into Impacket.

It looks fine now:
image

However, I think we should use --history instead of --enabled. But this would require another Impacket PR :/

@mpgn

mpgn commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Noob question but why not dump the trusted key by default with --ntds ?
image

by why not juste --ntds and it also dump the trusted key ? if the guy only want trusted is use --just-trusted-keys ?

@Goultarde

Copy link
Copy Markdown
Contributor Author

Hi! That’s a fair question.
To me, it felt natural to keep -just-dc and -trust-keys separate in Impacket, since they work differently and produce different output.
However, I don’t think merging them under --ntds would be unreasonable either.
I’m just not sure which approach is best.

Noob question but why not dump the trusted key by default with --ntds ? image

by why not juste --ntds and it also dump the trusted key ? if the guy only want trusted is use --just-trusted-keys ?

@mpgn

mpgn commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Hi! That’s a fair question. To me, it felt natural to keep -just-dc and -trust-keys separate in Impacket, since they work differently and produce different output. However, I don’t think merging them under --ntds would be unreasonable either. I’m just not sure which approach is best.

Noob question but why not dump the trusted key by default with --ntds ? image
by why not juste --ntds and it also dump the trusted key ? if the guy only want trusted is use --just-trusted-keys ?

yeah but for exemple "-just-dc" doesn't exist in nxc, the logic is not the same as impacket-secretdump who dump sam, lsa, ntds and can target remote or local, server or dc, in our case we know "--ntds" will target a DC and the privilege to dump is already granted and dump the trust key doesn't cost if you are already dumping the ntds.

I would keep --just-trust-keys but --trust-key is one more option you need to remember which doesn't bring much.

@Goultarde

Copy link
Copy Markdown
Contributor Author

Seems right to me. I'll change this later. 👍

mpgn added 2 commits August 31, 2026 21:45
Signed-off-by: mpgn <5891788+mpgn@users.noreply.github.com>
Set default value for --trust-keys argument to True.

Signed-off-by: mpgn <5891788+mpgn@users.noreply.github.com>
@mpgn

mpgn commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Should be good if you want to test it :)

@NeffIsBack

Copy link
Copy Markdown
Member

Is it possible to separate it visually from the other output (e.g. adding a .success() log or something)? What about the output file, will it be dumped into the same file?
Might cause issues with parsing if the output has a different structure but it is in the same file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants