Skip to content

Conversation

@ruycr4ft
Copy link

Problem Description

In Impacket v0.13.0 and v0.14.0, the secretsdump.py script fails to extract user hashes when performing a parse of an NTDS.dit file from a Read-Only Domain Controller (RODC). The script successfully finds and decrypts the PEK (Password Encryption Key) but outputs no user credentials, exiting silently. This is a regression from v0.12.0, which parses the same RODC file correctly.

Root Cause

The bug is located in the NTDSHashes class's main record-processing loop (the while True: loop using __ESEDB.getNextRow()). A filtering condition incorrectly excludes all relevant user records from an RODC database.

The condition in question was:

if record[self.NAME_TO_INTERNAL['sAMAccountType']] in self.ACCOUNT_TYPES and record[self.NAME_TO_INTERNAL['instanceType']] & 4:

The check record[self.NAME_TO_INTERNAL['instanceType']] & 4 evaluates whether the instanceType attribute has bit 4 (0x4) set. According to Microsoft documentation, this bit indicates "The object is writable on this directory."

This condition is valid for objects on a writable Domain Controller. However, on an RODC, all replicated objects are read-only. Therefore, this bit is not set for user account records within an RODC's NTDS.dit. Consequently, the if statement evaluates to False for every RODC user record, causing the loop to silently skip them and produce no output.

Proposed Fix

Remove the instanceType & 4 check from the filtering condition for the offline NTDS.dit parsing path. The check for sAMAccountType is sufficient to identify user and computer accounts.

Change from:

if record[self.NAME_TO_INTERNAL['sAMAccountType']] in self.ACCOUNT_TYPES and record[self.NAME_TO_INTERNAL['instanceType']] & 4:

Change to:

if record[self.NAME_TO_INTERNAL['sAMAccountType']] in self.ACCOUNT_TYPES:

Testing performed

With Impacket v0.14.0 (happens the same with v0.13.0):

(venv) ➜  examples git:(master) ./secretsdump.py local_admin:'password@1'@192.168.100.2 -use-vss
Impacket v0.14.0.dev0+20260116.125256.a0bc463b - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: <boot_key>
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:<...>:<...>:::
Guest:501:<...>:<...>:::
DefaultAccount:503:<...>:<...>:::
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] $MACHINE.ACC
DOMAIN\RODC$:aes256-cts-hmac-sha1-96:<...>
DOMAIN\RODC$:aes128-cts-hmac-sha1-96:<...>
DOMAIN\RODC$:des-cbc-md5:<...>
DOMAIN\RODC$:plain_password_hex:<...>
DOMAIN\RODC$:<...>:<...>:::
[*] DPAPI_SYSTEM
dpapi_machinekey:<...>
dpapi_userkey:<...>
[*] NL$KM
<...>
NL$KM:...
[*] Searching for NTDS.dit
[*] Registry says NTDS.dit is at C:\Windows\NTDS\ntds.dit. Calling vssadmin to get a copy. This might take some time
[*] Using smbexec method for remote execution
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: <PEK>
[*] Reading and decrypting hashes from \\192.168.100.2\ADMIN$\Temp\tmQQrlOk.tmp
[*] Cleaning up...
(venv) ➜  examples git:(master)

Sensitive information has been replaced with <...>. As you can notice, the NTDS.dit dump reports nothing.

With Impacket v0.12.0:

(venv) ➜  examples git:(master) secretsdump.py local_admin:'password@1'@192.168.100.2 -use-vss
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: <...>
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:<...>:<...>:::
Guest:501:<...>:<...>:::
DefaultAccount:503:<...>:<...>:::
[-] SAM hashes extraction for user WDAGUtilityAccount failed. The account doesn't have hash information.
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] $MACHINE.ACC
DOMAIN\RODC$:aes256-cts-hmac-sha1-96:<...>
DOMAIN\RODC$:aes128-cts-hmac-sha1-96:<...>
DOMAIN\RODC$:des-cbc-md5:<...>
DOMAIN\RODC$:plain_password_hex:<...>
DOMAIN\RODC$:<...>:<...>:::
[*] DPAPI_SYSTEM
dpapi_machinekey:<...>
dpapi_userkey:<...>
[*] NL$KM
 <...>
NL$KM:<...>
[*] Searching for NTDS.dit
[*] Registry says NTDS.dit is at C:\Windows\NTDS\ntds.dit. Calling vssadmin to get a copy. This might take some time
[*] Using smbexec method for remote execution
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: <...>
[*] Reading and decrypting hashes from \\192.168.100.2\ADMIN$\Temp\FFccPdMD.tmp
DC$:1000:<...>:<...>:::
RODC$:1602:<...>:<...>:::
Guest:501:<...>:<...>:::
Administrator:500:<...>:<...>:::
krbtgt:502:<...>:<...>:::
krbtgt_XXXX:1603:<...>:<...>:::
domain.local\local_admin:3102:<...>:<...>:::
[*] Kerberos keys from \\192.168.100.2\ADMIN$\Temp\FFccPdMD.tmp
RODC$:aes256-cts-hmac-sha1-96:<...>
RODC$:aes128-cts-hmac-sha1-96:<...>
RODC$:des-cbc-md5:<...>
[*] Cleaning up...
(venv) ➜  examples git:(master)

