diff --git a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c index e004581..929c677 100644 --- a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c +++ b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.c @@ -37,17 +37,17 @@ NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]) { PCWSTR inFilePolicy, inFileCred; PVOID filePolicy, fileCred, out; - DWORD szFilePolicy, szFileCred, szOut, len, i; + DWORD szFilePolicy, szFileCred, szOut, len, i, mode = CRYPT_MODE_CBC; BYTE aes128[AES_128_KEY_SIZE], aes256[AES_256_KEY_SIZE]; PKULL_M_CRED_VAULT_POLICY vaultPolicy; PKULL_M_CRED_VAULT_CREDENTIAL vaultCredential; PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute; PKULL_M_CRED_VAULT_CLEAR clear; PVOID buffer; - + BOOL isAttr; HCRYPTPROV hProv; HCRYPTKEY hKey; - + if(kull_m_string_args_byName(argc, argv, L"cred", &inFileCred, NULL)) { if(kull_m_file_readData(inFileCred, (PBYTE *) &fileCred, &szFileCred)) @@ -69,7 +69,7 @@ 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++) @@ -77,38 +77,21 @@ NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]) if(attribute = vaultCredential->attributes[i]) { kprintf(L" > Attribute %u : ", attribute->id); - if(attribute->id && (attribute->id < 100)) + if(attribute->data && (len = attribute->szData)) { - if(len = (attribute->attributeElement.simpleAttribute.size >= 1) ? (attribute->attributeElement.simpleAttribute.size - 1) : 0) + if(buffer = LocalAlloc(LPTR, len)) { - if(kull_m_crypto_hkey(hProv, CALG_AES_128, aes128, AES_128_KEY_SIZE, 0, &hKey, NULL)) + RtlCopyMemory(buffer, attribute->data, len); + if(kuhl_m_dpapi_vault_key_type(attribute, hProv, aes128, aes256, &hKey, &isAttr)) { - if(buffer = LocalAlloc(LPTR, len)) + if(CryptDecrypt(hKey, 0, TRUE, 0, (PBYTE) buffer, &len)) { - RtlCopyMemory(buffer, attribute->attributeElement.simpleAttribute.attributeData->data, len); - - if(CryptDecrypt(hKey, 0, TRUE, 0, (PBYTE) buffer, &len)) + if(isAttr) { + kull_m_string_wprintf_hex(buffer, len, 0); } - else PRINT_ERROR_AUTO(L"CryptDecrypt"); - CryptDestroyKey(hKey); - LocalFree(buffer); - } - } - } - else kprintf(L"n/a"); - } - else - { - if(len = (attribute->attributeElement.complexAttribute.size >= 5) ? (attribute->attributeElement.complexAttribute.size - 5) : 0) - { - if(kull_m_crypto_hkey(hProv, CALG_AES_256, aes256, AES_256_KEY_SIZE, 0, &hKey, NULL)) - { - if(buffer = LocalAlloc(LPTR, len)) - { - RtlCopyMemory(buffer, attribute->attributeElement.complexAttribute.attributeData->data, len); - if(CryptDecrypt(hKey, 0, TRUE, 0, (PBYTE) buffer, &len)) + else { kprintf(L"\n"); if(!attribute->id || (attribute->id == 100)) @@ -122,13 +105,11 @@ NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]) else kull_m_string_wprintf_hex(buffer, len, 1 | (16 << 16)); kprintf(L"\n"); } - else PRINT_ERROR_AUTO(L"CryptDecrypt"); - CryptDestroyKey(hKey); - LocalFree(buffer); } + else PRINT_ERROR_AUTO(L"CryptDecrypt"); } + LocalFree(buffer); } - else kprintf(L"n/a"); } kprintf(L"\n"); } @@ -153,4 +134,34 @@ NTSTATUS kuhl_m_dpapi_vault(int argc, wchar_t * argv[]) else PRINT_ERROR(L"Input Cred file needed (/cred:file)\n"); return STATUS_SUCCESS; +} + +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; + DWORD mode = CRYPT_MODE_CBC, calgId, keyLen; + LPCVOID key; + + *isAttr = attribute->id && (attribute->id < 100); + if(*isAttr) + { + calgId = CALG_AES_128; + key = aes128; + keyLen = AES_128_KEY_SIZE; + + } + else + { + calgId = CALG_AES_256; + key = aes256; + keyLen = AES_256_KEY_SIZE; + } + + if(status = kull_m_crypto_hkey(hProv, calgId, key, keyLen, 0, hKey, NULL)) + { + CryptSetKeyParam(*hKey, KP_MODE, (LPCBYTE) &mode, 0); + if(attribute->szIV && attribute->IV) + CryptSetKeyParam(*hKey, KP_IV, attribute->IV, 0); + } + return status; } \ No newline at end of file diff --git a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h index 5cda99a..aef30bd 100644 --- a/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h +++ b/mimikatz/modules/dpapi/packages/kuhl_m_dpapi_creds.h @@ -16,4 +16,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[]); + +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/modules/kull_m_cred.c b/modules/kull_m_cred.c index af7504a..7655828 100644 --- a/modules/kull_m_cred.c +++ b/modules/kull_m_cred.c @@ -317,6 +317,7 @@ PKULL_M_CRED_VAULT_CREDENTIAL kull_m_cred_vault_credential_create(PVOID data/*, { PKULL_M_CRED_VAULT_CREDENTIAL credential = NULL; PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute; + PBYTE ptr; DWORD i; if(credential = (PKULL_M_CRED_VAULT_CREDENTIAL) LocalAlloc(LPTR, sizeof(KULL_M_CRED_VAULT_CREDENTIAL))) { @@ -336,29 +337,20 @@ PKULL_M_CRED_VAULT_CREDENTIAL kull_m_cred_vault_credential_create(PVOID data/*, if(credential->attributes[i] = (PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE) LocalAlloc(LPTR, sizeof(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE))) { attribute = (PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE) ((PBYTE) data + credential->attributesMap[i].offset); - RtlCopyMemory(credential->attributes[i], attribute, FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, attributeElement)); - if(attribute->id < 100) - { - RtlCopyMemory(&credential->attributes[i]->attributeElement.simpleAttribute, &attribute->attributeElement.simpleAttribute, FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE, attributeData)); - credential->attributes[i]->attributeElement.simpleAttribute.attributeData = (PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA) &attribute->attributeElement.simpleAttribute.attributeData; - kull_m_string_ptr_replace(&credential->attributes[i]->attributeElement.simpleAttribute.attributeData, credential->attributes[i]->attributeElement.simpleAttribute.size); - } - else - { - RtlCopyMemory(&credential->attributes[i]->attributeElement.complexAttribute, &attribute->attributeElement.complexAttribute, FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX, attributeData)); - credential->attributes[i]->attributeElement.complexAttribute.attributeData = (PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA) &attribute->attributeElement.complexAttribute.attributeData; - kull_m_string_ptr_replace(&credential->attributes[i]->attributeElement.complexAttribute.attributeData, credential->attributes[i]->attributeElement.complexAttribute.size); - } + + RtlCopyMemory(credential->attributes[i], attribute, FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, szData)); + ptr = (PBYTE) attribute; + if(attribute->id >= 100) + ptr += sizeof(DWORD); // boo! + ptr += FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, szData); + kull_m_cred_vault_credential_create_attribute_from_data(ptr, credential->attributes[i]); } } - if(attribute && credential->unk0 < 4) { if(credential->attributes[i] = (PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE) LocalAlloc(LPTR, sizeof(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE))) { - RtlCopyMemory(&credential->attributes[i]->attributeElement.complexAttribute.size, (PBYTE) attribute + FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, attributeElement) + FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE, attributeData) + attribute->attributeElement.simpleAttribute.size + sizeof(USHORT), FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX, attributeData) - FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX, size)); - credential->attributes[i]->attributeElement.complexAttribute.attributeData = (PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA) ((PBYTE) attribute + FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, attributeElement) + FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE, attributeData) + attribute->attributeElement.simpleAttribute.size + sizeof(USHORT) + (FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX, attributeData) - FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX, size))); - kull_m_string_ptr_replace(&credential->attributes[i]->attributeElement.complexAttribute.attributeData, credential->attributes[i]->attributeElement.complexAttribute.size); + kull_m_cred_vault_credential_create_attribute_from_data((PBYTE) attribute + FIELD_OFFSET(KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, data) + attribute->szData + sizeof(USHORT), credential->attributes[i]); credential->__cbElements++; } } @@ -367,6 +359,32 @@ PKULL_M_CRED_VAULT_CREDENTIAL kull_m_cred_vault_credential_create(PVOID data/*, return credential; } +void kull_m_cred_vault_credential_create_attribute_from_data(PBYTE ptr, PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute) +{ + BOOLEAN isIV; + if(attribute->szData = *(PDWORD) ptr) + { + attribute->szData--; + ptr += sizeof(DWORD); + isIV = *(PBOOLEAN) ptr; + ptr += sizeof(BOOLEAN); + if(isIV) + { + attribute->szData -= sizeof(DWORD);; + if(attribute->szIV = *(PDWORD) ptr) + { + attribute->szData -= attribute->szIV; + ptr += sizeof(DWORD); + attribute->IV = ptr; + ptr += attribute->szIV; + kull_m_string_ptr_replace(&attribute->IV, attribute->szIV); + } + } + attribute->data = ptr; + kull_m_string_ptr_replace(&attribute->data, attribute->szData); + } +} + void kull_m_cred_vault_credential_delete(PKULL_M_CRED_VAULT_CREDENTIAL credential) { DWORD i; @@ -383,16 +401,10 @@ void kull_m_cred_vault_credential_delete(PKULL_M_CRED_VAULT_CREDENTIAL credentia { if(credential->attributes[i]) { - if(credential->attributes[i]->id && (credential->attributes[i]->id < 100)) - { - if(credential->attributes[i]->attributeElement.simpleAttribute.attributeData) - LocalFree(credential->attributes[i]->attributeElement.simpleAttribute.attributeData); - } - else - { - if(credential->attributes[i]->attributeElement.complexAttribute.attributeData) - LocalFree(credential->attributes[i]->attributeElement.complexAttribute.attributeData); - } + if(credential->attributes[i]->data) + LocalFree(credential->attributes[i]->data); + if(credential->attributes[i]->IV) + LocalFree(credential->attributes[i]->IV); LocalFree(credential->attributes[i]); } } @@ -430,23 +442,17 @@ void kull_m_cred_vault_credential_attribute_descr(DWORD level, PKULL_M_CRED_VAUL { kprintf(L"%*s" L" id : %08x - %u\n", level << 1, L"", attribute->id, attribute->id); kprintf(L"%*s" L" unk0/1/2: %08x/%08x/%08x\n", level << 1, L"", attribute->unk0, attribute->unk1, attribute->unk2); - if(attribute->id && (attribute->id < 100)) + if(attribute->szIV && attribute->IV) { - if((attribute->attributeElement.simpleAttribute.size >= 1) && attribute->attributeElement.simpleAttribute.attributeData) - { - kprintf(L"%*s" L" Simple data (%02x): ", level << 1, L"", attribute->attributeElement.simpleAttribute.attributeData->unkByte); - kull_m_string_wprintf_hex(attribute->attributeElement.simpleAttribute.attributeData->data, attribute->attributeElement.simpleAttribute.size - 1, 0); - kprintf(L"\n"); - } + kprintf(L"%*s" L" IV : ", level << 1, L""); + kull_m_string_wprintf_hex(attribute->IV, attribute->szIV, 0); + kprintf(L"\n"); } - else + if(attribute->szData && attribute->data) { - if((attribute->attributeElement.complexAttribute.size >= (4 + 1)) && attribute->attributeElement.complexAttribute.attributeData) - { - kprintf(L"%*s" L" Complex data : (%08x - %08x - %02x) - ", level << 1, L"", attribute->attributeElement.complexAttribute.unk0, attribute->attributeElement.complexAttribute.unk1, attribute->attributeElement.complexAttribute.attributeData->unkByte); - kull_m_string_wprintf_hex(attribute->attributeElement.complexAttribute.attributeData->data, attribute->attributeElement.complexAttribute.size - (4 + 1), 0); - kprintf(L"\n"); - } + kprintf(L"%*s" L" Data : ", level << 1, L""); + kull_m_string_wprintf_hex(attribute->data, attribute->szData, 0); + kprintf(L"\n"); } } } @@ -497,10 +503,9 @@ void kull_m_cred_vault_clear_descr(DWORD level, PKULL_M_CRED_VAULT_CLEAR clear) kprintf(L"%*s" L"**VAULT CREDENTIAL CLEAR ATTRIBUTES**\n", level << 1, L""); if(clear) { - kprintf(L"%*s" L" unkArray : ", level << 1, L""); kull_m_string_wprintf_hex(clear->unkArray, sizeof(clear->unkArray), 0); kprintf(L"\n"); - kprintf(L"%*s" L" version : %08x - %u\n", level << 1, L"", clear->version, clear->version); - kprintf(L"%*s" L" count : %08x - %u\n", level << 1, L"", clear->count, clear->count); - kprintf(L"%*s" L" unk : %08x - %u\n", level << 1, L"", clear->unk, clear->unk); + kprintf(L"%*s" L" version: %08x - %u\n", level << 1, L"", clear->version, clear->version); + kprintf(L"%*s" L" count : %08x - %u\n", level << 1, L"", clear->count, clear->count); + kprintf(L"%*s" L" unk : %08x - %u\n", level << 1, L"", clear->unk, clear->unk); if(clear->entries) { diff --git a/modules/kull_m_cred.h b/modules/kull_m_cred.h index d8925f5..28ab873 100644 --- a/modules/kull_m_cred.h +++ b/modules/kull_m_cred.h @@ -9,32 +9,16 @@ #include "kull_m_string.h" #pragma pack(push, 1) -typedef struct _KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA { - BYTE unkByte; - BYTE data[ANYSIZE_ARRAY]; -} KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA, *PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA; - -typedef struct _KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE { - DWORD size; // inc bullshit - PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA attributeData; -} KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE, *PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE; - -typedef struct _KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX { - DWORD unk0; - DWORD size; // inc bullshit - DWORD unk1; // maybe flags; - PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_DATA attributeData; -} KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX, *PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX; - typedef struct _KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE { DWORD id; DWORD unk0; // maybe flags DWORD unk1; // maybe type DWORD unk2; // 0a 00 00 00 - union { - KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_SIMPLE simpleAttribute; // if id < 100 - KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE_COMPLEX complexAttribute; - } attributeElement; + //DWORD unkComplex; // only in complex (and 0, avoid it ?) + DWORD szData; // when parsing, inc bullshit... clean in structure + PBYTE data; + DWORD szIV; + PBYTE IV; } KULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE, *PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE; #pragma pack(pop) @@ -137,7 +121,6 @@ typedef struct _KULL_M_CRED_VAULT_CLEAR_ENTRY { } KULL_M_CRED_VAULT_CLEAR_ENTRY, *PKULL_M_CRED_VAULT_CLEAR_ENTRY; typedef struct _KULL_M_CRED_VAULT_CLEAR { - BYTE unkArray[16]; DWORD version; DWORD count; DWORD unk; @@ -166,6 +149,7 @@ void kull_m_cred_vault_policy_key_delete(PKULL_M_CRED_VAULT_POLICY_KEY key); void kull_m_cred_vault_policy_key_descr(DWORD level, PKULL_M_CRED_VAULT_POLICY_KEY key); PKULL_M_CRED_VAULT_CREDENTIAL kull_m_cred_vault_credential_create(PVOID data/*, DWORD size*/); +void kull_m_cred_vault_credential_create_attribute_from_data(PBYTE ptr, PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute); void kull_m_cred_vault_credential_delete(PKULL_M_CRED_VAULT_CREDENTIAL credential); void kull_m_cred_vault_credential_descr(DWORD level, PKULL_M_CRED_VAULT_CREDENTIAL credential); void kull_m_cred_vault_credential_attribute_descr(DWORD level, PKULL_M_CRED_VAULT_CREDENTIAL_ATTRIBUTE attribute);