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 =,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.


Nicolas said…
Great article. Creddump now only misses a function to dump the protected storage (encrypted with LSA secrets iirc?). I will dig into that if you are interested (code to dump protected storage is widely available).
Indeed, protected storage is something that should be implemented. I've been thinking about doing it, but have not yet had the time. If you think you have a decent idea of how to implement it, go for it! Feel free to e-mail me if you have any questions about the CredDump code as well.

Unknown said…
Really good stuff, makes the whole process much clearer.
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.
I'm glad you enjoyed the article! To answer your question, it should indeed be possible to change the password, hash it, and then re-encrypt the block and put it in the registry. I've actually written code to do this in the case of standard local user hashes (to demonstrate an attack that will be discussed in my DFRWS paper); however, it should be pretty easy to do the same with cached domain credentials.

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.
Mic said…
Really an interesting article. TNX for that excellent work. The Volatility-plugin was able to extract the hash from a SP2-memdump but failed with SP3. Do you know what MS may have changed?


Unknown said…
Great article! You break it down extremely well. I've noticed Vista/7 are different than XP on protected storage. Do you know of any progress on decrypting the LSA/NKLM key on Vista/7?

Thanks again. That was awesome.
Bob S said…
@moyix - regarding setting a domain cached credential ... the trick seems to be the checksum needed. Do you know how to set the final checksum on the last 16 bytes? Thx!
Unknown said…
Hi Great article,
Just wanted to know if the stored domain credentials will remain in the registry permanently or will be automatically cleared after some days
Bob S said…
@moyix - Bumping this question ... do you know the answer? Regarding setting a domain cached credential ... the trick seems to be the checksum needed. Do you know how to set the final checksum on the last 16 bytes? Thx!
Arun said…
I am accepting the point of Bob. To Set a domain cached credential the system contacting DC everytime. The DC send these values. To check the integrity of this windows add or follow some checksum in the tail of the cached data. It differs 16 byte data to 20/22 byte data. Me to failed to crack it. Right now I am working on it to reverse engineer this, once I succeed will update in this thread.

Or if anyone know this please correct me.
Arun said…
This comment has been removed by the author.
Bob S said…
@Arun - how is it going? Did you figure it out?

Popular posts from this blog

Someone’s Been Messing With My Subnormals!

Decrypting LSA Secrets

SysKey and the SAM