gentilkiwi / mimikatz

A little tool to play with Windows security
http://blog.gentilkiwi.com/mimikatz
18.99k stars 3.62k forks source link

Can't found SASL Digest-MD5 hashes on the DC #399

Closed CravateRouge closed 1 year ago

CravateRouge commented 1 year ago

AD supports SASL Digest-MD5 for authentication on LDAP for example. But as stated in RFC2831 the response-value sent by the client containsmd5(user:realm:password). A blog post says the following: "_so for DIGEST compatibility AD pre-calculates 29 MD5 hashes for all kinds of scenarios and stores them in WDIGEST_CREDENTIALS_ attribute"

It means it is stored somewhere on the DC but I can't find it even using mimikatz. For now I tried without much success:

sekurlsa::logonPasswords full

sekurlsa::wdigest

Is mimikatz able to retrieve them?

piaudonn commented 1 year ago

They're not in the DC's memory but in its database. You can see them if you look into the DB eg. using lsadump::dcsync.

CravateRouge commented 1 year ago

Thank you, so it means it is also stored on the hard drive of the DC but mimikatz can only retrieve it calling the replication protocol and not by parsing the file/files where it is stored?

piaudonn commented 1 year ago

It's in the NTDS.dit of the domain controller (so yes, in the disk). RPC DRS is the only API "allowing" you to retrieve the information live (it is not meant to be read by anyone but just replicated amongst domain controllers). If you have a backup of domain controllers, tools such as DSInternals allow you to extract it from the file itself. I don't think it is stored anywhere in the SSP memory, as it doesn't not need to be. Those hashes are only useful for the DC side. The client part just generates the hash and the server will check it (oversimplified flow here... the hash isn't sent by used to encrypt messages etc... see MS-APDS). I am not sure why (maybe to make the process faster?) but the DC is accepting multiple valid hashes for a user. Let's take the user CONTOSO\test with the password Passw0rd!. The DC will pre-calculate and store all that:

md5("test:CONTOSO:Passw0rd!")
md5("TEST:contoso:Passw0rd!")
md5("TEST:CONTOSO:Passw0rd!")
md5("test:CONTOSO.COM:Passw0rd!")
md5("TEST:CONTOSO.COM:Passw0rd!")
md5("TEST:contoso.com:Passw0rd!")
md5("TEST@CONTOSO.COM::Passw0rd!")
md5("test@contoso.com::Passw0rd!")
md5("CONTOSO\test::Passw0rd!")
...

The client needs the clear-text, the server (here the DC) needs the possible derived hashes from it.

CravateRouge commented 1 year ago

Thank you very much for this detailed explanation!