mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-08 14:36:22 +01:00
717 lines
16 KiB
C
717 lines
16 KiB
C
#include "metcli.h"
|
|
|
|
extern ConsoleCommand consoleCommands[];
|
|
extern ConsoleCommand *extendedCommandsHead;
|
|
|
|
/*****************
|
|
* Command: help *
|
|
*****************/
|
|
|
|
VOID cmd_help_output_command(ConsoleCommand *command)
|
|
{
|
|
if (command->separator)
|
|
console_write_output(
|
|
"\n%13s %s\n"
|
|
" ------------ ---------------\n",
|
|
command->name, command->help);
|
|
else
|
|
console_write_output("%13s %s\n", command->name,
|
|
command->help);
|
|
}
|
|
|
|
/*
|
|
* Print the help banner
|
|
*/
|
|
DWORD cmd_help(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
ConsoleCommand *current;
|
|
DWORD index;
|
|
|
|
for (index = 0;
|
|
consoleCommands[index].name;
|
|
index++)
|
|
cmd_help_output_command(&consoleCommands[index]);
|
|
|
|
for (current = extendedCommandsHead;
|
|
current;
|
|
current = current->next)
|
|
cmd_help_output_command(current);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*****************
|
|
* Command: open *
|
|
*****************/
|
|
|
|
/*
|
|
* Opens a logical channel with the remote endpoint that is not tied to
|
|
* a stream
|
|
*/
|
|
DWORD cmd_open(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
DWORD res;
|
|
|
|
if ((res = channel_open(remote, NULL, 0, NULL)) == ERROR_SUCCESS)
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " CHANNEL: Requesting a new channel...\n");
|
|
else
|
|
console_write_output(
|
|
"Error: channel_open failed, result %lu.\n", res);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*****************
|
|
* Command: read *
|
|
*****************/
|
|
|
|
/*
|
|
* Channel completion routine for reading from a channel
|
|
*/
|
|
DWORD cmd_read_channel_complete(Remote *remote, Channel *channel,
|
|
LPVOID context, DWORD result, PUCHAR buffer, ULONG bytesRead)
|
|
{
|
|
if (result == ERROR_SUCCESS && bytesRead > 0)
|
|
{
|
|
PCHAR tmp = (PCHAR)malloc(bytesRead + 1);
|
|
|
|
if (tmp)
|
|
{
|
|
// Copy the buffer into tmp and null terminate it
|
|
memcpy(tmp, buffer, bytesRead);
|
|
tmp[bytesRead] = 0;
|
|
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: read %lu bytes from channel %lu:\n"
|
|
"%s"
|
|
"\n",
|
|
bytesRead, channel_get_id(channel), tmp);
|
|
|
|
free(tmp);
|
|
}
|
|
else
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: read %lu bytes, local allocation failed.\n",
|
|
bytesRead);
|
|
}
|
|
else if (result != ERROR_SUCCESS)
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: cmd_read failed, result %lu.\n", result);
|
|
|
|
console_write_prompt();
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Reads in data from the remote endpoint of a channel
|
|
*/
|
|
DWORD cmd_read(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
ChannelCompletionRoutine complete;
|
|
DWORD channelId = 0, length = 4096;
|
|
DWORD res = ERROR_SUCCESS;
|
|
Channel *channel;
|
|
|
|
do
|
|
{
|
|
// Check to see if the supplied channel identifier is valid
|
|
if (argc == 1)
|
|
{
|
|
console_write_output("Usage: read channel_id [length]\n");
|
|
res = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
channelId = strtoul(argv[1], NULL, 10);
|
|
|
|
// If a length was provided, use it.
|
|
if (argc > 2)
|
|
length = strtoul(argv[2], NULL, 10);
|
|
|
|
if (!(channel = channel_find_by_id(channelId)))
|
|
{
|
|
console_write_output("Error: Could not locate channel %lu.\n",
|
|
channelId);
|
|
break;
|
|
}
|
|
|
|
// Initialize the completion routine
|
|
memset(&complete, 0, sizeof(complete));
|
|
|
|
complete.routine.read = cmd_read_channel_complete;
|
|
|
|
// Read the data in.
|
|
if ((res = channel_read(channel, remote, NULL, 0, length,
|
|
&complete))
|
|
== ERROR_SUCCESS)
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " CHANNEL: Requesting %lu bytes from channel %lu...\n",
|
|
length, channelId);
|
|
else
|
|
console_write_output("Error: channel_read failed, result %lu.\n", res);
|
|
|
|
} while (0);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/******************
|
|
* Command: write *
|
|
******************/
|
|
|
|
/*
|
|
* Completion routine for a previous write
|
|
*/
|
|
DWORD cmd_write_channel_complete(Remote *remote, Channel *channel,
|
|
LPVOID context, DWORD result, ULONG bytesWritten)
|
|
{
|
|
if (result == ERROR_SUCCESS)
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: Wrote %lu bytes to channel %lu.\n",
|
|
bytesWritten, channel_get_id(channel));
|
|
else
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: write failed, result %lu.\n",
|
|
result);
|
|
|
|
console_write_prompt();
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Writes the supplied text to the remote end of the channel
|
|
*/
|
|
DWORD cmd_write(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
ChannelCompletionRoutine complete;
|
|
DWORD channelId = 0;
|
|
DWORD res = ERROR_SUCCESS;
|
|
Channel *channel;
|
|
DWORD length = 0;
|
|
LONG bytesRead;
|
|
PCHAR buffer = NULL;
|
|
CHAR chunk[2048];
|
|
|
|
chunk[sizeof(chunk) - 1] = 0;
|
|
|
|
do
|
|
{
|
|
// Check to see if the supplied channel identifier is valid
|
|
if (argc < 2)
|
|
{
|
|
console_write_output("Usage: write channel_id\n");
|
|
res = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
channelId = strtoul(argv[1], NULL, 10);
|
|
|
|
if (!(channel = channel_find_by_id(channelId)))
|
|
{
|
|
console_write_output("Error: Could not locate channel %lu.\n",
|
|
channelId);
|
|
break;
|
|
}
|
|
|
|
console_write_output("Enter text, terminate with single-line '.':\n");
|
|
|
|
/*
|
|
* XXX: needs to not use stdin for non-cmd input
|
|
*/
|
|
while (fgets(chunk, sizeof(chunk) - 1, stdin))
|
|
{
|
|
PCHAR newBuffer;
|
|
|
|
if (chunk[0] == '.')
|
|
break;
|
|
|
|
bytesRead = strlen(chunk);
|
|
|
|
if (!buffer)
|
|
newBuffer = (PCHAR)malloc(bytesRead);
|
|
else
|
|
newBuffer = (PCHAR)realloc(buffer, length + bytesRead);
|
|
|
|
if (!newBuffer)
|
|
{
|
|
if (buffer)
|
|
free(buffer);
|
|
|
|
buffer = NULL;
|
|
|
|
break;
|
|
}
|
|
|
|
memcpy(newBuffer + length, chunk, bytesRead);
|
|
|
|
buffer = newBuffer;
|
|
length += bytesRead;
|
|
}
|
|
|
|
if (!buffer)
|
|
{
|
|
console_write_output(
|
|
"Error: No text was provided.\n");
|
|
break;
|
|
}
|
|
|
|
// Initialize the completion routine
|
|
memset(&complete, 0, sizeof(complete));
|
|
|
|
complete.routine.write = cmd_write_channel_complete;
|
|
|
|
// Read the data in.
|
|
if ((res = channel_write(channel, remote, NULL, 0, buffer,
|
|
length, &complete))
|
|
== ERROR_SUCCESS)
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " CHANNEL: Writing %lu bytes to channel %lu...\n",
|
|
length, channelId);
|
|
else
|
|
console_write_output("Error: channel_write failed, result %lu.\n", res);
|
|
|
|
free(buffer);
|
|
|
|
} while (0);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/******************
|
|
* Command: close *
|
|
******************/
|
|
|
|
/*
|
|
* Closes a channel that was allocated with the remote endpoint
|
|
*/
|
|
DWORD cmd_close(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
DWORD res = ERROR_SUCCESS;
|
|
DWORD channelId;
|
|
Channel *channel;
|
|
|
|
do
|
|
{
|
|
if (argc == 1)
|
|
{
|
|
console_write_output(
|
|
"Usage: close channel_id\n");
|
|
res = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
channelId = strtoul(argv[1], NULL, 10);
|
|
|
|
// Find the channel
|
|
if (!(channel = channel_find_by_id(channelId)))
|
|
{
|
|
console_write_output("Error: Could not locate channel id %lu.\n",
|
|
channelId);
|
|
|
|
res = ERROR_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
if ((res = channel_close(channel, remote, NULL, 0, NULL))
|
|
== ERROR_SUCCESS)
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " CHANNEL: Closing channel %lu...\n", channelId);
|
|
else
|
|
console_write_output("Error: channel_close failed, result %lu.\n",
|
|
res);
|
|
|
|
} while (0);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*********************
|
|
* Command: interact *
|
|
*********************/
|
|
|
|
/*
|
|
* Completion routine for when interact responds
|
|
*/
|
|
DWORD cmd_interact_complete(Remote *remote, Channel *channel,
|
|
LPVOID context, DWORD result)
|
|
{
|
|
if (result == ERROR_SUCCESS)
|
|
{
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: Started interactive with channel %lu..\n\n",
|
|
channel_get_id(channel));
|
|
|
|
console_set_interactive_channel(remote, channel);
|
|
}
|
|
else
|
|
{
|
|
console_write_output(
|
|
"\n"
|
|
INBOUND_PREFIX " CHANNEL: Failed to interact with channel %lu, result %lu.\n",
|
|
channel_get_id(channel));
|
|
|
|
console_write_prompt();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Switches to interactive mode with a a provided channel
|
|
*/
|
|
DWORD cmd_interact(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
ChannelCompletionRoutine complete;
|
|
DWORD res = ERROR_SUCCESS;
|
|
Channel *channel;
|
|
|
|
do
|
|
{
|
|
if (argc == 1)
|
|
{
|
|
console_write_output(
|
|
"Usage: interact channel_id\n");
|
|
res = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// Try to find the channel context from the supplied identifier
|
|
if (!(channel = channel_find_by_id(strtoul(argv[1], NULL, 10))))
|
|
{
|
|
console_write_output(
|
|
"Error: The channel identifier %s could not be found.\n",
|
|
argv[1]);
|
|
res = ERROR_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " CHANNEL: Switching to interactive console on %lu.\n",
|
|
channel_get_id(channel));
|
|
|
|
// Initialize the completion routine
|
|
memset(&complete, 0, sizeof(complete));
|
|
|
|
complete.routine.interact = cmd_interact_complete;
|
|
|
|
// Interact with the channel
|
|
res = channel_interact(channel, remote, NULL, 0, TRUE,
|
|
&complete);
|
|
|
|
} while (0);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*****************
|
|
* Command: exit *
|
|
*****************/
|
|
|
|
/*
|
|
* Exit the client
|
|
*/
|
|
DWORD cmd_exit(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
exit(0);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/********************
|
|
* Command: loadlib *
|
|
********************/
|
|
|
|
/*
|
|
* Load library completion routine
|
|
*/
|
|
DWORD cmd_loadlib_complete(Remote *remote, Packet *packet, LPVOID context,
|
|
LPCSTR method, DWORD res)
|
|
{
|
|
return console_generic_response_output(remote, packet, "PROCESS", "loadlib");
|
|
}
|
|
|
|
/*
|
|
* Loads a library into the context of the remote process
|
|
*/
|
|
DWORD cmd_loadlib(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
PCHAR libraryPath = NULL, targetPath = NULL;
|
|
PacketRequestCompletion complete;
|
|
Packet *request = NULL;
|
|
BOOL printBanner = FALSE;
|
|
DWORD res = ERROR_SUCCESS;
|
|
ArgumentContext arg;
|
|
DWORD flags = 0;
|
|
|
|
// Zero the argument context
|
|
memset(&arg, 0, sizeof(arg));
|
|
|
|
do
|
|
{
|
|
// No arguments?
|
|
if (argc == 1)
|
|
{
|
|
printBanner = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Default to being a local (to the remote machine) library
|
|
flags |= LOAD_LIBRARY_FLAG_LOCAL;
|
|
|
|
// Parse the supplied arguments
|
|
while (args_parse(argc, argv, "f:t:lde", &arg) == ERROR_SUCCESS)
|
|
{
|
|
switch (arg.toggle)
|
|
{
|
|
case 'f':
|
|
libraryPath = arg.argument;
|
|
break;
|
|
case 't':
|
|
targetPath = arg.argument;
|
|
break;
|
|
case 'l':
|
|
// Unset the local library flag
|
|
flags &= ~(LOAD_LIBRARY_FLAG_LOCAL);
|
|
break;
|
|
case 'd':
|
|
flags |= LOAD_LIBRARY_FLAG_ON_DISK;
|
|
break;
|
|
case 'e':
|
|
flags |= LOAD_LIBRARY_FLAG_EXTENSION;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!targetPath)
|
|
targetPath = libraryPath;
|
|
|
|
// Make sure that a library was supplied
|
|
if (!libraryPath)
|
|
{
|
|
console_write_output(
|
|
"Error: No library path was specified.\n");
|
|
break;
|
|
}
|
|
|
|
// Allocate the request packet
|
|
if (!(request = packet_create(PACKET_TLV_TYPE_REQUEST,
|
|
"core_loadlib")))
|
|
{
|
|
console_write_output(
|
|
"Error: Packet allocation failure.\n");
|
|
break;
|
|
}
|
|
|
|
// If the library is not local to the remote machine, parse the local
|
|
// copy into a data buffer to be transmitted to the remote host
|
|
if (!(flags & LOAD_LIBRARY_FLAG_LOCAL))
|
|
{
|
|
PUCHAR buffer;
|
|
ULONG length;
|
|
|
|
// Store the contents of the specified file in a buffer
|
|
if ((res = buffer_from_file(libraryPath, &buffer, &length))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
console_write_output(
|
|
"Error: The local file could not be parsed, result %lu.\n",
|
|
res);
|
|
break;
|
|
}
|
|
|
|
// Add the file's contents as a data tlv
|
|
packet_add_tlv_raw(request, TLV_TYPE_DATA, buffer,
|
|
length);
|
|
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " PROCESS: Uploading local library '%s', %lu bytes.\n",
|
|
libraryPath, length);
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
// Add the library path name & flags
|
|
packet_add_tlv_string(request, TLV_TYPE_LIBRARY_PATH,
|
|
libraryPath);
|
|
packet_add_tlv_uint(request, TLV_TYPE_FLAGS,
|
|
flags);
|
|
|
|
if (targetPath)
|
|
packet_add_tlv_string(request, TLV_TYPE_TARGET_PATH,
|
|
targetPath);
|
|
|
|
console_write_output(
|
|
OUTBOUND_PREFIX " PROCESS: Loading library from '%s' on remote machine.\n",
|
|
targetPath ? targetPath : libraryPath);
|
|
|
|
// Initialize the completion routine
|
|
memset(&complete, 0, sizeof(complete));
|
|
|
|
complete.routine = cmd_loadlib_complete;
|
|
|
|
// Transmit the request
|
|
res = packet_transmit(remote, request, &complete);
|
|
|
|
} while (0);
|
|
|
|
if (printBanner)
|
|
{
|
|
console_write_output(
|
|
"Usage: loadlib -f library [ -t target ] [ -lde ]\n\n"
|
|
" -f <file> The path to the library to load, whether local or remote.\n"
|
|
" -t <targ> The target file on the remote machine in which to store the library when uploading.\n"
|
|
" -l The library is local to the client machine, upload it to the remote machine.\n"
|
|
" -d When used with -l, this parameter indicates that the library should be saved to disk.\n"
|
|
" -e The library being loaded is a feature extension module, call its Init routine on load.\n");
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/****************
|
|
* Command: use *
|
|
****************/
|
|
|
|
/*
|
|
* Use a feature module implementation, installing it both locally and remotely
|
|
*/
|
|
DWORD cmd_use(Remote *remote, UINT argc, CHAR **argv)
|
|
{
|
|
LPCSTR module = NULL, path = NULL;
|
|
PCHAR currentModule = NULL, comma;
|
|
BOOL printBanner = FALSE;
|
|
DWORD res = ERROR_SUCCESS;
|
|
CHAR clientLibraryPath[1024];
|
|
CHAR serverLibraryPath[1024];
|
|
BOOL diskOnly = FALSE;
|
|
ArgumentContext arg;
|
|
CHAR *loadlibArgv[6];
|
|
DWORD loadlibArgc = 0;
|
|
|
|
clientLibraryPath[sizeof(clientLibraryPath) - 1] = 0;
|
|
serverLibraryPath[sizeof(serverLibraryPath) - 1] = 0;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
|
|
do
|
|
{
|
|
// No arguments?
|
|
if (argc == 1)
|
|
{
|
|
printBanner = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Parse the supplied arguments
|
|
while (args_parse(argc, argv, "m:p:d", &arg) == ERROR_SUCCESS)
|
|
{
|
|
switch (arg.toggle)
|
|
{
|
|
case 'm':
|
|
module = arg.argument;
|
|
break;
|
|
case 'p':
|
|
path = arg.argument;
|
|
break;
|
|
case 'd':
|
|
diskOnly = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// No module?
|
|
if (!module)
|
|
{
|
|
printBanner = TRUE;
|
|
break;
|
|
}
|
|
|
|
currentModule = (PCHAR)module;
|
|
|
|
// Enumerate through the comma delimited module list
|
|
while (currentModule)
|
|
{
|
|
comma = strchr(currentModule, ',');
|
|
|
|
if (comma)
|
|
*comma = 0;
|
|
|
|
// Populate the client and server path buffers
|
|
_snprintf_s(clientLibraryPath, sizeof(clientLibraryPath), sizeof(clientLibraryPath) - 1,
|
|
"%s%sext_client_%s.dll",
|
|
(path) ? path : "",
|
|
(path) ? "\\" : "",
|
|
currentModule);
|
|
_snprintf_s(serverLibraryPath, sizeof(clientLibraryPath), sizeof(clientLibraryPath) - 1,
|
|
"%s%sext_server_%s.dll",
|
|
(path) ? path : "",
|
|
(path) ? "\\" : "",
|
|
currentModule);
|
|
|
|
// Try to load the client library
|
|
if ((res = module_load_client(remote, currentModule, clientLibraryPath))
|
|
!= ERROR_SUCCESS)
|
|
break;
|
|
|
|
console_write_output("Successfully loaded '%s' on the client.\n", currentModule);
|
|
|
|
loadlibArgc = 0;
|
|
|
|
loadlibArgv[loadlibArgc++] = "loadlib";
|
|
|
|
// Now load the library on the remote machine
|
|
if (diskOnly)
|
|
{
|
|
// loadlib -f server_mod_path -e
|
|
loadlibArgv[loadlibArgc++] = "-f";
|
|
loadlibArgv[loadlibArgc++] = serverLibraryPath;
|
|
loadlibArgv[loadlibArgc++] = "-e";
|
|
}
|
|
else
|
|
{
|
|
// loadlib -f server_mod_path -l -e
|
|
loadlibArgv[loadlibArgc++] = "-f";
|
|
loadlibArgv[loadlibArgc++] = serverLibraryPath;
|
|
loadlibArgv[loadlibArgc++] = "-l";
|
|
loadlibArgv[loadlibArgc++] = "-e";
|
|
}
|
|
|
|
// Call the load library command
|
|
res = cmd_loadlib(remote, loadlibArgc, loadlibArgv);
|
|
|
|
if (comma)
|
|
{
|
|
*comma = ',';
|
|
currentModule = comma + 1;
|
|
}
|
|
else
|
|
currentModule = NULL;
|
|
}
|
|
|
|
} while (0);
|
|
|
|
if (printBanner)
|
|
{
|
|
console_write_output(
|
|
"Usage: use -m module1,module2,module3 [ -p path ] [ -d ]\n\n"
|
|
" -m <mod> The names of one or more module(s) to load (e.g. 'net').\n"
|
|
" -p <path> The path to load the module(s) from locally.\n"
|
|
" -d Load the library from disk, do not upload.\n");
|
|
}
|
|
|
|
return res;
|
|
}
|