1
mirror of https://github.com/rapid7/metasploit-payloads synced 2024-12-08 23:33:07 +01:00

Refactor XOR code, dedup packet writing code

This commit is contained in:
OJ 2016-10-10 14:40:05 +10:00
parent f5690866f8
commit 7e8b4c3c52
No known key found for this signature in database
GPG Key ID: D5DC61FB93260597
7 changed files with 241 additions and 387 deletions

View File

@ -108,7 +108,7 @@ void enable_debugging()
#endif
VOID xor_bytes(DWORD xorKey, LPBYTE buffer, DWORD bufferSize)
VOID xor_bytes(BYTE xorKey[sizeof(DWORD)], LPBYTE buffer, DWORD bufferSize)
{
static BOOL initialised = FALSE;
if (!initialised)
@ -117,10 +117,8 @@ VOID xor_bytes(DWORD xorKey, LPBYTE buffer, DWORD bufferSize)
initialised = TRUE;
}
LPBYTE xor = (LPBYTE)&xorKey;
for (DWORD i = 0; i < bufferSize; ++i)
{
buffer[i] ^= xor[i % sizeof(DWORD)];
buffer[i] ^= xorKey[i % sizeof(DWORD)];
}
}

View File

@ -233,4 +233,4 @@ static _inline void real_dprintf(char *format, ...)
#endif
int current_unix_timestamp(void);
VOID xor_bytes(DWORD xorKey, LPBYTE buffer, DWORD bufferSize);
VOID xor_bytes(BYTE xorKey[sizeof(DWORD)], LPBYTE buffer, DWORD bufferSize);

View File

@ -140,6 +140,100 @@ VOID core_update_desktop(Remote * remote, DWORD dwSessionID, char * cpStationNam
#endif
}
/*!
* @brief Serialize a packet to a byte stream, and destroy the packet.
* @param remote Pointer to the remote instance.
* @param packet Pointer to the packet to serialize.
* @param buffer Pointer that will receive a pointer to the serialized packet buffer.
* @param bufferSize Pointer that will receive the resulting serialized packet buffer size.
* @return Indication of success or failure.
*/
DWORD packet_serialize_and_destroy(Remote* remote, Packet* packet, BYTE** buffer, size_t* bufferSize)
{
CryptoContext* crypto;
Tlv requestId;
DWORD res = ERROR_SUCCESS;
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)
{
DWORD index;
CHAR rid[32];
rid[sizeof(rid)-1] = 0;
for (index = 0; index < sizeof(rid)-1; index++)
{
rid[index] = (rand() % 0x5e) + 0x21;
}
packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
}
do
{
// 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))
{
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)
{
SetLastError(res);
break;
}
// Destroy the original payload as we no longer need it
free(origPayload);
// Update the header length
packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
}
// create a buffer for the serialized packet
*bufferSize = sizeof(packet->header) + packet->payloadLength;
*buffer = (BYTE*)calloc(1, *bufferSize);
if (buffer == NULL)
{
res = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// generate a new XOR key
DWORD xorKey = rand_xor_key();
// make sure the existing XOR key it set to zero, we'll be overwriting
// it shortly
memset(packet->header.xor_key, 0, sizeof(packet->header.xor_key));
// copy the header & payload over to the buffer
memcpy(*buffer, &packet->header, sizeof(packet->header));
memcpy(*buffer + sizeof(packet->header), packet->payload, packet->payloadLength);
// XOR the entire buffer, with they key (results in the xor key being written
// to the first 4 bytes because they're currently zero anyway
xor_bytes((BYTE*)&xorKey, *buffer, (DWORD)*bufferSize);
} while (0);
// Destroy the packet
packet_destroy(packet);
lock_release(remote->lock);
return res;
}
/*!
* @brief Create a packet of a given type (request/response) and method.
* @param type The TLV type that this packet represents.

View File

@ -196,7 +196,7 @@ typedef struct
typedef struct
{
DWORD xor_key;
BYTE xor_key[sizeof(DWORD)];
DWORD length;
DWORD type;
} PacketHeader;
@ -237,6 +237,7 @@ typedef struct _PacketRequestCompletion
/*
* Packet manipulation
*/
LINKAGE DWORD packet_serialize_and_destroy(Remote* remote, Packet* packet, BYTE** buffer, size_t* bufferSize);
LINKAGE Packet *packet_create(PacketTlvType type, LPCSTR method);
LINKAGE Packet *packet_create_response(Packet *packet);
LINKAGE Packet* packet_create_group();

