Cached Domain Credentials
When a Windows computer is joined to a domain, authentication of users is performed not against the local SAM database, but by querying the domain controller. From this description, we might be tempted to conclude that there won't be any useful credentials stored in the registry on a machine that is part of a domain; the users and their hashes don't actually exist on the local machine but rather on the domain controller.
As it turns out, however, by default Windows does store domain credentials on client machines. The reason for this is simple: if the domain controller is unavailable for some reason, users would still like to be able to log into their machines using their credentials; for this reason Windows caches domain credentials of the last (by default) 10 users to log on to the machine. The exact number of cached logons is controlled by the value "CachedLogonCount" of HKLM\Software\Microsoft\Windows NT\CurrentVersion\WinLogon.
Cached Credentials in the Registry
The cached credentials are stored in the SECURITY hive, as with LSA secrets; specifically, they can be found in the values of HKLM\Security\Cache. This key has a number of values, named NL$1 for the first cached account, NL$2 for the second, and so on. However, as we have come to expect in these matters, the data there is not immediately usable.
The first public tool capable of dumping these credentials was CacheDump, by Arnaud Pilon. He was also kind enough to provide a pretty decent explanation of how the whole process worked, in addition to the code, which makes our job at this point much easier.
As Pilon explains, the data in the NL$?? keys is formatted as follows:
[ metadata ][ CH ][ T ][ Encrypted Data ]
64 bytes 16 16 > 100 bytes
The metadata section is cleartext, and contains such information as:
- Length of the username
- Length of the domain
- Length of the full domain name
The actual username, domain name, and hash data are all stored in the encrypted data block. The CH portion of the data is an apparently random 16 byte key that is used to generate the decryption key for the encrypted data.
Decrypting the Cached Data
The decryption process is actually quite simple. First, we obtain the value of NL$KM from the LSA secrets database and decrypt it, as described in an earlier article. Then we generate an RC4 key by taking the HMAC of CH and use NL$KM as the key for the hash function. In Python this looks like:
hmac_md5 = HMAC.new(nlkm,ch)
rc4key = hmac_md5.digest()
The key is then used to decrypt the data in the NL$?? key. (As an aside, this may be the simplest of the obfuscation techniques we have looked at so far.
Once we have the data decrypted, we can find the domain cached password as the first 16 bytes of the encrypted data. The username, domain, and domain name then appear in a contiguous block starting at offset 72 in the encrypted data. We can use the lengths of these fields from the metadata block to extract the strings; note however that they are aligned to 4 bytes, so if the length is not a multiple of 4, it will be padded with nulls.
Wasn't that easy?
And that's really all that there is to it. For the record, the hash algorithm used on the plaintext password is:
MD4(MD4(password) + username)
where both password and username are little-endian UTF-16 strings.
This concludes our brief tour of the various mechanisms used to obscure credentials in Windows. As we have seen, all of the algorithms, once reverse engineered, can be implemented offline; this is precisely what CredDump does. If you have any lingering questions about how all this works, feel free to check out the code, or shoot me an e-mail. Next time we'll be diving right back into memory analysis, and I'll describe how these same techniques we've explored in the past few articles can be used on what portions of the hive remain in memory on Windows systems.
Comments
Cheers,
Brendan
Is it possible to reverse the process to encrypt data using the RC4 Key? The reason for this would be to overwrite the existing password hash with one you calculated from a known password. I realise that this would have a very limited application but sometimes you just have to log on as a particular user to get something to work, and if the domain password security is good, then using a dictonary attack or brute forcing are just not effective.
One thing that should be noted though, is that even if you do this, I'm pretty sure you will still not be able to access network resources as that domain user, as the original hash is used in the NTLM challenge/response mechanism. You might be able to use something like the "pass the hash" toolkit to re-inject the correct hash once you've logged in, though.
Cu
Michael
Thanks again. That was awesome.
Just wanted to know if the stored domain credentials will remain in the registry permanently or will be automatically cleared after some days
Thanks
Or if anyone know this please correct me.