Contents
Abstract
Password are stored on hard drives in something called “Registry Files”. Physically they can be found on places like C:\Windows\System32\config\ in files like ‘SAM’ and ‘SYSTEM’.
They are, of course, not stored in clear text but rather in “hashed” form and for all recent Windows versions, using the NTLM proprietary (but known) hashing algorithm.
However, even the hashes are not stored “as is“, they are actually found Double Encrypted within the SAM Registry Hive, with parts of the encryption keys in the SYSTEM Registry Hive.
This article will try to explain exactly and in great detail how these hashes can be fully retrieved.
It will also discuss the changes that are made in the Windows 10 Anniversary Update (10.0.14393 or v1607). Here Microsoft decided to kick out RC4 encryption in favor of AES encryption (AES-128-CBC with an IV).
This article will only focus on NTLM hashes, not LM.
Everything below is based on personal research and reading papers, books and a lot of different scripts or programs.
The latter include Mimikatz and Powerdump of which only the first one supports AES encrypted hashes.
Since the finalization of my research, I also learned of the existence of CredDump7. CredDump7 also supports AES but not for all systems (see Corner Cases) and focuses on a different use case: it only supports extraction from SAM & SYSTEM dump files.
Note: Many of the terminology I use in this article is by my own choice and could potentially be wrong. A lot of literature differ in the terminology they use and actually use different terms to specify the same things…
Old Style Hash Retrieval
Only four things are needed from the “Target PC” to retrieve any given (local) user hash:
- The User RID or Runtime Identifier
- For the builtin Administrator this is always ‘500’ (0x1f4), whereas normal users start at ‘1001’ (0x3e9) and increment from there
- The Registry HEX Value found at HKLM\SAM\SAM\Domains\Account\Users\000001F4 in the “V” value
- Where “V” means Variable in size and thus uses an “Offset” + “Length” system
- Requires “System” privileges to be extracted and/or seen (Admin is not enough)
- The Registry HEX Value found at HKLM\SAM\SAM\Domains\Account in the “F” value
- Where “F” means Fixed in size and only requires knowledge of the fixed offsets
- Requires “System” privileges to be extracted and/or seen (admin privs are not enough)
- The Class Names of 4 Registry Keys: HKLM\System\CurrentControlSet\Control\Lsa\{JD,Skew1,GBG,Data}
- These are not values of some sort and are actually not visible in the regedit GUI
- To get these values, the keys need to be exported as Text (txt)
These things, combined with some static values as below are the only “input” things that are needed.
!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%
0123456789012345678901234567890123456789
NTPASSWORD
ShiftArray1 = [8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7]
ShiftArray2 = [0,1,2,3,0,1,2]
ShiftArray3 = [3,0,1,2,3,0,1]
Step By Step Example: old NTLM Hash Retrieval (RC4 Cipher)
–> For the entire article, the demo user is the built in Administrator with RID 500, also visible as ‘0x000001f4’ or (in code) known as ‘f4010000’. The stored password is ‘123456’
There are three different encryptions taking place: DES of the Hash (split in two), RC4 of the DES Encrypted Hash and RC4 for the SysKey. The RC4 keys are actually MD5 Hashes.
- Retrieving the Double Encrypted Hash (DES(RC4(NTLMHASH)))
- Hash length at V[0xAC]: if this is 0x14 –> RC4 Hash, if this is 0x38 –> AES Hash,
if this is some other length –> User has no NTLM password/hash - The hash itself starts at V[0xA8+0xCC] and always has a length of 16 bytes
- Note: It seems that, although all literature states that at “V[0xAC]” the hash length is specified.
It actually always seems to be 16 bytes in length. (e.g. here the next 4 bytes would be ‘03000100’) - Double Encrypted NTLM Hash example: d4442d6644edae736d4f3dfb8ff04f0f (16 bytes)
- Hash length at V[0xAC]: if this is 0x14 –> RC4 Hash, if this is 0x38 –> AES Hash,
- The RC4 Key to decrypt the Double Encrypted Hash is derived from the “SysKey”, which is in itself also RC4 encrypted. This step will extract the Encrypted SysKey
- F[0x80] = 97700b19ab0fa48f3f5fed8ed046c680 (16 bytes)
- The Encrypted SysKey needs to be decrypted, to built the RC4 decryption key, we need the Bootkey.
This Bootkey is calculated by reordering the 4 Class Names from JD, Skew1, GBG and Data- JD + Skew1 + GBG + Data = 5d5991a3486c05965af833413f2cceb9
- Reorder using ShiftArray1 [8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7] =
- Bootkey = 5a6c489141f82ca35d05593fce33b996 (16 bytes)
- Next up is building the SysKey RC4 Encryption Key. Four values are needed:
- F[0x70] = 70a7884da3fa7f816cbd324e7ac3996f (16 bytes)
- String1 ‘!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%‘
- Bootkey from (3.): 5a6c489141f82ca35d05593fce33b996 (16 bytes)
- String2 ‘0123456789012345678901234567890123456789‘
- These 4 values are put together and hashed using MD5(F[0x70] + String1 + Bootkey + String2)
- Resulting MD5 and SysKey RC4 Encryption Key = d6ec4ecfb9850063cecf65d1f77efe96 (16 bytes)
- RC4 decrypting the Encrypted SysKey from (2.) with the Key from (4.)
- RC4Decrypt 97700b19ab0fa48f3f5fed8ed046c680
with Key d6ec4ecfb9850063cecf65d1f77efe96 - Decrypted SysKey = afe7e35df020b79484a1c49440f90f18 (16 bytes)
- RC4Decrypt 97700b19ab0fa48f3f5fed8ed046c680
- To Decrypt the Double Encrypted NTLM hash, the RC4 Key has to be calculated. Three values are needed:
- SysKey from (5.): afe7e35df020b79484a1c49440f90f18 (16 bytes)
- RID of the user: f4010000
- String ‘NTPASSWORD‘
- These 3 values are put together and hashed using MD5(SysKey + RID + String)
- Resulting MD5 and RC4 Key for the Double Encrypted NTLM Hash = 76f1327b198c0731ae2611dab42716ea (16 bytes)
- RC4 decrypting the Double Encrypted NTLM hash from (1.) with the Key from (6.)
- RC4Decrypt d4442d6644edae736d4f3dfb8ff04f0f with Key 76f1327b198c0731ae2611dab42716ea
- Encrypted NTLM Hash = a291d14b768a6ac455a0ab9d376d8551 (16 bytes)
- The Encrypted NTLM is cut in two and each part is DES encrypted, the DES keys are derived from the RID
- RID = f4010000 (4 bytes)
- DES SOURCE 1 reorder using ShiftArray2 [0,1,2,3,0,1,2] = f4010000f40100 (7 bytes)
- DES SOURCE 2 reorder using ShiftArray3 [3,0,1,2,3,0,1] = 00f4010000f401 (7 bytes)
- 7 bytes needs to become 8 bytes using an algorithm plus Odd Parity (Always odd number of ‘ones’):
- DESKEY1 = f40140010ea10401 (8 bytes)
- DESKEY2 = 017a01200107d002 (8 bytes)
- Note that the only source for these keys is the RID, therefor every Administrator account has the same DESKEYs
- Finally cut the Encrypted NTLM hash from (7.) in two and decrypt each part with the DES keys from (8.):
- NTLM Hash part 1 = a291d14b768a6ac4 with DESKEY f40140010ea10401 = 32ed87bdb5fdc5e9 (8 bytes)
- NTLM Hash part 2 = 55a0ab9d376d8551 with DESKEY 017a01200107d002 = cba88547376818d4 (8 bytes)
- Putting these two halves together gives us 32ed87bdb5fdc5e9cba88547376818d4 (16 bytes) which is the hash for password ‘123456’
New Style Hash Retrieval
Since July 2016 (Windows 10 v1607), hashes are no longer encrypted with RC4 but are using an AES Cipher. Also all usage of “MD5” is gone.
Watch out: there are subtle differences: In case Windows is installed as a pre v1607 version, all passwords are stored in RC4 format. After an update to v1607, they remain stored in RC4 format until one updates his password. However: even after updating and changing the passwords, the SysKey encryption remains in RC4 format.
This step-by-step only applies to Windows systems that where installed as a post v1607 version. The NTLM hashing algorithm remains the same, so the resulting hash will still be 32ed87bdb5fdc5e9cba88547376818d4 (or ‘123456’ in plain text).
In this case, static strings such as ‘NTPASSWORD’ or ‘!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%’ or no longer used. The entire process is slightly simplified but remains roughly the same. This means only these static “values” need to be known:
ShiftArray1 = [8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7]
ShiftArray2 = [0,1,2,3,0,1,2]
ShiftArray3 = [3,0,1,2,3,0,1]
Step By Step Example: new NTLM Hash Retrieval (AES Cipher)
There are three different encryptions taking place: DES of the Hash (split in two), AES of the DES Encrypted Hash and AES for the SysKey. The Encryption scheme used is the AES-128-CBC cipher. This means 128bit (or 16byte) keys are required together with a 16 byte Initial Vector (or IV).
- Retrieving the Double Encrypted Hash (DES(AES(NTLMHASH)))
- Hash length at V[0xAC]: if this is 0x14 –> RC4 Hash, if this is 0x38 –> AES Hash,
if this is some other length –> User has no NTLM password/hash - The hash itself starts at V[0xA8+0xCC] and always has a length of 16 bytes
- Note: It seems that, although all literature states that at “V[0xAC]” the hash length is specified.
The hash actually always seems to be 16 bytes in length. - Double Encrypted NTLM Hash example: 3f89be20888e4878a098921d8396b535 (16 bytes)
- The AES Initial Vector (AES IV) starts at V[0xB4+0xCC] and is always 16 bytes
- AES IV example: 3fd3027790ff2c0a5b8f162239d41476 (16 bytes)
- Hash length at V[0xAC]: if this is 0x14 –> RC4 Hash, if this is 0x38 –> AES Hash,
- The AES Key to decrypt the Double Encrypted Hash is derived from the “SysKey”, which is in itself also AES encrypted. So again Data and IV is extracted.
This step will extract the Encrypted SysKey and IV- How do we know the SysKey is AES or RC4 encrypted? Just look at the very first byte of the “F” value: 0x02 means RC4 encrypted, 0x03 means AES encrypted
- F[0x88] = 7b06427ecf48cec9b61e67caed0292c9 (16 bytes)
- F[0x78] = ea322e0e26f58e4b5ab8587e75c861db (16 bytes)
- We have Encrypted SysKey (data) and the IV, but need the Key to decrypt the SysKey, this is the Bootkey.
This Bootkey is calculated by reordering the 4 Class Names from JD, Skew1, GBG and Data- JD + Skew1 + GBG + Data = 3f089869880dc18915d4e5adf1f6a792
- Reorder using ShiftArray1 [8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7] =
- Bootkey = 150d8898add4f6693fc108f1a7e59289 (16 bytes)
- (This step is no longer needed with an AES encrypted SysKey.
To decrypt the SysKey, we no longer have to construct the Encryption Key, it just IS the Bootkey and no longer a derivation thereof) - AES decrypting the Encrypted SysKey and IV from (2.) with the Key from (3.)
- AESDecrypt 7b06427ecf48cec9b61e67caed0292c9 with Key 150d8898add4f6693fc108f1a7e59289 and IV ea322e0e26f58e4b5ab8587e75c861db
- Full SysKey = 903d474b0fa91eb3003768eefcc2143d (16 bytes)
- Decrypted SysKey = 903d474b0fa91eb3003768eefcc2143d (16 bytes)
- (Again: this step is no longer needed with an AES encrypted Hash. To decrypt the Double Encrypted hash, the key just IS the SysKey and no longer a derivation thereof)
- AES decrypting the Double Encrypted NTLM hash and IV from (1.) with the Key from (5.)
- AESDecrypt 3f89be20888e4878a098921d8396b535 with Key 903d474b0fa91eb3003768eefcc2143d and IV 3fd3027790ff2c0a5b8f162239d41476
- Encrypted NTLM Hash = a291d14b768a6ac455a0ab9d376d8551 (16 bytes)
- The Encrypted NTLM is cut in two and each part is DES encrypted, the DES keys are derived from the RID
- RID = f4010000 (4 bytes)
- DES SOURCE 1 reorder using ShiftArray2 [0,1,2,3,0,1,2] = f4010000f40100 (7 bytes)
- DES SOURCE 2 reorder using ShiftArray3 [3,0,1,2,3,0,1] = 00f4010000f401 (7 bytes)
- 7 bytes needs to become 8 bytes using an algorithm plus Odd Parity (Always odd number of ‘ones’):
- DESKEY1 = f40140010ea10401 (8 bytes)
- DESKEY2 = 017a01200107d002 (8 bytes)
- Note that the only source for these keys is the RID, therefor every Administrator account has the same DESKEYs
- Finally cut the Encrypted NTLM hash from (7.) in two and decrypt each part with the DES keys from (8.):
- NTLM Hash part 1 = a291d14b768a6ac4 with DESKEY f40140010ea10401 = 32ed87bdb5fdc5e9 (8 bytes)
- NTLM Hash part 2 = 55a0ab9d376d8551 with DESKEY 017a01200107d002 = cba88547376818d4 (8 bytes)
- Putting these two halves together gives us 32ed87bdb5fdc5e9cba88547376818d4 (16 bytes) which is the hash for password ‘123456’
Corner Cases
As specified earlier, there are also:
- Windows systems out there that where installed pre Windows v1607: RC4 encryption only.
- Windows systems that where installed as pre Windows v1607 but updated later without password updates (net user Administrator 123456): RC4 encryption only
- Windows systems that where installed as pre Windows v1607 and then updated and have updated one or more user passwords (net user Administrator 123456): Mixed RC4 (SysKey) and AES (Hash) encryption
- Windows systems that where installed as Windows v1607 or newer: AES encryption only.
My scripts
I have written two scripts Just As A Demonstration or study tool.
I am in no way a real programmer or developer and have created this script just to educate myself and prove my findings. I am fully aware that these scripts can be made a lot more portable, shorter and generally better…
I always try to make them as self contained as possible, requiring little extra libraries. They only library required is pycrypto (which is installed by default on e.g. Kali Linux).
The first script “DumpSomeHashes.py” requires manual actions to retrieve the four things from the target PC (the Registry Data). It is described in the script how to get this data. The script therefor does not have to be run as Admin and will work on any OS (given the used Python libs are installed).
The second script “DumpSomeHashesAuto.py” is an attempt to automate the whole process and will try to retrieve one single NTLM Hash (only needs the RID) by using PowerShell (and Windows API’s which is cheating) to get the three required pieces of data.
–> Of course it is trivial to just read out all users and their RID (“net user” combined with “wmic useraccount where name=’Administrator’ get sid“), but this is not the purpose of the script nor this article
“DumpSomeHashes.py” on my Github
“DumpSomeHashesAuto.py” on my Github
Although the scripts have been tested in a “lab” environment, any feedback is more than welcome 🙂
Conclusion
Since al required data to decrypt the hashes is either static, known or just some elaborate calculation. This is a great example of “Security By Obscurity”.
Microsoft has improved and simplified the encryption cycle by removing not only RC4 from the equation but also MD5 together with all unnecessary (and old) static strings.
The question still remains why the “length” of the hash is actually not the “length”, not all 56 or even 20 bytes are used or even useful. And if Microsoft really wanted to improve the security of their users, it should improve on the used hashing algorithm rather than just changing the used encryption ciphers …
References
- https://www.passcape.com/index.php?section=blog&cmd=details&id=35 – Details on what changed in Win10 AU
- http://moyix.blogspot.be/2008/02/syskey-and-sam.html – Details on the used strings and algorithms
- http://www.beginningtoseethelight.org/ntsecurity/index.htm – Very interesting article on Registry Layout (for Windows XP)
- https://diablohorn.com/2013/10/24/remote-hash-dumping-no-processes-or-tool-upload-needed/ – Blog about Remote Hash Dumping with some more resources and references listed
2 reacties