View File

@ -529,133 +529,61 @@ out:
*/
DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion)
{
CryptoContext* crypto;
Tlv requestId;
DWORD res;
DWORD idx;
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
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)
{
DWORD index;
CHAR rid[32];
rid[sizeof(rid)-1] = 0;
for (index = 0; index < sizeof(rid)-1; index++)
{
rid[index] = (rand() % 0x5e) + 0x21;
}
packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
}
do
{
// 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_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))
{
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)
{
SetLastError(res);
break;
}
// Destroy the original payload as we no longer need it
free(origPayload);
// Update the header length
packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
}
dprintf("[PACKET] New xor key for sending");
packet->header.xor_key = rand_xor_key();
// before transmission, xor the whole lot, starting with the body
xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength);
// then the header
xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8);
// be sure to switch the xor header before writing
packet->header.xor_key = htonl(packet->header.xor_key);
idx = 0;
while (idx < sizeof(packet->header))
{
// Transmit the packet's header (length, type)
res = SSL_write(
ctx->ssl,
(LPCSTR)(&packet->header) + idx,
sizeof(packet->header) - idx
);
if (res <= 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
break;
}
idx += res;
}
if (res < 0)
{
break;
}
idx = 0;
while (idx < packet->payloadLength)
{
// Transmit the packet's payload (length, type)
res = SSL_write(
ctx->ssl,
packet->payload + idx,
packet->payloadLength - idx
);
if (res < 0)
{
break;
}
idx += res;
}
if (res < 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
break;
}
SetLastError(ERROR_SUCCESS);
} while (0);
res = GetLastError();
// Destroy the packet
packet_destroy(packet);
lock_release(remote->lock);
BYTE* buffer = NULL;
size_t bufferSize = 0;
Tlv requestId;
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
// 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_add_completion_handler((LPCSTR)requestId.buffer, completion);
}
dprintf("[TRANSMIT] Serializing the packet");
DWORD res = packet_serialize_and_destroy(remote, packet, &buffer, &bufferSize);
dprintf("[TRANSMIT] Packet serialised with result: %d 0x%x, buffer: %p, size: %u", res, res, buffer, bufferSize);
lock_acquire(remote->lock);
do
{
if (res != ERROR_SUCCESS || buffer == NULL)
{
dprintf("[PACKET] Error during serialization");
break;
}
size_t index = 0;
int written = 0;
vdprintf("[TRANSMIT] sent %u of %u", index, bufferSize);
while (index < bufferSize)
{
// Transmit the packet's header (length, type)
written = SSL_write(ctx->ssl, buffer + index, (int)(bufferSize - index));
if (written <= 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", written, index);
res = GetLastError();
break;
}
index += written;
vdprintf("[TRANSMIT] sent %u of %u", index, bufferSize);
}
} while (0);
lock_release(remote->lock);
if (buffer != NULL)
{
free(buffer);
}
dprintf("[TRANSMIT] result of packet sending: %d 0x%x", res, res);
return res;
}
@ -715,10 +643,8 @@ static DWORD packet_receive_via_ssl(Remote *remote, Packet **packet)
break;
}
header.xor_key = ntohl(header.xor_key);
// xor the header data
xor_bytes(header.xor_key, &header.length, 8);
xor_bytes(header.xor_key, (PUCHAR)&header.length, 8);
// Initialize the header
header.length = ntohl(header.length);

