Skip to content

Feature/rodc prp - #1338

Open
A3-N wants to merge 9 commits into
Pennyw0rth:mainfrom
A3-N:feature/rodc-prp
Open

Feature/rodc prp#1338
A3-N wants to merge 9 commits into
Pennyw0rth:mainfrom
A3-N:feature/rodc-prp

Conversation

@A3-N

@A3-N A3-N commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

rodc-prp is a Read Only Domain Controller Password Replication Policy for ldap. Read about it in specterops blog and 0xdeaddood thinking the idea was fairly cool. Tried to force this on an assessment, but couldn't get the opportunity without making too many changes. So the code here was ran on my lab. Hopefully next time I get to use this.
image

A 101, the RODC can have a RODC Password Replication Group with deny or allow. Each RODC has a dedicated krbtgt_* account and the RODC can also cache credentials. So, if you get local admin on this box, you have the cached creds, but the part I found interesting was the Key List Attack. Even if an account isn't cached, but can be cached/cacheable, you can use the krbtgt_* account's aes key to get the cacheable account's nt hash.

So with msDS-RevealOnDemandGroup are the cacheable account's and msDS-NeverRevealGroup is the non-cacheable or denied account's, which will omit, msDS-RevealOnDemandGroup if set as well. So using impacket's KeyListSecrets you forge a RODC's partial TGT for the cacheable account. The DC (writable KDC) will then validate on the RODC's PRP if this is allowed for the account in the ticket. The writeable KDC will then return the RC4-HMAC/nt hash. And since the ticket was forged, we have the material and can decrypt the response to get this. So this means you can get an account's nt hash, as long as its cacheable, and doesn't have to exist/be cached on the RODC itself.

I hope I did some justice to explaining for the 101, but everything was already there in impacket I didn't reinvent the wheel.

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
  • Some formatting checks to match nxc's 'vibe'. (first module and wanted to ensure the format matched others, instead of me reinventing code that already exists elsewhere)

Setup guide for the review

Mostly default, but the details as follows:

  • Tested on Ubuntu 26.04
    • python3.12 and python3.14
  • DC and RODC
    • Windows Server 2022 Standard
    • An account allowed through msDS-RevealOnDemandGroup
    • An account denied through msDS-NeverRevealGroup

Screenshots:

Context:

  • .10 DC
  • .20 RODC
  • tycho.admin has Read Property access to msDS-RevealOnDemandGroup and msDS-NeverRevealGroup
  • The assumption is that you already have a means to get the aes key for the krbtgt_* account on the RODC
  • belt.tech cacheable on RODC
  • tycho.admin not cacheable on RODC
nxc ldap -M rodc-prp --options
[*] rodc-prp module options:

RODC    Filter by RODC account name, short hostname, or FQDN
TARGET  Check sAMAccountName, or use ALL to check every domain account
RODCKEY AES256 key of the RODC krbtgt_* account; retrieves account NT hash

Use --verbose flag to show RODC and policy DNs.

Using the module with no options returns the value RODC computer account, TYCHO$ and its matching krbtgt_29727 account. If its ran on a non RODC, it will show the RODC's computer account before.
image

TARGET is a sAMAccountName, and this shows specific account's cacheable status vs the ALL which will find all cacheable accounts.
image

The RODCKEY value is the krbtgt_29727's aes key, which will most likely fail, because you're running on a read only KDC where the ticket needs to be sent to a writeable KDC. So you need the built in nxc flag, --kdcHost to be paired with this.
image
image

Some errors and debugging info to verify the right reasons are returned.
image
image
Invalid aes key
image
Read Only KDC specified with valid aes key
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)

@NeffIsBack

Copy link
Copy Markdown
Member

Sounds pretty cool, thanks for the PR, ima have to give it a read!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants