Skip to content

DPAPI.py usage with PVK is broken#1165

Open
Nimretz wants to merge 3 commits intoPennyw0rth:mainfrom
Nimretz:main
Open

DPAPI.py usage with PVK is broken#1165
Nimretz wants to merge 3 commits intoPennyw0rth:mainfrom
Nimretz:main

Conversation

@Nimretz
Copy link

@Nimretz Nimretz commented Mar 19, 2026

Description

DPAPI.py's "get_domain_backup_key" ignores PVK file input as argument. All DPAPI modules (mobaxterm , putty , etc) are using that function which basically tries to export the domain backup key instead of using the provided PVK.

Type of change

Insert an "x" inside the brackets for relevant items (do not delete options)

  • 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 (list what type of assistance, tool(s)/model(s) in the description)

Setup guide for the review

when running "nxc smb target -u user -p pass --pvk caps_dpapi_backupkey.pvk -M mobaxterm -M putty"
you expect the modules to use the provided PVK. Instead - the "get_domain_backup_key" function tries to export the domain backup key from the DC. I modified the function to first check for PVK argument before trying to export the domain backup key.

Screenshots (if appropriate):

Screenshots are always nice to have and can give a visual representation of the change.
If appropriate, include before and after screenshot(s) to show which results are to be expected.

Checklist:

Insert an "x" inside the brackets for completed and relevant items (do not delete options)

  • 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)

DPAPI.py doesn't take into account PVK file input as argument.
All DPAPI modules are using that function which basically tries to export the domain backup key instead

Signed-off-by: Nimretz <71188380+Nimretz@users.noreply.github.com>
@NeffIsBack
Copy link
Member

Thanks for the bug fix PR!

Looks like a good catch, @zblurx what do you think? We should probably alter the way we are loading the pvk file here as well (move it to that function entirely):

NetExec/nxc/protocols/smb.py

Lines 2097 to 2105 in 8dbf09c

if self.args.pvk is not None:
try:
self.pvkbytes = open(self.args.pvk, "rb").read() # noqa: SIM115
self.logger.success(f"Loading domain backupkey from {self.args.pvk}")
except Exception as e:
self.logger.fail(str(e))
if self.pvkbytes is None:
self.pvkbytes = get_domain_backup_key(self)

@NeffIsBack NeffIsBack added the bug-fix This Pull Request fixes a bug label Mar 20, 2026
@zblurx
Copy link
Collaborator

zblurx commented Mar 23, 2026

Thanks for the bug fix PR!

Looks like a good catch, @zblurx what do you think? We should probably alter the way we are loading the pvk file here as well (move it to that function entirely):

NetExec/nxc/protocols/smb.py

Lines 2097 to 2105 in 8dbf09c

if self.args.pvk is not None:
try:
self.pvkbytes = open(self.args.pvk, "rb").read() # noqa: SIM115
self.logger.success(f"Loading domain backupkey from {self.args.pvk}")
except Exception as e:
self.logger.fail(str(e))
if self.pvkbytes is None:
self.pvkbytes = get_domain_backup_key(self)

Totally agree with you, we don't need to load the pvk file twice !

removed loading pk file twice in smb.py

Signed-off-by: zblurx <68540460+zblurx@users.noreply.github.com>

def get_domain_backup_key(context):
pvkbytes = None
if getattr(context.args, "pvk", None):
Copy link
Member

Choose a reason for hiding this comment

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

This should probably be if context.args.pvk is not None: because the arg always exists (so we don't have to check if it has that attr).

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

Labels

bug-fix This Pull Request fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants