From 7e8b4c3c5206891de38312c15518e5139fc56d6e Mon Sep 17 00:00:00 2001 From: OJ Date: Mon, 10 Oct 2016 14:40:05 +1000 Subject: [PATCH] Refactor XOR code, dedup packet writing code --- c/meterpreter/source/common/common.c | 6 +- c/meterpreter/source/common/common.h | 2 +- c/meterpreter/source/common/core.c | 94 +++++++++ c/meterpreter/source/common/core.h | 3 +- .../source/server/server_setup_posix.c | 186 ++++++------------ .../source/server/win/server_transport_tcp.c | 154 ++++----------- .../server/win/server_transport_winhttp.c | 183 +++++------------ 7 files changed, 241 insertions(+), 387 deletions(-) diff --git a/c/meterpreter/source/common/common.c b/c/meterpreter/source/common/common.c index 35c0ae1d..5ae43ce1 100755 --- a/c/meterpreter/source/common/common.c +++ b/c/meterpreter/source/common/common.c @@ -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)]; } } diff --git a/c/meterpreter/source/common/common.h b/c/meterpreter/source/common/common.h index 45889798..e3a5d163 100755 --- a/c/meterpreter/source/common/common.h +++ b/c/meterpreter/source/common/common.h @@ -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); \ No newline at end of file +VOID xor_bytes(BYTE xorKey[sizeof(DWORD)], LPBYTE buffer, DWORD bufferSize); \ No newline at end of file diff --git a/c/meterpreter/source/common/core.c b/c/meterpreter/source/common/core.c index 696572a6..1e91d760 100755 --- a/c/meterpreter/source/common/core.c +++ b/c/meterpreter/source/common/core.c @@ -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. diff --git a/c/meterpreter/source/common/core.h b/c/meterpreter/source/common/core.h index af976f3f..e2fdd94d 100755 --- a/c/meterpreter/source/common/core.h +++ b/c/meterpreter/source/common/core.h @@ -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(); diff --git a/c/meterpreter/source/server/server_setup_posix.c b/c/meterpreter/source/server/server_setup_posix.c index 8031375e..8dd9b3f4 100755 --- a/c/meterpreter/source/server/server_setup_posix.c +++ b/c/meterpreter/source/server/server_setup_posix.c @@ -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); diff --git a/c/meterpreter/source/server/win/server_transport_tcp.c b/c/meterpreter/source/server/win/server_transport_tcp.c index 64094d3d..f4a82fa1 100755 --- a/c/meterpreter/source/server/win/server_transport_tcp.c +++ b/c/meterpreter/source/server/win/server_transport_tcp.c @@ -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; } diff --git a/c/meterpreter/source/server/win/server_transport_winhttp.c b/c/meterpreter/source/server/win/server_transport_winhttp.c index dc098e47..57b8de06 100755 --- a/c/meterpreter/source/server/win/server_transport_winhttp.c +++ b/c/meterpreter/source/server/win/server_transport_winhttp.c @@ -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);