After modifying latest Impacket (same modification is made in v0.13.0 and v0.14.0) you get the same output as in v0.12.0:

(venv) ➜  examples git:(master) ./secretsdump.py local_admin:'password@1'@192.168.100.2 -use-vss
Impacket v0.14.0.dev0+20260116.125256.a0bc463b - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: <...>
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:<...>:<...>:::
Guest:501:<...>:<...>:::
DefaultAccount:503:<...>:<...>:::
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] $MACHINE.ACC
DOMAIN\RODC$:aes256-cts-hmac-sha1-96:<...>
DOMAIN\RODC$:aes128-cts-hmac-sha1-96:<...>
DOMAIN\RODC$:des-cbc-md5:<...>
DOMAIN\RODC$:plain_password_hex:<...>
DOMAIN\RODC$:<...>:<...>:::
[*] DPAPI_SYSTEM
dpapi_machinekey:<...>
dpapi_userkey:<...>
<...>
NL$KM:<...>
[*] Searching for NTDS.dit
[*] Registry says NTDS.dit is at C:\Windows\NTDS\ntds.dit. Calling vssadmin to get a copy. This might take some time
[*] Using smbexec method for remote execution
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: <...>
[*] Reading and decrypting hashes from \\192.168.100.2\ADMIN$\Temp\IgecvbDb.tmp
DC$:1000:<...>:<...>:::
RODC$:1602:<...>:<...>:::
Guest:501:<...>:<...>:::
Administrator:500:<...>:<...>:::
krbtgt:502:<...>:<...>:::
krbtgt_XXXX:1603:<...>:<...>:::
domain.local\local_admin:3107:<...>:<...>:::
[*] Kerberos keys from \\192.168.100.2\ADMIN$\Temp\IgecvbDb.tmp
RODC$:aes256-cts-hmac-sha1-96:<...>
RODC$:aes128-cts-hmac-sha1-96:<...>
RODC$:des-cbc-md5:<...>
[*] Cleaning up...
(venv) ➜  examples git:(master) 

Local dumping makes the same issue to occur.

./secretsdump.py local_admin:'password@1'@192.168.100.2 -use-vss -use-remoteSSWMI -use-remoteSSWMI-NTDS
....
(venv) ➜  examples git:(fix-ntds-parsing-ro-objects) ✗ ./secretsdump.py -ntds ./ntds.dit -system ./SYSTEM LOCAL
Impacket v0.14.0.dev0+20260116.125256.a0bc463b - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: <...>
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: <...>
[*] Reading and decrypting hashes from ./ntds.dit
[*] Cleaning up...
(venv) ➜  examples git:(fix-ntds-parsing-ro-objects) ✗

With impacket v0.12.0 (same files of ntds.dit and SYSTEM:

(venv) ➜  examples git:(fix-ntds-parsing-ro-objects) ✗ secretsdump.py -ntds ./ntds.dit -system ./SYSTEM LOCAL
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: <...>
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: <...>
[*] Reading and decrypting hashes from ./ntds.dit
DC$:1000:<...>:<...>:::
RODC$:1602:<...>:<...>:::
Guest:501:<...>:<...>:::
Administrator:500:<...>:<...>:::
krbtgt:502:<...>:<...>:::
krbtgt_XXXX:1603:<...>:<...>:::
domain.local\local_admin:3107:<...>:<...>:::
[*] Kerberos keys from ./ntds.dit
RODC$:aes256-cts-hmac-sha1-96:<...>
RODC$:aes128-cts-hmac-sha1-96:<...>
RODC$:des-cbc-md5:<...>
[*] Cleaning up...
(venv) ➜  examples git:(fix-ntds-parsing-ro-objects) ✗

Fixed v0.14.0 and 0.13.0

(venv) ➜  examples git:(fix-ntds-parsing-ro-objects) ✗ ./secretsdump.py -ntds ./ntds.dit -system ./SYSTEM LOCAL
Impacket v0.14.0.dev0+20260116.125256.a0bc463b - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: <...>
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: <...>
[*] Reading and decrypting hashes from ./ntds.dit
DC$:1000:<...>:<...>:::
RODC$:1602:<...>:<...>:::
Guest:501:<...>:<...>:::
Administrator:500:<...>:<...>:::
krbtgt:502:<...>:<...>:::
krbtgt_XXXX:1603:<...>:<...>:::
domain.local\local_admin:3107:<...>:<...>:::
[*] Kerberos keys from ./ntds.dit
RODC$:aes256-cts-hmac-sha1-96:<...>
RODC$:aes128-cts-hmac-sha1-96:<...>
RODC$:des-cbc-md5:<...>
[*] Cleaning up...
(venv) ➜  examples git:(fix-ntds-parsing-ro-objects) ✗

@SAERXCIT
Copy link
Contributor

Hi! Yes, that's from me, from this PR #1759. I indeed did not think of RODCs when implementing this. I still think there must be a way to fit both use cases.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants