1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-18 07:11:12 +02:00

511 lines
15 KiB
C
Executable File

/*!
* @file python_commands.c
* @brief Definitions for the python command bindings.
*/
#include "Python.h"
#include "marshal.h"
#include "python_main.h"
#include "python_commands.h"
#include "python_meterpreter_binding.h"
#include "Resource Files/python_core.rh"
#include "common_metapi.h"
///! @brief Struct that contains pointer to init function and name.
typedef struct _InitFunc
{
#ifdef DEBUGTRACE
PCHAR name;
#endif
PyMODINIT_FUNC(*func)(void);
} InitFunc;
#ifdef DEBUGTRACE
#define DEC_INIT_FUNC(x) { #x, x }
#else
#define DEC_INIT_FUNC(x) { x }
#endif
// All external python functions we have baked into the runtime which let us deploy
// it as one chunk rather than dynamically loading libs.
extern PyMODINIT_FUNC initerrno(void);
extern PyMODINIT_FUNC init_functools(void);
extern PyMODINIT_FUNC init_socket(void);
extern PyMODINIT_FUNC init_weakref(void);
extern PyMODINIT_FUNC initarray(void);
extern PyMODINIT_FUNC initaudioop(void);
extern PyMODINIT_FUNC init_csv(void);
extern PyMODINIT_FUNC init_io(void);
extern PyMODINIT_FUNC init_multibytecodec(void);
extern PyMODINIT_FUNC init_bisect(void);
extern PyMODINIT_FUNC init_codecs(void);
extern PyMODINIT_FUNC init_collections(void);
extern PyMODINIT_FUNC init_heapq(void);
extern PyMODINIT_FUNC init_locale(void);
extern PyMODINIT_FUNC init_lsprof(void);
extern PyMODINIT_FUNC init_random(void);
extern PyMODINIT_FUNC init_sre(void);
extern PyMODINIT_FUNC init_struct(void);
extern PyMODINIT_FUNC init_weakref(void);
extern PyMODINIT_FUNC initaudioop(void);
extern PyMODINIT_FUNC initbinascii(void);
extern PyMODINIT_FUNC initcmath(void);
extern PyMODINIT_FUNC initcPickle(void);
extern PyMODINIT_FUNC initcStringIO(void);
extern PyMODINIT_FUNC initdatetime(void);
extern PyMODINIT_FUNC initfuture_builtins(void);
extern PyMODINIT_FUNC initgc(void);
extern PyMODINIT_FUNC initimageop(void);
extern PyMODINIT_FUNC inititertools(void);
extern PyMODINIT_FUNC initmath(void);
extern PyMODINIT_FUNC init_md5(void);
extern PyMODINIT_FUNC initmmap(void);
extern PyMODINIT_FUNC initoperator(void);
extern PyMODINIT_FUNC initparser(void);
extern PyMODINIT_FUNC initnt(void);
extern PyMODINIT_FUNC init_sha256(void);
extern PyMODINIT_FUNC init_sha512(void);
extern PyMODINIT_FUNC init_sha(void);
extern PyMODINIT_FUNC initsignal(void);
extern PyMODINIT_FUNC initstrop(void);
extern PyMODINIT_FUNC init_symtable(void);
extern PyMODINIT_FUNC initthread(void);
extern PyMODINIT_FUNC inittime(void);
extern PyMODINIT_FUNC initxxsubtype(void);
extern PyMODINIT_FUNC initzipimport(void);
extern PyMODINIT_FUNC init_subprocess(void);
extern PyMODINIT_FUNC init_winreg(void);
extern PyMODINIT_FUNC initselect(void);
extern PyMODINIT_FUNC initunicodedata(void);
extern PyMODINIT_FUNC init_ctypes(void);
extern PyMODINIT_FUNC initmsvcrt(void);
extern PyMODINIT_FUNC init_ssl(void);
extern PyMODINIT_FUNC init_multiprocessing(void);
/// order of these is actually important
static InitFunc init_funcs[] =
{
// the functions below that are commented out are invoked prior
// to the python modules being included.
//DEC_INIT_FUNC(initerrno),
//DEC_INIT_FUNC(initnt),
//DEC_INIT_FUNC(init_socket),
//DEC_INIT_FUNC(init_functools),
DEC_INIT_FUNC(initmsvcrt),
DEC_INIT_FUNC(initselect),
DEC_INIT_FUNC(init_weakref),
DEC_INIT_FUNC(initarray),
DEC_INIT_FUNC(initaudioop),
DEC_INIT_FUNC(init_csv),
DEC_INIT_FUNC(init_io),
DEC_INIT_FUNC(init_multibytecodec),
DEC_INIT_FUNC(init_bisect),
DEC_INIT_FUNC(init_codecs),
DEC_INIT_FUNC(init_collections),
DEC_INIT_FUNC(init_heapq),
DEC_INIT_FUNC(init_locale),
DEC_INIT_FUNC(init_lsprof),
DEC_INIT_FUNC(init_random),
DEC_INIT_FUNC(init_sre),
DEC_INIT_FUNC(init_struct),
DEC_INIT_FUNC(init_weakref),
DEC_INIT_FUNC(initaudioop),
DEC_INIT_FUNC(initbinascii),
DEC_INIT_FUNC(initcmath),
DEC_INIT_FUNC(initcStringIO),
DEC_INIT_FUNC(initcPickle),
DEC_INIT_FUNC(inittime),
DEC_INIT_FUNC(initdatetime),
DEC_INIT_FUNC(initgc),
DEC_INIT_FUNC(initimageop),
DEC_INIT_FUNC(inititertools),
DEC_INIT_FUNC(initfuture_builtins),
DEC_INIT_FUNC(initmath),
DEC_INIT_FUNC(init_md5),
DEC_INIT_FUNC(initmmap),
DEC_INIT_FUNC(initoperator),
DEC_INIT_FUNC(initparser),
DEC_INIT_FUNC(init_sha256),
DEC_INIT_FUNC(init_sha512),
DEC_INIT_FUNC(init_sha),
DEC_INIT_FUNC(initsignal),
DEC_INIT_FUNC(initstrop),
DEC_INIT_FUNC(init_symtable),
DEC_INIT_FUNC(initunicodedata),
DEC_INIT_FUNC(initthread),
DEC_INIT_FUNC(initxxsubtype),
DEC_INIT_FUNC(initzipimport),
DEC_INIT_FUNC(init_subprocess),
DEC_INIT_FUNC(init_winreg),
DEC_INIT_FUNC(init_ctypes),
DEC_INIT_FUNC(init_ssl),
DEC_INIT_FUNC(init_multiprocessing),
DEC_INIT_FUNC(NULL)
};
static LIST* stderrBuffer = NULL;
static LIST* stdoutBuffer = NULL;
static LPBYTE coreLibPointer = NULL;
static DWORD coreLibSize = 0;
static PyObject* handle_write(LIST* target, PyObject* self, PyObject* args)
{
const char* written = NULL;
if (PyArg_ParseTuple(args, "s", &written))
{
dprintf("[PYTHON] something written to %p: %s", target, written);
if (target != NULL)
{
met_api->list.add(target, strdup(written));
}
}
else
{
dprintf("[PYTHON] something written to %p (can't parse)", target);
}
return Py_BuildValue("");
}
static PyObject* handle_flush(PyObject* self, PyObject* args)
{
return Py_BuildValue("");
}
static PyObject* handle_stderr(PyObject* self, PyObject* args)
{
return handle_write(stderrBuffer, self, args);
}
static PyObject* handle_stdout(PyObject* self, PyObject* args)
{
return handle_write(stdoutBuffer, self, args);
}
///! @brief Defines a hook for catching stdout
static PyMethodDef meterpreter_stdout_hooks[] =
{
{ "write", handle_stdout, METH_VARARGS, "Write something to stdout" },
{ "flush", handle_flush, METH_NOARGS, "Flush stdout" },
{ NULL, NULL, 0, NULL }
};
///! @brief Defines a hook for catching stderr
static PyMethodDef meterpreter_stderr_hooks[] =
{
{ "write", handle_stderr, METH_VARARGS, "Write something to stderr" },
{ "flush", handle_flush, METH_NOARGS, "Flush stderr" },
{ NULL, NULL, 0, NULL }
};
static VOID dump_to_packet(LIST* source, Packet* packet, UINT tlvType)
{
met_api->lock.acquire(source->lock);
PNODE current = source->start;
while (current != NULL)
{
met_api->packet.add_tlv_string(packet, tlvType, (LPCSTR)current->data);
current = current->next;
}
met_api->lock.release(source->lock);
}
VOID clear_std_handler(LIST* source)
{
dprintf("[PYTHON] clearing list %p", source);
met_api->list.clear(source, free);
dprintf("[PYTHON] cleared list %p", source);
}
VOID initialize_std_handlers()
{
dprintf("[PYTHON] initializing handlers");
if (stderrBuffer == NULL)
{
stderrBuffer = met_api->list.create();
}
if (stdoutBuffer == NULL)
{
stdoutBuffer = met_api->list.create();
}
dprintf("[PYTHON] initialized handlers");
}
VOID destroy_std_handlers()
{
dprintf("[PYTHON] destroying handlers");
clear_std_handler(stderrBuffer);
met_api->list.destroy(stderrBuffer);
stderrBuffer = NULL;
clear_std_handler(stdoutBuffer);
met_api->list.destroy(stdoutBuffer);
stdoutBuffer = NULL;
dprintf("[PYTHON] destroyed handlers");
}
/*!
* @brief Destroy the session.
*/
VOID python_destroy_session()
{
destroy_std_handlers();
Py_Finalize();
}
/*!
* @brief Prepare the session for use, including all the resources that are embedded.
*/
VOID python_prepare_session()
{
Py_IgnoreEnvironmentFlag = 1;
Py_NoSiteFlag = 1;
Py_Initialize();
PyEval_InitThreads();
PyObject* stdoutModule = Py_InitModule("meterpreter_stdout", meterpreter_stdout_hooks);
if (stdoutModule != NULL && PySys_SetObject("stdout", stdoutModule) == 0)
{
dprintf("[PYTHON] Successfully set the stdout hook");
}
else
{
dprintf("[PYTHON] Failed to set the stdout hook");
}
PyObject* stderrModule = Py_InitModule("meterpreter_stderr", meterpreter_stderr_hooks);
if (stderrModule != NULL && PySys_SetObject("stderr", stderrModule) == 0)
{
dprintf("[PYTHON] Successfully set the stderr hook");
}
else
{
dprintf("[PYTHON] Failed to set the stderr hook");
}
// with the output handlers sorted, we load the stuff from the compressed resource
// which should give us all the stuff we need to be useful.
initerrno();
initnt();
init_socket();
init_functools();
// have we loaded the core pointer already?
if (coreLibPointer == NULL)
{
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery((LPVOID)python_prepare_session, &mbi, sizeof(mbi)))
{
dprintf("[PYTHON] VirtualQuery failed: %d", GetLastError());
return;
}
HMODULE mod = (HMODULE)mbi.AllocationBase;
dprintf("[PYTHON] Module handle: %p", (LPVOID)mod);
HRSRC res = FindResource(mod, MAKEINTRESOURCEA(IDR_PYTHON_CORE), "BINARY");
if (res == NULL)
{
dprintf("[PYTHON] Unable to find resource: %d", GetLastError());
return;
}
HGLOBAL file = LoadResource(mod, res);
if (file == NULL)
{
dprintf("[PYTHON] Unable to load core library resource: %d", GetLastError());
return;
}
// store these pointers for when we reset the session, saves us from
// doing all of this nonsense again.
coreLibPointer = (LPBYTE)LockResource(file);
coreLibSize = *(LPDWORD)coreLibPointer;
coreLibPointer += sizeof(DWORD);
}
dprintf("[PYTHON] coreLibPointer: %p, coreLibSize: %d", coreLibPointer, coreLibSize);
if (coreLibPointer != NULL)
{
// Create a byte array with everything in it
PyObject* libString = PyString_FromStringAndSize(coreLibPointer, coreLibSize);
dprintf("[PYTHON] libString is %p", libString);
// import zlib
PyObject* zlibModStr = PyString_FromString("zlib");
dprintf("[PYTHON] zlibModStr: %p", zlibModStr);
PyObject* zlibMod = PyImport_Import(zlibModStr);
dprintf("[PYTHON] zlibMod: %p", zlibMod);
// get a reference to the decompress function
PyObject* zlibDecompress = PyObject_GetAttrString(zlibMod, "decompress");
dprintf("[PYTHON] zlibDecompress: %p", zlibDecompress);
// prepare arguments for invocation
PyObject* zlibDecompressArgs = PyTuple_Pack(1, libString);
dprintf("[PYTHON] zlibDecompressArgs: %p", zlibDecompressArgs);
// call zlib.decompress(libString)
PyObject* zlibDecompressResult = PyObject_CallObject(zlibDecompress, zlibDecompressArgs);
dprintf("[PYTHON] zlibDecompressResult: %p", zlibDecompressResult);
//dprintf("[PYTHON] zlibDecompressResult type: %s", zlibDecompressResult->ob_type->tp_name);
PCHAR byteArray = NULL;
Py_ssize_t byteArrayLength = 0;
PyString_AsStringAndSize(zlibDecompressResult, &byteArray, &byteArrayLength);
dprintf("[PYTHON] bytes: %p %u", byteArray, byteArrayLength);
PyObject* modData = PyMarshal_ReadObjectFromString(byteArray, byteArrayLength);
dprintf("[PYTHON] modData: %p", modData);
PyObject* mainMod = PyImport_AddModule("__main__");
PyObject* mainDict = PyModule_GetDict(mainMod);
PyModule_AddObject(mainMod, "met_lib_data", modData);
// TODO: double-check that we don't need to remove existing finders which might
// hit the file system
#ifdef DEBUGTRACE
PyRun_SimpleString("eval(met_lib_data[0]);met_init(True)");
#else
PyRun_SimpleString("eval(met_lib_data[0]);met_init(False)");
#endif
// TODO: figure out which reference counts need to be reduce to avoid leaking.
}
// now load the baked-in modules
PyErr_Clear();
for (InitFunc* f = &init_funcs[0]; f->func != NULL; f += 1)
{
dprintf("[PYTHON] Running %s", f->name);
f->func();
if (PyErr_Occurred())
{
#ifdef DEBUGTRACE
PyErr_Print();
#endif
dprintf("[PYTHON] %s errored", f->name);
PyErr_Clear();
}
}
initialize_std_handlers();
binding_init();
}
/*!
* @brief Reset/restart the interpreter.
* @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_reset(Remote* remote, Packet* packet)
{
dprintf("[PYTHON] resetting the interpreter");
destroy_std_handlers();
Py_Finalize();
Py_Initialize();
python_prepare_session();
met_api->packet.transmit_empty_response(remote, packet, ERROR_SUCCESS);
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
met_api->packet.add_tlv_string(responsePacket, TLV_TYPE_EXTENSION_PYTHON_RESULT, PyString_AsString(result));
}
else
{
PyObject* resultStr = PyObject_Str(result);
met_api->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 = met_api->packet.create_response(packet);
DWORD codeSize = 0;
LPBYTE pythonCode = met_api->packet.get_tlv_value_raw(packet, TLV_TYPE_EXTENSION_PYTHON_CODE, &codeSize);
PyObject* mainModule = PyImport_AddModule("__main__");
PyObject* mainDict = PyModule_GetDict(mainModule);
if (pythonCode != NULL)
{
UINT codeType = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_TYPE);
CHAR* modName = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_EXTENSION_PYTHON_NAME);
UINT pythonCodeLength = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_EXTENSION_PYTHON_CODE_LEN);
CHAR* resultVar = met_api->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);
dump_to_packet(stdoutBuffer, response, TLV_TYPE_EXTENSION_PYTHON_STDOUT);
clear_std_handler(stdoutBuffer);
met_api->packet.transmit_response(dwResult, remote, response);
}
return dwResult;
}