NTLM History extraction from ntds.dit fails when "Win2016 TP4 decryption" is used
crackmeifyoucan opened this issue · comments
I believe I have found an issue with using secretsdump.py with a NTDS.dit that is from a Windows 2016 Server. When we would dump the histories hashes, they would not crack. But the current hashes would crack.
I believe I found a problem in impacket/impacket/examples/secretsdump.py around line 2142
The code checks to see if the header starts with 1300, if it finds it, it should run a CRYPTED_HASHW16 against the value. But it does not.
By simply adding a single line of:
encryptedNTHistory = self.CRYPTED_HASHW16(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']]))
you can fix it (at line 2142)
if record[self.NAME_TO_INTERNAL['ntPwdHistory']] is not None:
encryptedNTHistory = self.CRYPTED_HISTORY(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']]))
if encryptedNTHistory['Header'][:4] == b'\x13\x00\x00\x00':
# Win2016 TP4 decryption is different
encryptedNTHistory = self.CRYPTED_HASHW16(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']]))
pekIndex = hexlify(encryptedNTHistory['Header'])
tmpNTHistory = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])],
encryptedNTHistory['EncryptedHash'],
encryptedNTHistory['KeyMaterial'])
else:
tmpNTHistory = self.__removeRC4Layer(encryptedNTHistory)
Minga (KoreLogic)
@crackmeifyoucan
Side note:
I do not know if the function __decryptSupplementalInfo needs a similar fix. It appears to be missing a CRYPTED_HASHW16 call as well. But I haven't tested that theory.
Just noticed, my patch needs work because it only works with one history entry, and then fails on the rest.
[-] Error while processing row for user [santized]
[-] b2a_hex() argument 1 must be string or buffer, not None
Any progress on this issue? I can reproduce this issue where password hash history content is incorrectly extracted from NTDS.dit/ntdsutil dumps.
I think I found a fix for this issue by building on crackmeifyoucan's change. I dumped the password history from an NTDS.dit where I knew four of an account's previous passwords and all cracked successfully. I'm not sure if the fix is universal as I only had one NTDS database to test with. If it seems to work for others, I can submit a PR.
The changes involve adding a new data structure class, then using that to store the encryptedNTHistory.
After the class CRYPTED_HISTORY(Structure) definition that is around line 1799, add class CRYPTED_HISTORYW16(Structure):
class CRYPTED_HISTORY(Structure):
structure = (
('Header','8s=b""'),
('KeyMaterial','16s=b""'),
('EncryptedHash',':'),
)
class CRYPTED_HISTORYW16(Structure):
structure = (
('Header','8s=b""'),
('KeyMaterial','16s=b""'),
('Unknown','<L=0'),
('EncryptedHash',':'),
)
class CRYPTED_BLOB(Structure):
structure = (
('Header','8s=b""'),
('KeyMaterial','16s=b""'),
('EncryptedHash',':'),
)
Finally, around what is originally line 2142, add the line encryptedNTHistory = self.CRYPTED_HISTORYW16(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']]))
if encryptedNTHistory['Header'][:4] == b'\x13\x00\x00\x00':
# Win2016 TP4 decryption is different
encryptedNTHistory = self.CRYPTED_HISTORYW16(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']]))
pekIndex = hexlify(encryptedNTHistory['Header'])
Hi folks! I created this PR-> #783 that addresses the issue using the solution suggested by @crackmeifyoucan and @Hyperjag. Please check it and let me know if everything it's OK. Thanks for the collaboration guys!!
Closing as fixed.