View File

@ -617,8 +617,6 @@ static DWORD packet_receive_via_ssl(Remote *remote, Packet **packet)
break;
}
header.xor_key = ntohl(header.xor_key);
// xor the header data
xor_bytes(header.xor_key, (LPBYTE)&header.length, 8);
@ -1004,135 +1002,61 @@ static BOOL configure_tcp_connection(Transport* transport)
*/
DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion)
{
CryptoContext* crypto;
BYTE* buffer = NULL;
size_t bufferSize = 0;
Tlv requestId;
DWORD res;
DWORD idx;
TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;
// 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_add_completion_handler((LPCSTR)requestId.buffer, completion);
}
dprintf("[TRANSMIT] Sending packet to the server");
dprintf("[TRANSMIT] Serializing the packet");
DWORD res = packet_serialize_and_destroy(remote, packet, &buffer, &bufferSize);
dprintf("[TRANSMIT] Packet serialised with result: %d 0x%x, buffer: %p, size: %u", res, res, buffer, bufferSize);
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)
{
DWORD index;
CHAR rid[32];
rid[sizeof(rid)-1] = 0;
for (index = 0; index < sizeof(rid)-1; index++)
{
rid[index] = (rand() % 0x5e) + 0x21;
}
packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
}
do
{
// 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))
if (res != ERROR_SUCCESS || buffer == NULL)
{
packet_add_completion_handler((LPCSTR)requestId.buffer, completion);
dprintf("[PACKET] Error during serialization");
break;
}
// 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))
{
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)
{
SetLastError(res);
break;
}
// Destroy the original payload as we no longer need it
free(origPayload);
// Update the header length
packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
}
size_t index = 0;
int written = 0;
vdprintf("[TRANSMIT] sent %u of %u", index, bufferSize);
while (index < bufferSize)
{
// Transmit the packet's header (length, type)
written = SSL_write(ctx->ssl, buffer + index, (int)(bufferSize - index));
dprintf("[PACKET] New xor key for sending");
packet->header.xor_key = rand_xor_key();
// before transmission, xor the whole lot, starting with the body
xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength);
// then the header
xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8);
// be sure to switch the xor header before writing
packet->header.xor_key = htonl(packet->header.xor_key);
idx = 0;
while (idx < sizeof(packet->header))
{
// Transmit the packet's header (length, type)
res = SSL_write(
ctx->ssl,
(LPCSTR)(&packet->header) + idx,
sizeof(packet->header) - idx
);
if (res <= 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
break;
}
idx += res;
if (written <= 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", written, index);
res = GetLastError();
break;
}
index += written;
vdprintf("[TRANSMIT] sent %u of %u", index, bufferSize);
}
if (res < 0)
{
break;
}
idx = 0;
while (idx < packet->payloadLength)
{
// Transmit the packet's payload (length, type)
res = SSL_write(
ctx->ssl,
packet->payload + idx,
packet->payloadLength - idx
);
if (res < 0)
{
break;
}
idx += res;
}
if (res < 0)
{
dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
break;
}
SetLastError(ERROR_SUCCESS);
} while (0);
res = GetLastError();
// Destroy the packet
packet_destroy(packet);
lock_release(remote->lock);
if (buffer != NULL)
{
free(buffer);
}
dprintf("[TRANSMIT] result of packet sending: %d 0x%x", res, res);
return res;
}

View File

