1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-24 18:16:24 +01:00
HD Moore 7539286182 Cleanups to the socket code, its still not perfect, but much more usable now
git-svn-id: file:///home/svn/framework3/trunk@7750 4d416f70-5f16-0410-b530-b9f4589650da
2009-12-08 14:52:07 +00:00

498 lines
13 KiB
C

#include "common.h"
// Local remote request implementors
extern DWORD remote_request_core_console_write(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_open(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_write(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_read(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_close(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_seek(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_eof(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet);
extern DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet);
extern DWORD remote_request_core_crypto_negotiate(Remote *remote, Packet *packet);
extern DWORD remote_request_core_migrate(Remote *remote, Packet *packet);
// Local remote response implementors
extern DWORD remote_response_core_console_write(Remote *remote, Packet *packet);
extern DWORD remote_response_core_channel_open(Remote *remote, Packet *packet);
extern DWORD remote_response_core_channel_close(Remote *remote, Packet *packet);
DWORD remote_request_core_console_write(Remote *remote, Packet *packet)
{
return ERROR_SUCCESS;
}
DWORD remote_response_core_console_write(Remote *remote, Packet *packet)
{
return ERROR_SUCCESS;
}
/*
* Base RPC dispatch table
*/
Command commands[] =
{
/*
* Core commands
*/
// Console commands
{ "core_console_write",
{ remote_request_core_console_write, { TLV_META_TYPE_STRING }, 1 | ARGUMENT_FLAG_REPEAT },
{ remote_response_core_console_write, { 0 }, 0 },
},
// Native Channel commands
{ "core_channel_open",
{ remote_request_core_channel_open, { 0 }, 0 },
{ remote_response_core_channel_open, { 0 }, 0 },
},
{ "core_channel_write",
{ remote_request_core_channel_write, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "core_channel_close",
{ remote_request_core_channel_close, { 0 }, 0 },
{ remote_response_core_channel_close, { 0 }, 0 },
},
// Buffered/Pool channel commands
{ "core_channel_read",
{ remote_request_core_channel_read, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Pool channel commands
{ "core_channel_seek",
{ remote_request_core_channel_seek, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "core_channel_eof",
{ remote_request_core_channel_eof, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
{ "core_channel_tell",
{ remote_request_core_channel_tell, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Soon to be deprecated
{ "core_channel_interact",
{ remote_request_core_channel_interact, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Crypto
{ "core_crypto_negotiate",
{ remote_request_core_crypto_negotiate, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Migration
{ "core_migrate",
{ remote_request_core_migrate, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Terminator
{ NULL,
{ NULL, { 0 }, 0 },
{ NULL, { 0 }, 0 },
},
};
// Dynamically registered command extensions
Command *extensionList = NULL;
/*
* Dynamically register a custom command handler
*/
DWORD command_register(Command *command)
{
Command *newCommand;
if (!(newCommand = (Command *)malloc(sizeof(Command))))
return ERROR_NOT_ENOUGH_MEMORY;
memcpy(newCommand, command, sizeof(Command));
if (extensionList)
extensionList->prev = newCommand;
newCommand->next = extensionList;
newCommand->prev = NULL;
extensionList = newCommand;
return ERROR_SUCCESS;
}
/*
* Dynamically deregister a custom command handler
*/
DWORD command_deregister(Command *command)
{
Command *current, *prev;
DWORD res = ERROR_NOT_FOUND;
// Search the extension list for the command
for (current = extensionList, prev = NULL;
current;
prev = current, current = current->next)
{
if (strcmp(command->method, current->method))
continue;
if (prev)
prev->next = current->next;
else
extensionList = current->next;
if (current->next)
current->next->prev = prev;
// Deallocate it
free(current);
res = ERROR_SUCCESS;
break;
}
return res;
}
/*
* A list of all command threads currenlty executing.
*/
LIST * commandThreadList = NULL;
/*
* Block untill all running command threads have finished.
*/
VOID command_join_threads( VOID )
{
while( list_count( commandThreadList ) > 0 )
{
THREAD * thread = (THREAD *)list_get( commandThreadList, 0 );
if( thread )
thread_join( thread );
}
}
/*
* Crude method of throttling the ammount of concurrent command
* threads we allow in the system at a given time.
*/
/*
VOID command_throtle( int maxthreads )
{
while( list_count( commandThreadList ) >= maxthreads )
{
Sleep( 250 );
}
}
*/
/*
* Process a single command in a seperate thread of execution.
*/
DWORD THREADCALL command_process_thread( THREAD * thread )
{
DWORD index = 0;
DWORD result = ERROR_SUCCESS;
Tlv methodTlv = {0};
Tlv requestIdTlv = {0};
PCHAR method = NULL;
PCHAR requestId = NULL;
Command * current = NULL;
Remote * remote = NULL;
Packet * packet = NULL;
if( thread == NULL )
return ERROR_INVALID_HANDLE;
remote = (Remote *)thread->parameter1;
if( remote == NULL )
return ERROR_INVALID_HANDLE;
packet = (Packet *)thread->parameter2;
if( packet == NULL )
return ERROR_INVALID_DATA;
if( commandThreadList == NULL )
{
commandThreadList = list_create();
if( commandThreadList == NULL )
return ERROR_INVALID_HANDLE;
}
list_add( commandThreadList, thread );
__try
{
do
{
// Extract the method
result = packet_get_tlv_string( packet, TLV_TYPE_METHOD, &methodTlv );
if( result != ERROR_SUCCESS )
break;
dprintf( "[COMMAND] Processing method %s", methodTlv.buffer );
// Get the request identifier if the packet has one.
result = packet_get_tlv_string( packet, TLV_TYPE_REQUEST_ID, &requestIdTlv );
if( result == ERROR_SUCCESS )
requestId = (PCHAR)requestIdTlv.buffer;
method = (PCHAR)methodTlv.buffer;
result = ERROR_NOT_FOUND;
// Try to find a match in the dispatch type
for( index = 0, result = ERROR_NOT_FOUND ; result == ERROR_NOT_FOUND && commands[index].method ; index++ )
{
if( strcmp( commands[index].method, method ) )
continue;
// Call the base handler
result = command_call_dispatch( &commands[index], remote, packet );
}
// Regardless of error code, try to see if someone has overriden a base handler
for( current = extensionList, result = ERROR_NOT_FOUND ;
result == ERROR_NOT_FOUND && current && current->method ; current = current->next )
{
if( strcmp( current->method, method ) )
continue;
// Call the custom handler
result = command_call_dispatch( current, remote, packet );
}
dprintf("[COMMAND] Calling completion handlers...");
// Finally, call completion routines for the provided identifier
if( ((packet_get_type(packet) == PACKET_TLV_TYPE_RESPONSE) || (packet_get_type(packet) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && (requestId))
packet_call_completion_handlers( remote, packet, requestId );
// If we get here, we're successful.
result = ERROR_SUCCESS;
} while( 0 );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
dprintf("[COMMAND] Exception hit in command thread 0x%08X!", thread );
}
packet_destroy( packet );
if( list_remove( commandThreadList, thread ) )
thread_destroy( thread );
return ERROR_SUCCESS;
}
/*
* Process a single command
*/
/*
DWORD command_process_remote(Remote *remote, Packet *inPacket)
{
DWORD res = ERROR_SUCCESS, index;
Tlv methodTlv, requestIdTlv;
Packet *localPacket = NULL;
PCHAR method, requestId = NULL;
Command *current;
do
{
// If no packet was providied, try to receive one.
if (!inPacket)
{
if ((res = packet_receive(remote, &localPacket)) != ERROR_SUCCESS)
break;
else
inPacket = localPacket;
}
// Extract the method
if ((packet_get_tlv_string(inPacket, TLV_TYPE_METHOD, &methodTlv)
!= ERROR_SUCCESS))
break;
dprintf("Processing method %s", methodTlv.buffer);
// Get the request identifier if the packet has one.
if (packet_get_tlv_string(inPacket, TLV_TYPE_REQUEST_ID,
&requestIdTlv) == ERROR_SUCCESS)
requestId = (PCHAR)requestIdTlv.buffer;
method = (PCHAR)methodTlv.buffer;
res = ERROR_NOT_FOUND;
// Try to find a match in the dispatch type
for (index = 0, res = ERROR_NOT_FOUND;
res = ERROR_NOT_FOUND && commands[index].method;
index++)
{
if (strcmp(commands[index].method, method))
continue;
// Call the base handler
res = command_call_dispatch(&commands[index], remote, inPacket);
}
// Regardless of error code, try to see if someone has overriden
// a base handler
for (current = extensionList, res = ERROR_NOT_FOUND;
res == ERROR_NOT_FOUND && current && current->method;
current = current->next)
{
if (strcmp(current->method, method))
continue;
// Call the custom handler
res = command_call_dispatch(current, remote, inPacket);
}
dprintf("Calling completion handlers...");
// Finally, call completion routines for the provided identifier
if (((packet_get_type(inPacket) == PACKET_TLV_TYPE_RESPONSE) ||
(packet_get_type(inPacket) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) &&
(requestId))
packet_call_completion_handlers(remote, inPacket, requestId);
// If we get here, we're successful.
res = ERROR_SUCCESS;
} while (0);
if (localPacket)
packet_destroy(localPacket);
return res;
}*/
/*
* Process incoming commands, calling dispatch tables appropriately
*/
/*
DWORD command_process_remote_loop(Remote *remote)
{
DWORD res = ERROR_SUCCESS;
Packet *packet;
while ((res = packet_receive(remote, &packet)) == ERROR_SUCCESS)
{
res = command_process_remote(remote, packet);
// Destroy the packet
packet_destroy(packet);
// If a command returned exit, we shall return.
if (res == ERROR_INSTALL_USEREXIT)
break;
}
return res;
}
*/
/*
* Call the dispatch routine for a given command
*/
DWORD command_call_dispatch(Command *command, Remote *remote, Packet *packet)
{
DWORD res;
// Validate the arguments, if requested. Always make sure argument
// lengths are sane.
if ((res = command_validate_arguments(command, packet)) != ERROR_SUCCESS)
return res;
switch (packet_get_type(packet))
{
case PACKET_TLV_TYPE_REQUEST:
case PACKET_TLV_TYPE_PLAIN_REQUEST:
if (command->request.handler)
res = command->request.handler(remote, packet);
break;
case PACKET_TLV_TYPE_RESPONSE:
case PACKET_TLV_TYPE_PLAIN_RESPONSE:
if (command->response.handler)
res = command->response.handler(remote, packet);
break;
default:
res = ERROR_NOT_FOUND;
break;
}
return res;
}
/*
* Validate command arguments
*/
DWORD command_validate_arguments(Command *command, Packet *packet)
{
PacketDispatcher *dispatcher = NULL;
PacketTlvType type = packet_get_type(packet);
DWORD res = ERROR_SUCCESS,
packetIndex, commandIndex;
Tlv current;
// Select the dispatcher table
if ((type == PACKET_TLV_TYPE_RESPONSE) ||
(type == PACKET_TLV_TYPE_PLAIN_RESPONSE))
dispatcher = &command->response;
else
dispatcher = &command->request;
// Enumerate the arguments, validating the meta types of each
for (commandIndex = 0, packetIndex = 0;
((packet_enum_tlv(packet, packetIndex, TLV_TYPE_ANY, &current)
== ERROR_SUCCESS) &&
(res == ERROR_SUCCESS));
commandIndex++, packetIndex++)
{
TlvMetaType tlvMetaType;
// Check to see if we've reached the end of the command arguments
if ((dispatcher->numArgumentTypes) &&
(commandIndex == (dispatcher->numArgumentTypes & ARGUMENT_FLAG_MASK)))
{
// If the repeat flag is set, reset the index
if (commandIndex & ARGUMENT_FLAG_REPEAT)
commandIndex = 0;
else
break;
}
// Make sure the argument is at least one of the meta types
tlvMetaType = packet_get_tlv_meta(packet, &current);
// Validate argument meta types
switch (tlvMetaType)
{
case TLV_META_TYPE_STRING:
if (packet_is_tlv_null_terminated(packet, &current) != ERROR_SUCCESS)
res = ERROR_INVALID_PARAMETER;
break;
default:
break;
}
if ((res != ERROR_SUCCESS) &&
(commandIndex < dispatcher->numArgumentTypes))
break;
}
return res;
}