1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-30 22:19:17 +02:00

Documented base.* and core.*

Big job, this documentation lark. Also modified the prototype the
packet_is_tlv_null_terminated function, which used to take a Packet
instance as well as the TLV, but never used the packet in its
implementation.
This commit is contained in:
OJ 2013-10-15 16:14:39 +10:00
parent ebf13ffaa7
commit 2c865a4a37
5 changed files with 405 additions and 189 deletions
c/meterpreter/source
common
extensions/stdapi/server/sys/process

@ -506,7 +506,7 @@ DWORD command_validate_arguments(Command *command, Packet *packet)
switch (tlvMetaType)
{
case TLV_META_TYPE_STRING:
if (packet_is_tlv_null_terminated(packet, &current) != ERROR_SUCCESS)
if (packet_is_tlv_null_terminated(&current) != ERROR_SUCCESS)
res = ERROR_INVALID_PARAMETER;
break;
default:

@ -9,7 +9,7 @@
#include "core.h"
/*! @brief Function pointer type that defines the interface for a dispatch handler. */
typedef DWORD (*DISPATCH_ROUTINE)(Remote *remote, Packet *packet);
typedef DWORD (*DISPATCH_ROUTINE)( Remote *remote, Packet *packet );
/*! @brief Specifies the maximum number of arguments that are checked/handled
* in a request/response packet dispatcher.

@ -1,26 +1,44 @@
/*!
* @file core.c
* @brief Definitions of core components of the Meterpreter suite.
* @details Much of what exists in the core files is used in almost every area
* of the Meterpreter code base, and hence it's very important. Don't
* change this stuff unless you know what you're doing!
*/
#include "common.h"
DWORD packet_find_tlv_buf(Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index,
TlvType type, Tlv *tlv);
/*! @brief List element that contains packet completion routine details. */
typedef struct _PacketCompletionRoutineEntry
{
LPCSTR requestId;
PacketRequestCompletion handler;
struct _PacketCompletionRoutineEntry *next;
LPCSTR requestId; ///< Id of the request.
PacketRequestCompletion handler; ///< Handler to call on completion.
struct _PacketCompletionRoutineEntry *next; ///< Pointer to the next compleiont routine entry.
} PacketCompletionRoutineEntry;
/*!
* @brief Reference to the list of packet completion routines.
* @details This pointer is a singularly-linked list which contains references
* to PacketCompletionRouteEntry items, each of which is processed
* when packet_call_completion_handlers is invoked.
*/
PacketCompletionRoutineEntry *packetCompletionRoutineList = NULL;
/************
* Core API *
************/
/*
* Transmit a single string to the remote connection with instructions to
* print it to the screen or whatever medium has been established.
/*!
* @brief Print a remote console message.
* @details Transmit a single string to the remote connection with instructions
* to print it to the screen or whatever medium has been established.
* @param remote Pointer to the \c Remote instance that the message should be
sent to
* @param fmt Format string.
* @param ... Varargs that will be printed to the \c fmt format string.
* @return Indication of success or failure.
* @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the request packet.
* @retval ERROR_SUCCESS Transmission was successful.
*/
DWORD send_core_console_write(Remote *remote, LPCSTR fmt, ...)
DWORD send_core_console_write( Remote *remote, LPCSTR fmt, ... )
{
Packet *request = NULL;
CHAR buf[8192];
@ -58,16 +76,17 @@ DWORD send_core_console_write(Remote *remote, LPCSTR fmt, ...)
return res;
}
/*
* XXX
/*!
* @todo I have no idea why this is here, need someone else to explain.
*/
HANDLE core_update_thread_token(Remote *remote, HANDLE token)
HANDLE core_update_thread_token( Remote *remote, HANDLE token )
{
HANDLE temp = NULL;
#ifdef _WIN32
lock_acquire( remote->lock );
do {
do
{
temp = remote->hThreadToken;
// A NULL token resets the state back to the server token
@ -78,12 +97,11 @@ HANDLE core_update_thread_token(Remote *remote, HANDLE token)
remote->hThreadToken = token;
// Close the old token if its not one of the two active tokens
if(temp && temp != remote->hServerToken && temp != remote->hThreadToken) {
if( temp && temp != remote->hServerToken && temp != remote->hThreadToken ) {
CloseHandle(temp);
}
} while(0);
lock_release( remote->lock );
#else
/*
@ -93,11 +111,15 @@ HANDLE core_update_thread_token(Remote *remote, HANDLE token)
return(token);
}
/*
* Update the session/station/desktop to be used by multi threaded meterpreter for desktop related operations.
* We dont store the handles as it is more convienient to use string,s especially as we cant use the regular API
* to break out of sessions.
* Note: It is up to the caller to free any station/desktop name provided as internally we use strdup.
/*!
* @brief Update the session/station/desktop to be used by multi threaded meterpreter for desktop related operations.
* @details We dont store the handles as it is more convienient to use strings, especially as we cant use the regular API
* to break out of sessions.
* @remark It is up to the caller to free any station/desktop name provided as internally we use \c strdup.
* @param remote Pointer to the remote connection.
* @param dwSessionID ID of the session which contains the window station in \c cpStationName.
* @param cpStationName Name of the window station that contains the desktop in \c cpDesktopName.
* @param cpDesktopName Name of the desktop to switch to.
*/
VOID core_update_desktop( Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName )
{
@ -142,14 +164,14 @@ VOID core_update_desktop( Remote * remote, DWORD dwSessionID, char * cpStationNa
lock_release( remote->lock );
#endif
}
/*******************
* Packet Routines *
*******************/
/*
* Create a packet of a given type (request/response) and method.
/*!
* @brief Create a packet of a given type (request/response) and method.
* @param type The TLV type that this packet represents.
* @param method TLV method type (can be \c NULL).
* @return Pointer to the newly created \c Packet.
*/
Packet *packet_create(PacketTlvType type, LPCSTR method)
Packet *packet_create( PacketTlvType type, LPCSTR method )
{
Packet *packet = NULL;
BOOL success = FALSE;
@ -191,11 +213,14 @@ Packet *packet_create(PacketTlvType type, LPCSTR method)
return packet;
}
/*
* Create a response packet from a request, referencing the requestors
/*!
* @brief Create a response packet from a request.
* @details Create a response packet from a request, referencing the requestors
* message identifier.
* @param request The request \c Packet to build a response for.
* @return Pointer to a new \c Packet.
*/
Packet *packet_create_response(Packet *request)
Packet *packet_create_response( Packet *request )
{
Packet *response = NULL;
Tlv method, requestId;
@ -240,8 +265,9 @@ Packet *packet_create_response(Packet *request)
return response;
}
/*
* Destroy the packet context and the payload buffer
/*!
* @brief Destroy the packet context and the payload buffer.
* @param packet Pointer to the \c Packet to destroy.
*/
VOID packet_destroy( Packet * packet )
{
@ -279,28 +305,46 @@ VOID packet_destroy( Packet * packet )
free( packet );
}
/*
* Add a TLV as a string, including the null terminator.
/*!
* @brief Add a string value TLV to a packet, including the \c NULL terminator.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param str Pointer to the string value to add to the packet.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_string(Packet *packet, TlvType type, LPCSTR str)
DWORD packet_add_tlv_string( Packet *packet, TlvType type, LPCSTR str )
{
return packet_add_tlv_raw(packet, type, (PUCHAR)str, (DWORD)strlen(str) + 1);
}
/*
* Add a TLV as a string, including the null terminator.
/*!
* @brief Add a unsigned integer value TLV to a packet.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param val The value to add to the packet.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val)
DWORD packet_add_tlv_uint( Packet *packet, TlvType type, UINT val )
{
val = htonl(val);
return packet_add_tlv_raw(packet, type, (PUCHAR)&val, sizeof(val));
}
/*
* Add a TLV as a QWORD.
/*!
* @brief Add a quad-work value TLV to a packet.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param val The value to add to the packet.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val )
DWORD packet_add_tlv_qword( Packet *packet, TlvType type, QWORD val )
{
val = htonq( val );
@ -308,18 +352,32 @@ DWORD packet_add_tlv_qword(Packet *packet, TlvType type, QWORD val )
}
/*
* Add a TLV as a bool.
/*!
* @brief Add a boolean value TLV to a packet.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param val The value to add to the packet.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val)
{
return packet_add_tlv_raw(packet, type, (PUCHAR)&val, 1);
}
/*
* Add a TLV group. A TLV group is a TLV that contains multiple sub-TLVs
/*!
* @brief Add a group TLV to a packet.
* @details A TLV group is a TLV that contains multiple sub-TLVs.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param entries Pointer to the array of TLV entries to add.
* @param numEntries Count of the number of TLV entries in the \c entries array.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries)
DWORD packet_add_tlv_group( Packet *packet, TlvType type, Tlv *entries, DWORD numEntries )
{
DWORD totalSize = 0,
offset = 0,
@ -369,23 +427,37 @@ DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD num
return res;
}
/*
* Add an array of TLVs
/*!
* @brief Add an array of TLVs to a packet.
* @param packet Pointer to the packet to add the values to.
* @param entries Pointer to the array of TLV entries to add.
* @param numEntries Count of the number of TLV entries in the \c entries array.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries)
DWORD packet_add_tlvs( Packet *packet, Tlv *entries, DWORD numEntries )
{
DWORD index;
for (index = 0; index < numEntries; index++)
packet_add_tlv_raw(packet, entries[index].header.type, entries[index].buffer, entries[index].header.length);
packet_add_tlv_raw(packet, (TlvType)entries[index].header.type, entries[index].buffer, entries[index].header.length);
return ERROR_SUCCESS;
}
/*
* Add an arbitrary TLV whose data is to be compressed with zlib.
/*!
* @brief Add a raw value TLV to a packet, with compression.
* @details The value given in the \c buf parameter will be compressed with zlib.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param buf Pointer to the data that is to be compressed and added.
* @param length Number of bytes in \c buf to compress.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_raw_compressed(Packet *packet, TlvType type, LPVOID buf, DWORD length)
DWORD packet_add_tlv_raw_compressed( Packet *packet, TlvType type, LPVOID buf, DWORD length )
{
DWORD result = ERROR_SUCCESS;
DWORD headerLength = sizeof( TlvHeader );
@ -446,10 +518,18 @@ DWORD packet_add_tlv_raw_compressed(Packet *packet, TlvType type, LPVOID buf, DW
return result;
}
/*
* Add an arbitrary TLV
/*!
* @brief Add an arbitrary raw value TLV to a packet.
* @details The value given in the \c buf parameter will _not_ be compressed.
* @param packet Pointer to the packet to add the value to.
* @param type TLV type for the value.
* @param buf Pointer to the data that is to be added.
* @param length Number of bytes in \c buf to add.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_ENOUGH_MEMORY Insufficient memory available.
*/
DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length)
DWORD packet_add_tlv_raw( Packet *packet, TlvType type, LPVOID buf, DWORD length )
{
DWORD headerLength = sizeof(TlvHeader);
DWORD realLength = length + headerLength;
@ -462,9 +542,9 @@ DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length)
// Allocate/Reallocate the packet's payload
if (packet->payload)
newPayload = (PUCHAR)realloc(packet->payload, newPayloadLength);
newPayload = (PUCHAR)realloc( packet->payload, newPayloadLength );
else
newPayload = (PUCHAR)malloc(newPayloadLength);
newPayload = (PUCHAR)malloc( newPayloadLength );
if (!newPayload)
return ERROR_NOT_ENOUGH_MEMORY;
@ -473,7 +553,7 @@ DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length)
((LPDWORD)(newPayload + packet->payloadLength))[0] = htonl(realLength);
((LPDWORD)(newPayload + packet->payloadLength))[1] = htonl((DWORD)type);
memcpy(newPayload + packet->payloadLength + headerLength, buf, length);
memcpy( newPayload + packet->payloadLength + headerLength, buf, length );
// Update the header length and payload length
packet->header.length = htonl(ntohl(packet->header.length) + realLength);
@ -483,10 +563,17 @@ DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length)
return ERROR_SUCCESS;
}
/*
* Checks to see if a tlv is null terminated
/*!
* @brief Check if a TLV is NULL-terminated.
* @details The function checks the data within the range of bytes specified by
* the \c length property of the TLV \c header.
* @param tlv Pointer to the TLV to check.
* @return Indication of whether the TLV is terminated with a \c NULL byte or not.
* @retval ERROR_SUCCESS A \c NULL byte is present.
* @retval ERROR_NOT_FOUND No \c NULL byte is present.
* @sa TlvHeader
*/
DWORD packet_is_tlv_null_terminated(Packet *packet, Tlv *tlv)
DWORD packet_is_tlv_null_terminated( Tlv *tlv )
{
if ((tlv->header.length) && (tlv->buffer[tlv->header.length - 1] != 0))
return ERROR_NOT_FOUND;
@ -494,84 +581,132 @@ DWORD packet_is_tlv_null_terminated(Packet *packet, Tlv *tlv)
return ERROR_SUCCESS;
}
/*
* Get the type of the packet
/*!
* @brief Get the TLV type of the packet.
* @param packet Pointer to the packet to get the type from.
* @return \c PacketTlvType for the given \c Packet.
*/
PacketTlvType packet_get_type(Packet *packet)
PacketTlvType packet_get_type( Packet *packet )
{
return (PacketTlvType)ntohl(packet->header.type);
return (PacketTlvType)ntohl( packet->header.type );
}
TlvMetaType packet_get_tlv_meta(Packet *packet, Tlv *tlv)
/*!
* @brief Get the TLV meta-type of the packet.
* @param packet Pointer to the packet to get the meta-type from.
* @return \c TlvMetaType for the given \c Packet.
*/
TlvMetaType packet_get_tlv_meta( Packet *packet, Tlv *tlv )
{
return TLV_META_TYPE_MASK(tlv->header.type);
return TLV_META_TYPE_MASK( tlv->header.type );
}
/*
* Get the TLV of the given type
/*!
* @brief Get a TLV of a given type from the packet.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get.
* @param tlv Pointer to the TLV that will receive the data.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_FOUND Unable to find the TLV.
*/
DWORD packet_get_tlv(Packet *packet, TlvType type, Tlv *tlv)
DWORD packet_get_tlv( Packet *packet, TlvType type, Tlv *tlv )
{
return packet_enum_tlv(packet, 0, type, tlv);
return packet_enum_tlv( packet, 0, type, tlv );
}
/*
* Get a TLV as a string
/*!
* @brief Get a string TLV from the packet.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get.
* @param tlv Pointer to the TLV that will receive the data.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_FOUND Unable to find the TLV or the string
* value is not NULL-terminated.
*/
DWORD packet_get_tlv_string(Packet *packet, TlvType type, Tlv *tlv)
DWORD packet_get_tlv_string( Packet *packet, TlvType type, Tlv *tlv )
{
DWORD res;
if ((res = packet_get_tlv(packet, type, tlv)) == ERROR_SUCCESS)
res = packet_is_tlv_null_terminated(packet, tlv);
if ((res = packet_get_tlv( packet, type, tlv )) == ERROR_SUCCESS)
res = packet_is_tlv_null_terminated( tlv );
return res;
}
/*
* Enumerate a TLV group (a TLV that consists other multiple sub-TLVs) and
* finds the first match of a given type, if it exists.
/*!
* @brief Get a TLV of a given type from a group TLV in the packet.
* @param packet Pointer to the packet to get the TLV from.
* @param group Pointer to the group TLV to get the value from.
* @param type Type of TLV to get.
* @param tlv Pointer to the TLV that will receive the data.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_FOUND Unable to find the TLV.
*/
DWORD packet_get_tlv_group_entry(Packet *packet, Tlv *group, TlvType type, Tlv *entry)
DWORD packet_get_tlv_group_entry( Packet *packet, Tlv *group, TlvType type, Tlv *entry )
{
return packet_find_tlv_buf( packet, group->buffer, group->header.length, 0, type, entry);
return packet_find_tlv_buf( packet, group->buffer, group->header.length, 0, type, entry );
}
/*
* Enumerate a TLV, optionally of a specified typed.
/*!
* @brief Enumerate a TLV (with the option of constraining its type).
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get (optional).
* @param tlv Pointer to the TLV that will receive the data.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_FOUND Unable to find the TLV.
*/
DWORD packet_enum_tlv(Packet *packet, DWORD index, TlvType type, Tlv *tlv)
DWORD packet_enum_tlv( Packet *packet, DWORD index, TlvType type, Tlv *tlv )
{
return packet_find_tlv_buf( packet, packet->payload, packet->payloadLength, index, type, tlv);
return packet_find_tlv_buf( packet, packet->payload, packet->payloadLength, index, type, tlv );
}
/*
* Get the value of a string TLV
/*!
* @brief Get the string value of a TLV.
* @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.
*/
PCHAR packet_get_tlv_value_string(Packet *packet, TlvType type)
PCHAR packet_get_tlv_value_string( Packet *packet, TlvType type )
{
Tlv stringTlv;
PCHAR string = NULL;
if (packet_get_tlv_string(packet, type, &stringTlv) == ERROR_SUCCESS)
if (packet_get_tlv_string( packet, type, &stringTlv ) == ERROR_SUCCESS)
string = (PCHAR)stringTlv.buffer;
return string;
}
/*
* Get the value of a UINT TLV
/*!
* @brief Get the unsigned int value of a TLV.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get (optional).
* @return The value found in the TLV.
* @todo On failure, 0 is returned. We need to make sure this is the right
* thing to do because 0 might also be a valid value.
*/
UINT packet_get_tlv_value_uint(Packet *packet, TlvType type)
UINT packet_get_tlv_value_uint( Packet *packet, TlvType type )
{
Tlv uintTlv;
if ((packet_get_tlv(packet, type, &uintTlv) != ERROR_SUCCESS) ||(uintTlv.header.length < sizeof(DWORD)))
if ((packet_get_tlv( packet, type, &uintTlv ) != ERROR_SUCCESS) || (uintTlv.header.length < sizeof(DWORD)))
return 0;
return ntohl(*(LPDWORD)uintTlv.buffer);
}
/*!
* @brief Get the raw value of a TLV.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get (optional).
* @return The value found in the TLV.
*/
BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type )
{
Tlv tlv;
@ -582,10 +717,15 @@ BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type )
return tlv.buffer;
}
/*
* Get the value of a QWORD TLV
/*!
* @brief Get the quad-word value of a TLV.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get (optional).
* @return The value found in the TLV.
* @todo On failure, 0 is returned. We need to make sure this is the right
* thing to do because 0 might also be a valid value.
*/
QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type)
QWORD packet_get_tlv_value_qword( Packet *packet, TlvType type )
{
Tlv qwordTlv;
@ -595,25 +735,38 @@ QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type)
return ntohq( *(QWORD *)qwordTlv.buffer );
}
/*
* Get the value of a bool TLV
/*!
* @brief Get the boolean value of a TLV.
* @param packet Pointer to the packet to get the TLV from.
* @param type Type of TLV to get (optional).
* @return The value found in the TLV.
* @todo On failure, FALSE is returned. We need to make sure this is the right
* thing to do because FALSE might also be a valid value.
*/
BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type)
BOOL packet_get_tlv_value_bool( Packet *packet, TlvType type )
{
Tlv boolTlv;
BOOL val = FALSE;
if (packet_get_tlv(packet, type, &boolTlv) == ERROR_SUCCESS)
if (packet_get_tlv( packet, type, &boolTlv ) == ERROR_SUCCESS)
val = (BOOL)(*(PCHAR)boolTlv.buffer);
return val;
}
/*
* Add an exception to a packet
/*!
* @brief Add an exception to a packet.
* @details When adding an exception, both a TLV_EXCEPTION_CODE and TLV_EXCEPTION_STRING
* are added to the packet.
* @param packet Pointer to the packet to add the detail to.
* @param code Exception code.
* @param fmt Form string for the exception string.
* @param ... Varargs for the format string.
* @return Indication of success or failure.
* @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the request packet.
* @retval ERROR_SUCCESS Transmission was successful.
*/
DWORD packet_add_exception(Packet *packet, DWORD code,
PCHAR fmt, ...)
DWORD packet_add_exception( Packet *packet, DWORD code, PCHAR fmt, ... )
{
DWORD codeNbo = htonl(code);
char buf[8192];
@ -636,21 +789,40 @@ DWORD packet_add_exception(Packet *packet, DWORD code,
entries[1].buffer = (PUCHAR)buf;
// Add the TLV group, or try to at least.
return packet_add_tlv_group(packet, TLV_TYPE_EXCEPTION, entries, 2);
return packet_add_tlv_group( packet, TLV_TYPE_EXCEPTION, entries, 2 );
}
/*
* Get the result code from the packet
/*!
* @brief Get the result code from the packet
* @param packet Pointer to the packet to get thget the result code from
* @return The result code.
*/
DWORD packet_get_result(Packet *packet)
DWORD packet_get_result( Packet *packet )
{
return packet_get_tlv_value_uint(packet, TLV_TYPE_RESULT);
return packet_get_tlv_value_uint( packet, TLV_TYPE_RESULT );
}
/*
* Enumerate TLV entries in a buffer until hitting a given index (optionally for a given type as well).
*/
DWORD packet_find_tlv_buf( Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index, TlvType type, Tlv *tlv)
/*!
* @brief Enumerate TLV entries until hitting a given index or type.
* @details This function will iterate through the given payload until one of the following conditions is true:
* - The end of the payload is encountered
* - The specified index is reached
* - A TLV of the specified type is reached
*
* If the first condition is met, the function returns with a failure.
* @param packet Pointer to the packet to get the TLV from.
* @param payload Pointer to the payload to parse.
* @param index Index of the TLV entry to find (optional).
* @param type Type of TLV to get (optional).
* @param tlv Pointer to the TLV that will receive the data.
* @return Indication of success or failure.
* @retval ERROR_SUCCESS The operation completed successfully.
* @retval ERROR_NOT_FOUND Unable to find the TLV.
*/
DWORD packet_find_tlv_buf( Packet *packet, PUCHAR payload, DWORD payloadLength, DWORD index, TlvType type, Tlv *tlv )
{
DWORD currentIndex = 0;
DWORD offset = 0, length = 0;
@ -759,14 +931,13 @@ DWORD packet_find_tlv_buf( Packet *packet, PUCHAR payload, DWORD payloadLength,
return (found) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
}
/***********************
* Completion Routines *
***********************/
/*
* Add a completion routine for a given request identifier
/*!
* @brief Add a completion routine for a given request identifier.
* @return Indication of success or failure.
* @retval ERROR_NOT_ENOUGH_MEMORY Unable to allocate memory for the \c PacketCompletionRouteEntry instance.
* @retval ERROR_SUCCESS Addition was successful.
*/
DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *completion)
DWORD packet_add_completion_handler( LPCSTR requestId, PacketRequestCompletion *completion )
{
PacketCompletionRoutineEntry *entry;
DWORD res = ERROR_SUCCESS;
@ -774,17 +945,17 @@ DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *c
do
{
// Allocate the entry
if (!(entry = (PacketCompletionRoutineEntry *)malloc(sizeof(PacketCompletionRoutineEntry))))
if (!(entry = (PacketCompletionRoutineEntry *)malloc( sizeof(PacketCompletionRoutineEntry) )))
{
res = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Copy the completion routine information
memcpy(&entry->handler, completion, sizeof(PacketRequestCompletion));
memcpy( &entry->handler, completion, sizeof(PacketRequestCompletion) );
// Copy the request identifier
if (!(entry->requestId = _strdup(requestId)))
if (!(entry->requestId = _strdup( requestId )))
{
res = ERROR_NOT_ENOUGH_MEMORY;
@ -803,25 +974,31 @@ DWORD packet_add_completion_handler(LPCSTR requestId, PacketRequestCompletion *c
}
/*
* Call the register completion handler(s) for the given request identifier.
*/
DWORD packet_call_completion_handlers(Remote *remote, Packet *response,LPCSTR requestId)
/*!
* @brief Call the register completion handler(s) for the given request identifier.
* @details Only those handlers that match the given request are executed.
* @param remote Pointer to the \c Remote instance for this call.
* @param response Pointer to the response \c Packet.
* @param requestId ID of the request to execute the completion handlers of.
* @return Indication of success or failure.
* @retval ERROR_NOT_FOUND Unable to find any matching completion handlers for the request.
* @retval ERROR_SUCCESS Execution was successful.
*/
DWORD packet_call_completion_handlers( Remote *remote, Packet *response, LPCSTR requestId )
{
PacketCompletionRoutineEntry *current;
DWORD result = packet_get_result(response);
DWORD result = packet_get_result( response );
DWORD matches = 0;
Tlv methodTlv;
LPCSTR method = NULL;
// Get the method associated with this packet
if (packet_get_tlv_string(response, TLV_TYPE_METHOD,
&methodTlv) == ERROR_SUCCESS)
if (packet_get_tlv_string(response, TLV_TYPE_METHOD, &methodTlv) == ERROR_SUCCESS)
method = (LPCSTR)methodTlv.buffer;
// Enumerate the completion routine list
for (current = packetCompletionRoutineList;
current;
current = current->next)
for (current = packetCompletionRoutineList; current; current = current->next)
{
// Does the request id of the completion entry match the packet's request
// id?
@ -842,10 +1019,12 @@ DWORD packet_call_completion_handlers(Remote *remote, Packet *response,LPCSTR re
return (matches > 0) ? ERROR_SUCCESS : ERROR_NOT_FOUND;
}
/*
* Remove one or more completion handlers for the given request identifier
/*!
* @brief Remove a set of completion routine handlers for a given request identifier.
* @param requestId ID of the request.
* @return \c ERROR_SUCCESS is always returned.
*/
DWORD packet_remove_completion_handler(LPCSTR requestId)
DWORD packet_remove_completion_handler( LPCSTR requestId )
{
PacketCompletionRoutineEntry *current, *next, *prev;
@ -873,10 +1052,16 @@ DWORD packet_remove_completion_handler(LPCSTR requestId)
return ERROR_SUCCESS;
}
/*
* Transmit and destroy a packet
/*!
* @brief Transmit _and_ destroy a packet.
* @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 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);
@ -887,10 +1072,15 @@ DWORD packet_transmit(Remote *remote, Packet *packet, PacketRequestCompletion *c
return 0;
}
/*
* Transmit and destroy a packet over SSL
/*!
* @brief Transmit a packet via SSL _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 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;
Tlv requestId;
@ -1006,10 +1196,14 @@ DWORD packet_transmit_via_ssl(Remote *remote, Packet *packet, PacketRequestCompl
/*
* Transmit and destroy a packet over HTTP(S)
/*!
* @brief 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.
*/
DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
DWORD packet_transmit_via_http( Remote *remote, Packet *packet, PacketRequestCompletion *completion )
{
CryptoContext *crypto;
Tlv requestId;
@ -1096,11 +1290,16 @@ DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestComp
}
/*
* Transmit and destroy a packet over HTTP(S)
*/
#ifdef _WIN32
DWORD packet_transmit_via_http_wininet(Remote *remote, Packet *packet, PacketRequestCompletion *completion) {
/*!
* @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;
@ -1157,10 +1356,14 @@ DWORD packet_transmit_via_http_wininet(Remote *remote, Packet *packet, PacketReq
#endif
/*
* Transmits a response with nothing other than a result code in it
/*!
* @brief Transmit a response with just a result code to the remote endpoint.
* @param remote Pointer to the \c Remote instance.
* @param packet Pointer to the \c Packet that is to be sent.
* @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);
@ -1174,10 +1377,13 @@ DWORD packet_transmit_empty_response(Remote *remote, Packet *packet, DWORD res)
return packet_transmit(remote, response, NULL);
}
/*
* Receive a new 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(Remote *remote, Packet **packet)
DWORD packet_receive( Remote *remote, Packet **packet )
{
DWORD headerBytes = 0, payloadBytesLeft = 0, res;
CryptoContext *crypto = NULL;
@ -1191,11 +1397,9 @@ DWORD packet_receive(Remote *remote, Packet **packet)
#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);
return packet_receive_via_http( remote, packet );
lock_acquire( remote->lock );
@ -1231,11 +1435,11 @@ DWORD packet_receive(Remote *remote, Packet **packet)
// Initialize the header
header.length = header.length;
header.type = header.type;
payloadLength = ntohl(header.length) - sizeof(TlvHeader);
payloadLength = ntohl( header.length ) - sizeof(TlvHeader);
payloadBytesLeft = payloadLength;
// Allocate the payload
if (!(payload = (PUCHAR)malloc(payloadLength)))
if (!(payload = (PUCHAR)malloc( payloadLength )))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
@ -1244,7 +1448,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( remote->ssl, payload + payloadLength - payloadBytesLeft, payloadBytesLeft )) <= 0)
{
if (GetLastError() == WSAEWOULDBLOCK)
@ -1269,7 +1473,7 @@ DWORD packet_receive(Remote *remote, Packet **packet)
break;
// Allocate a packet structure
if (!(localPacket = (Packet *)malloc(sizeof(Packet))))
if (!(localPacket = (Packet *)malloc( sizeof(Packet) )))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
@ -1279,15 +1483,15 @@ DWORD packet_receive(Remote *remote, Packet **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))
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)
if ((res = crypto->handlers.decrypt( crypto, payload, payloadLength,&payload, &payloadLength )) != ERROR_SUCCESS)
{
SetLastError(res);
break;
@ -1311,12 +1515,12 @@ DWORD packet_receive(Remote *remote, Packet **packet)
res = GetLastError();
// Cleanup on failure
if (res != ERROR_SUCCESS)
if ( res != ERROR_SUCCESS )
{
if (payload)
free(payload);
free( payload );
if (localPacket)
free(localPacket);
free( localPacket );
}
lock_release( remote->lock );
@ -1326,10 +1530,14 @@ DWORD packet_receive(Remote *remote, Packet **packet)
#ifdef _WIN32
/*
* Receive a new packet over HTTP using WinInet
/*!
* @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 not available in POSIX.
*/
DWORD packet_receive_http_via_wininet(Remote *remote, Packet **packet) {
DWORD packet_receive_http_via_wininet( Remote *remote, Packet **packet ) {
DWORD headerBytes = 0, payloadBytesLeft = 0, res;
CryptoContext *crypto = NULL;
@ -1355,7 +1563,7 @@ DWORD packet_receive_http_via_wininet(Remote *remote, Packet **packet) {
flags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
}
dprintf("[PACKET RECEIVE] HttpOpenRequest");
hReq = HttpOpenRequest(remote->hConnection, "POST", remote->uri, NULL, NULL, NULL, flags, 0);
hReq = HttpOpenRequest( remote->hConnection, "POST", remote->uri, NULL, NULL, NULL, flags, 0 );
if (hReq == NULL) {
dprintf("[PACKET RECEIVE] Failed HttpOpenRequest: %d", GetLastError());
@ -1511,11 +1719,15 @@ DWORD packet_receive_http_via_wininet(Remote *remote, Packet **packet) {
/*
* Receive a new packet over HTTP
/*!
* @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
* and doesn't yet have a POSIX implementation.
*/
DWORD packet_receive_via_http(Remote *remote, Packet **packet)
DWORD packet_receive_via_http( Remote *remote, Packet **packet )
{
#ifdef _WIN32
return packet_receive_http_via_wininet(remote, packet);

@ -53,9 +53,13 @@ typedef enum
/*! @brief Meta TLV argument type representing a flag set/mask value. */
#define TLV_META_TYPE_MASK(x) ((x) & 0xffff0000)
/*! @brief Base value for reserved TLV definitions. */
#define TLV_RESERVED 0
/*! @brief Base value for TLV definitions that are part of extensions. */
#define TLV_EXTENSIONS 20000
/*! @brief Base value for user TLV definitions. */
#define TLV_USER 40000
/*! @brief Base value for temporary TLV definitions. */
#define TLV_TEMP 60000
/*!
@ -95,7 +99,7 @@ typedef DWORD TlvMetaType;
*/
typedef enum
{
TLV_TYPE_ANY = TLV_VALUE(TLV_META_TYPE_NONE, 0),
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.
@ -125,8 +129,8 @@ 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),
TLV_TYPE_EXCEPTION_STRING = TLV_VALUE(TLV_META_TYPE_STRING, 301),
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).
@ -141,9 +145,9 @@ typedef enum
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),
TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000),
TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000),
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
@ -212,7 +216,7 @@ LINKAGE DWORD packet_add_tlv_bool(Packet *packet, TlvType type, BOOL val);
LINKAGE DWORD packet_add_tlv_group(Packet *packet, TlvType type, Tlv *entries, DWORD numEntries);
LINKAGE DWORD packet_add_tlvs(Packet *packet, Tlv *entries, DWORD numEntries);
LINKAGE DWORD packet_add_tlv_raw(Packet *packet, TlvType type, LPVOID buf, DWORD length);
LINKAGE DWORD packet_is_tlv_null_terminated(Packet *packet, Tlv *tlv);
LINKAGE DWORD packet_is_tlv_null_terminated(Tlv *tlv);
LINKAGE PacketTlvType packet_get_type(Packet *packet);
LINKAGE TlvMetaType packet_get_tlv_meta(Packet *packet, Tlv *tlv);
LINKAGE DWORD packet_get_tlv(Packet *packet, TlvType type, Tlv *tlv);
@ -267,7 +271,8 @@ LINKAGE DWORD packet_remove_completion_handler(LPCSTR requestId);
/*
* Core API
*/
LINKAGE DWORD send_core_console_write(Remote *remote, LPCSTR fmt, ...);
LINKAGE HANDLE core_update_thread_token(Remote *remote, HANDLE token);
LINKAGE DWORD send_core_console_write( Remote *remote, LPCSTR fmt, ... );
LINKAGE HANDLE core_update_thread_token( Remote *remote, HANDLE token );
LINKAGE VOID core_update_desktop( Remote * remote, DWORD dwSessionID, char * cpStationName, char * cpDesktopName );
#endif

@ -420,9 +420,8 @@ DWORD request_sys_process_thread_set_regs(Remote *remote, Packet *packet)
continue;
// Validate them
if ((packet_is_tlv_null_terminated(packet,
&nameTlv) != ERROR_SUCCESS) ||
(valueTlv.header.length < sizeof(ULONG)))
if ((packet_is_tlv_null_terminated(&nameTlv) != ERROR_SUCCESS)
|| (valueTlv.header.length < sizeof(ULONG)))
continue;
// Stash them