@ -262,60 +262,6 @@ static DWORD validate_response_winhttp(HANDLE hReq, HttpTransportContext* ctx)
return ERROR_SUCCESS;
}
/*!
* @brief Windows-specific function to transmit a packet via HTTP(s) using winhttp _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.
*/
static DWORD packet_transmit_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
{
DWORD res = 0;
HINTERNET hReq;
BOOL result;
DWORD retries = 5;
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
unsigned char *buffer;
DWORD totalLength = packet->payloadLength + sizeof(PacketHeader);
buffer = malloc(totalLength);
if (!buffer)
{
SetLastError(ERROR_NOT_FOUND);
return 0;
}
memcpy(buffer, &packet->header, sizeof(PacketHeader));
memcpy(buffer + sizeof(PacketHeader), packet->payload, packet->payloadLength);
do
{
hReq = ctx->create_req(ctx, FALSE, "PACKET TRANSMIT");
if (hReq == NULL)
{
break;
}
result = ctx->send_req(hReq, buffer, totalLength);
if (!result)
{
dprintf("[PACKET TRANSMIT] Failed HttpSendRequest: %d", GetLastError());
SetLastError(ERROR_NOT_FOUND);
break;
}
dprintf("[PACKET TRANSMIT] request sent.. apparently");
} while(0);
memset(buffer, 0, totalLength);
ctx->close_req(hReq);
return res;
}
/*!
* @brief Transmit a packet via HTTP(s) _and_ destroy it.
* @param remote Pointer to the \c Remote instance.
@ -325,94 +271,60 @@ static DWORD packet_transmit_http(Remote *remote, Packet *packet, PacketRequestC
*/
static DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
{
CryptoContext *crypto;
Tlv requestId;
DWORD res;
DWORD res;
BYTE* buffer = NULL;
size_t bufferSize = 0;
Tlv requestId;
HINTERNET hReq = NULL;
HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx;
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)
{
DWORD index;
CHAR rid[32];
rid[sizeof(rid)-1] = 0;
for (index = 0; index < sizeof(rid)-1; index++)
{
rid[index] = (rand() % 0x5e) + 0x21;
}
packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
}
do
{
// 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_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))
{
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)
{
SetLastError(res);
break;
}
// Destroy the original payload as we no longer need it
free(origPayload);
// Update the header length
packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
}
// 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_add_completion_handler((LPCSTR)requestId.buffer, completion);
}
dprintf("[PACKET] New xor key for sending");
packet->header.xor_key = rand_xor_key();
dprintf("[PACKET] XOR Encoding payload");
// before transmission, xor the whole lot, starting with the body
xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength);
dprintf("[PACKET] XOR Encoding header");
// then the header
xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8);
// be sure to switch the xor header before writing
packet->header.xor_key = htonl(packet->header.xor_key);
dprintf("[PACKET] Transmitting packet of length %d to remote", packet->payloadLength);
res = packet_transmit_http(remote, packet, completion);
if (res < 0)
{
dprintf("[PACKET] transmit failed with return %d\n", res);
break;
}
SetLastError(ERROR_SUCCESS);
dprintf("[TRANSMIT] Serializing the packet");
res = packet_serialize_and_destroy(remote, packet, &buffer, &bufferSize);
lock_acquire(remote->lock);
do
{
if (res != ERROR_SUCCESS)
{
break;
}
hReq = ctx->create_req(ctx, FALSE, "PACKET TRANSMIT");
if (hReq == NULL)
{
res = GetLastError();
break;
}
if (!ctx->send_req(hReq, buffer, (DWORD)bufferSize))
{
res = GetLastError();
dprintf("[PACKET TRANSMIT] Failed HttpSendRequest: %d", res);
break;
}
dprintf("[PACKET TRANSMIT] request sent.. apparently");
} while (0);
res = GetLastError();
// Destroy the packet
packet_destroy(packet);
ctx->close_req(hReq);
lock_release(remote->lock);
if (buffer != NULL)
{
free(buffer);
}
return res;
}
@ -522,7 +434,6 @@ static DWORD packet_receive_http(Remote *remote, Packet **packet)
}
dprintf("[PACKET RECEIVE HTTP] decoding header");
header.xor_key = ntohl(header.xor_key);
xor_bytes(header.xor_key, (LPBYTE)&header.length, 8);
header.length = ntohl(header.length);