mirror of
https://github.com/rapid7/metasploit-payloads
synced 2024-12-27 08:33:43 +01:00
Land #51, stageless windows meterpreter python initialization support
This commit is contained in:
commit
6ebd997d83
4
c/meterpreter/source/common/config.h
Normal file → Executable file
4
c/meterpreter/source/common/config.h
Normal file → Executable file
@ -69,6 +69,10 @@ typedef struct _MetsrvConfig
|
||||
MetsrvSession session;
|
||||
MetsrvTransportCommon transports[1]; ///! Placeholder for 0 or more transports
|
||||
// Extensions will appear after this
|
||||
// After extensions, we get a list of extension initialisers
|
||||
// <name of extension>\x00<datasize><data>
|
||||
// <name of extension>\x00<datasize><data>
|
||||
// \x00
|
||||
} MetsrvConfig;
|
||||
|
||||
#endif
|
||||
|
55
c/meterpreter/source/extensions/python/python_commands.c
Normal file → Executable file
55
c/meterpreter/source/extensions/python/python_commands.c
Normal file → Executable file
@ -9,11 +9,6 @@
|
||||
#include "python_meterpreter_binding.h"
|
||||
#include "Resource Files/python_core.rh"
|
||||
|
||||
///! @brief List of valid python code types for loading
|
||||
#define PY_CODE_TYPE_STRING 0
|
||||
#define PY_CODE_TYPE_PY 1
|
||||
#define PY_CODE_TYPE_PYC 2
|
||||
|
||||
///! @brief Struct that contains pointer to init function and name.
|
||||
typedef struct _InitFunc
|
||||
{
|
||||
@ -413,25 +408,13 @@ DWORD request_python_reset(Remote* remote, Packet* packet)
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Execute a block of python given in a string and return the result/output.
|
||||
* @param remote Pointer to the \c Remote making the request.
|
||||
* @param packet Pointer to the request \c Packet.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
DWORD request_python_execute(Remote* remote, Packet* packet)
|
||||
VOID python_execute(CHAR* modName, LPBYTE pythonCode, DWORD codeLength, UINT codeType, CHAR* resultVar, Packet* responsePacket)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet* response = packet_create_response(packet);
|
||||
LPBYTE pythonCode = packet_get_tlv_value_raw(packet, TLV_TYPE_EXTENSION_PYTHON_CODE);
|
||||
|
||||
PyObject* mainModule = PyImport_AddModule("__main__");
|
||||
PyObject* mainDict = PyModule_GetDict(mainModule);
|
||||
|
||||
if (pythonCode != NULL)
|
||||
{
|
||||
UINT codeType = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE);
|
||||
|
||||
if (codeType == PY_CODE_TYPE_STRING)
|
||||
{
|
||||
dprintf("[PYTHON] attempting to run string: %s", pythonCode);
|
||||
@ -440,7 +423,6 @@ DWORD request_python_execute(Remote* remote, Packet* packet)
|
||||
}
|
||||
else
|
||||
{
|
||||
CHAR* modName = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME);
|
||||
dprintf("[PYTHON] module name: %s", modName);
|
||||
if (modName)
|
||||
{
|
||||
@ -459,8 +441,7 @@ DWORD request_python_execute(Remote* remote, Packet* packet)
|
||||
{
|
||||
dprintf("[PYTHON] importing .pyc file");
|
||||
// must be a pyc file
|
||||
UINT pythonCodeLength = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_LEN);
|
||||
PyObject* pyModBody = PyString_FromStringAndSize(pythonCode, pythonCodeLength);
|
||||
PyObject* pyModBody = PyString_FromStringAndSize(pythonCode, codeLength);
|
||||
dprintf("[PYTHON] myModBody %p: %s", pyModBody, pyModBody->ob_type->tp_name);
|
||||
PyModule_AddObject(mainModule, "met_mod_body", pyModBody);
|
||||
}
|
||||
@ -469,8 +450,7 @@ DWORD request_python_execute(Remote* remote, Packet* packet)
|
||||
PyRun_SimpleString("met_import_code()");
|
||||
}
|
||||
|
||||
CHAR* resultVar = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_RESULT_VAR);
|
||||
if (resultVar)
|
||||
if (resultVar && responsePacket)
|
||||
{
|
||||
PyObject* result = PyDict_GetItemString(mainDict, resultVar);
|
||||
if (result != NULL)
|
||||
@ -478,16 +458,41 @@ DWORD request_python_execute(Remote* remote, Packet* packet)
|
||||
if (PyString_Check(result))
|
||||
{
|
||||
// result is already a string
|
||||
packet_add_tlv_string(response, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(result));
|
||||
packet_add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
PyObject* resultStr = PyObject_Str(result);
|
||||
packet_add_tlv_string(response, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(resultStr));
|
||||
packet_add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(resultStr));
|
||||
Py_DECREF(resultStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Execute a block of python given in a string and return the result/output.
|
||||
* @param remote Pointer to the \c Remote making the request.
|
||||
* @param packet Pointer to the request \c Packet.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
DWORD request_python_execute(Remote* remote, Packet* packet)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet* response = packet_create_response(packet);
|
||||
LPBYTE pythonCode = packet_get_tlv_value_raw(packet, TLV_TYPE_EXTENSION_PYTHON_CODE);
|
||||
|
||||
PyObject* mainModule = PyImport_AddModule("__main__");
|
||||
PyObject* mainDict = PyModule_GetDict(mainModule);
|
||||
|
||||
if (pythonCode != NULL)
|
||||
{
|
||||
UINT codeType = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE);
|
||||
CHAR* modName = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME);
|
||||
UINT pythonCodeLength = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_LEN);
|
||||
CHAR* resultVar = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_RESULT_VAR);
|
||||
python_execute(modName, pythonCode, pythonCodeLength, codeType, resultVar, response);
|
||||
|
||||
dump_to_packet(stderrBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDERR);
|
||||
clear_std_handler(stderrBuffer);
|
||||
|
6
c/meterpreter/source/extensions/python/python_commands.h
Normal file → Executable file
6
c/meterpreter/source/extensions/python/python_commands.h
Normal file → Executable file
@ -7,8 +7,14 @@
|
||||
|
||||
#include "../../common/common.h"
|
||||
|
||||
///! @brief List of valid python code types for loading
|
||||
#define PY_CODE_TYPE_STRING 0
|
||||
#define PY_CODE_TYPE_PY 1
|
||||
#define PY_CODE_TYPE_PYC 2
|
||||
|
||||
VOID python_prepare_session();
|
||||
VOID python_destroy_session();
|
||||
VOID python_execute(CHAR* modName, LPBYTE pythonCode, DWORD codeLength, UINT codeType, CHAR* resultVar, Packet* responsePacket);
|
||||
|
||||
DWORD request_python_reset(Remote* remote, Packet* packet);
|
||||
DWORD request_python_execute(Remote* remote, Packet* packet);
|
||||
|
13
c/meterpreter/source/extensions/python/python_main.c
Normal file → Executable file
13
c/meterpreter/source/extensions/python/python_main.c
Normal file → Executable file
@ -110,3 +110,16 @@ DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize)
|
||||
strncpy_s(buffer, bufferSize, "python", bufferSize - 1);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Do a stageless initialisation of the extension.
|
||||
* @param buffer Pointer to the buffer that contains the init data.
|
||||
* @param bufferSize Size of the \c buffer parameter.
|
||||
* @return Indication of success or failure.
|
||||
*/
|
||||
DWORD __declspec(dllexport) StagelessInit(const LPBYTE buffer, DWORD bufferSize)
|
||||
{
|
||||
dprintf("[PYTHON] Executing stagless script:\n%s", (LPCSTR)buffer);
|
||||
python_execute(NULL, (LPSTR)buffer, bufferSize, PY_CODE_TYPE_PY, NULL, NULL);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
1
c/meterpreter/source/server/metsrv.c
Normal file → Executable file
1
c/meterpreter/source/server/metsrv.c
Normal file → Executable file
@ -16,6 +16,7 @@ DWORD __declspec(dllexport) Init(SOCKET fd)
|
||||
// In the case of metsrv payloads, the parameter passed to init is NOT a socket, it's actually
|
||||
// a pointer to the metserv configuration, so do a nasty cast and move on.
|
||||
MetsrvConfig* metConfig = (MetsrvConfig*)fd;
|
||||
dprintf("[METSRV] Getting ready to init with config %p", metConfig);
|
||||
DWORD result = server_setup(metConfig);
|
||||
|
||||
dprintf("[METSRV] Exiting with %08x", metConfig->session.exit_func);
|
||||
|
@ -35,6 +35,7 @@ typedef DWORD (*PSRVINIT)(Remote *remote);
|
||||
typedef DWORD (*PSRVDEINIT)(Remote *remote);
|
||||
typedef DWORD (*PSRVGETNAME)(char* buffer, int bufferSize);
|
||||
typedef VOID (*PCMDADDED)(const char* commandName);
|
||||
typedef DWORD (*PSTAGELESSINIT)(LPBYTE data, DWORD dataSize);
|
||||
|
||||
typedef struct _EXTENSION
|
||||
{
|
||||
@ -43,6 +44,7 @@ typedef struct _EXTENSION
|
||||
PSRVDEINIT deinit;
|
||||
PSRVGETNAME getname;
|
||||
PCMDADDED commandAdded;
|
||||
PSTAGELESSINIT stagelessInit;
|
||||
Command* start;
|
||||
Command* end;
|
||||
char name[16];
|
||||
|
3
c/meterpreter/source/server/remote_dispatch.h
Normal file → Executable file
3
c/meterpreter/source/server/remote_dispatch.h
Normal file → Executable file
@ -4,7 +4,8 @@
|
||||
DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket);
|
||||
DWORD request_core_loadlib(Remote *pRemote, Packet *pPacket);
|
||||
|
||||
DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand);
|
||||
DWORD load_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand);
|
||||
DWORD stagelessinit_extension(const char* extensionName, LPBYTE data, DWORD dataSize);
|
||||
|
||||
VOID register_dispatch_routines();
|
||||
VOID deregister_dispatch_routines(Remote * remote);
|
||||
|
@ -77,11 +77,26 @@ VOID load_stageless_extensions(Remote* remote, MetsrvExtension* stagelessExtensi
|
||||
{
|
||||
dprintf("[SERVER] Extension located at 0x%p: %u bytes", stagelessExtensions->dll, stagelessExtensions->size);
|
||||
HMODULE hLibrary = LoadLibraryR(stagelessExtensions->dll, stagelessExtensions->size);
|
||||
initialise_extension(hLibrary, TRUE, remote, NULL, extensionCommands);
|
||||
load_extension(hLibrary, TRUE, remote, NULL, extensionCommands);
|
||||
stagelessExtensions = (MetsrvExtension*)((LPBYTE)stagelessExtensions->dll + stagelessExtensions->size);
|
||||
}
|
||||
|
||||
dprintf("[SERVER] All stageless extensions loaded");
|
||||
|
||||
// once we have reached the end, we may have extension initializers
|
||||
LPBYTE initData = (LPBYTE)(&stagelessExtensions->size) + sizeof(stagelessExtensions->size);
|
||||
|
||||
while (initData != NULL && *initData != '\0')
|
||||
{
|
||||
const char* extensionName = (const char*)initData;
|
||||
LPBYTE data = initData + strlen(extensionName) + 1 + sizeof(DWORD);
|
||||
DWORD dataSize = *(DWORD*)(data - sizeof(DWORD));
|
||||
dprintf("[STAGELESS] init data at %p, name %s, size is %d", extensionName, extensionName, dataSize);
|
||||
stagelessinit_extension(extensionName, data, dataSize);
|
||||
initData = data + dataSize;
|
||||
}
|
||||
|
||||
dprintf("[SERVER] All stageless extensions initialised");
|
||||
}
|
||||
|
||||
static Transport* create_transport(Remote* remote, MetsrvTransportCommon* transportCommon, LPDWORD size)
|
||||
@ -346,8 +361,6 @@ DWORD server_setup(MetsrvConfig* config)
|
||||
((TcpTransportContext*)remote->transport->ctx)->fd = (SOCKET)config->session.comms_fd;
|
||||
}
|
||||
|
||||
load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize));
|
||||
|
||||
// Set up the transport creation function pointer
|
||||
remote->trans_create = create_transport;
|
||||
// Set up the transport removal function pointer
|
||||
@ -358,6 +371,12 @@ DWORD server_setup(MetsrvConfig* config)
|
||||
// Store our thread handle
|
||||
remote->server_thread = serverThread->handle;
|
||||
|
||||
dprintf("[SERVER] Registering dispatch routines...");
|
||||
register_dispatch_routines();
|
||||
|
||||
// this has to be done after dispatch routine are registered
|
||||
load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize));
|
||||
|
||||
// Store our process token
|
||||
if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token))
|
||||
{
|
||||
@ -383,9 +402,6 @@ DWORD server_setup(MetsrvConfig* config)
|
||||
remote->orig_desktop_name = _strdup(desktopName);
|
||||
remote->curr_desktop_name = _strdup(desktopName);
|
||||
|
||||
dprintf("[SERVER] Registering dispatch routines...");
|
||||
register_dispatch_routines();
|
||||
|
||||
remote->sess_start_time = current_unix_timestamp();
|
||||
|
||||
// loop through the transports, reconnecting each time.
|
||||
|
@ -8,7 +8,24 @@ extern PLIST gExtensionList;
|
||||
// see common/base.c
|
||||
extern Command *extensionCommands;
|
||||
|
||||
DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand)
|
||||
DWORD stagelessinit_extension(const char* extensionName, LPBYTE data, DWORD dataSize)
|
||||
{
|
||||
dprintf("[STAGELESSINIT] searching for extension init for %s in %p", extensionName, gExtensionList);
|
||||
dprintf("[STAGELESSINIT] extension list start is %p", gExtensionList->start);
|
||||
for (PNODE node = gExtensionList->start; node != NULL; node = node->next)
|
||||
{
|
||||
PEXTENSION ext = (PEXTENSION)node->data;
|
||||
dprintf("[STAGELESSINIT] comparing to %s (init is %p)", ext->name, ext->stagelessInit);
|
||||
if (strcmp(ext->name, extensionName) == 0 && ext->stagelessInit != NULL)
|
||||
{
|
||||
dprintf("[STAGELESSINIT] found for %s", extensionName);
|
||||
return ext->stagelessInit(data, dataSize);
|
||||
}
|
||||
}
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
DWORD load_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand)
|
||||
{
|
||||
DWORD dwResult = ERROR_OUTOFMEMORY;
|
||||
PEXTENSION pExtension = (PEXTENSION)malloc(sizeof(EXTENSION));
|
||||
@ -27,6 +44,7 @@ DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote*
|
||||
pExtension->deinit = (PSRVDEINIT)GetProcAddressR(pExtension->library, "DeinitServerExtension");
|
||||
pExtension->getname = (PSRVGETNAME)GetProcAddressR(pExtension->library, "GetExtensionName");
|
||||
pExtension->commandAdded = (PCMDADDED)GetProcAddressR(pExtension->library, "CommandAdded");
|
||||
pExtension->stagelessInit = (PSTAGELESSINIT)GetProcAddressR(pExtension->library, "StagelessInit");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -34,6 +52,7 @@ DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote*
|
||||
pExtension->deinit = (PSRVDEINIT)GetProcAddress(pExtension->library, "DeinitServerExtension");
|
||||
pExtension->getname = (PSRVGETNAME)GetProcAddress(pExtension->library, "GetExtensionName");
|
||||
pExtension->commandAdded = (PCMDADDED)GetProcAddress(pExtension->library, "CommandAdded");
|
||||
pExtension->stagelessInit = (PSTAGELESSINIT)GetProcAddress(pExtension->library, "StagelessInit");
|
||||
}
|
||||
|
||||
// patch in the metsrv.dll's HMODULE handle, used by the server extensions for delay loading
|
||||
@ -207,7 +226,7 @@ DWORD request_core_loadlib(Remote *pRemote, Packet *pPacket)
|
||||
// call its Init routine
|
||||
if ((flags & LOAD_LIBRARY_FLAG_EXTENSION) && library)
|
||||
{
|
||||
res = initialise_extension(library, bLibLoadedReflectivly, pRemote, response, first);
|
||||
res = load_extension(library, bLibLoadedReflectivly, pRemote, response, first);
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
Loading…
Reference in New Issue
Block a user