mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-18 07:11:12 +02:00
341 lines
7.4 KiB
C
341 lines
7.4 KiB
C
#include "precomp.h"
|
|
#include <sys/stat.h>
|
|
|
|
/***************************
|
|
* File Channel Operations *
|
|
***************************/
|
|
|
|
typedef struct
|
|
{
|
|
FILE *fd;
|
|
DWORD mode;
|
|
} FileContext;
|
|
|
|
/*
|
|
* Writes the supplied data to the file
|
|
*/
|
|
static DWORD file_channel_write(Channel *channel, Packet *request,
|
|
LPVOID context, LPVOID buffer, DWORD bufferSize,
|
|
LPDWORD bytesWritten)
|
|
{
|
|
FileContext *ctx = (FileContext *)context;
|
|
DWORD result= ERROR_SUCCESS;
|
|
LONG written = 0;
|
|
|
|
// Write a chunk
|
|
if ((written = fwrite(buffer, 1, bufferSize, ctx->fd)) <= 0)
|
|
{
|
|
written = 0;
|
|
result = GetLastError();
|
|
}
|
|
|
|
// Set bytesWritten
|
|
if (bytesWritten)
|
|
*bytesWritten = written;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Closes the file
|
|
*/
|
|
static DWORD file_channel_close(Channel *channel, Packet *request,
|
|
LPVOID context)
|
|
{
|
|
FileContext *ctx = (FileContext *)context;
|
|
|
|
fclose(ctx->fd);
|
|
free(ctx);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Reads data from the file (if any)
|
|
*/
|
|
static DWORD file_channel_read(Channel *channel, Packet *request,
|
|
LPVOID context, LPVOID buffer, DWORD bufferSize,
|
|
LPDWORD bytesRead)
|
|
{
|
|
FileContext *ctx = (FileContext *)context;
|
|
DWORD result = ERROR_SUCCESS;
|
|
LONG bytes = 0;
|
|
|
|
// Read a chunk
|
|
if ((bytes= fread(buffer, 1, bufferSize, ctx->fd)) <= 0)
|
|
{
|
|
bytes = 0;
|
|
result = GetLastError();
|
|
}
|
|
|
|
// Set bytesRead
|
|
if (bytesRead)
|
|
*bytesRead = bytes;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Checks to see if the file pointer is currently at the end of the file
|
|
*/
|
|
static DWORD file_channel_eof(Channel *channel, Packet *request,
|
|
LPVOID context, LPBOOL isEof)
|
|
{
|
|
FileContext *ctx = (FileContext *)context;
|
|
|
|
return feof(ctx->fd) ? TRUE : FALSE;
|
|
}
|
|
|
|
/*
|
|
* Changes the current file pointer position in the file
|
|
*/
|
|
static DWORD file_channel_seek(Channel *channel, Packet *request,
|
|
LPVOID context, LONG offset, DWORD whence)
|
|
{
|
|
FileContext *ctx = (FileContext *)context;
|
|
|
|
return fseek(ctx->fd, offset, whence);
|
|
}
|
|
|
|
/*
|
|
* Returns the current offset in the file to the requestor
|
|
*/
|
|
static DWORD file_channel_tell(Channel *channel, Packet *request,
|
|
LPVOID context, LPLONG offset)
|
|
{
|
|
FileContext *ctx = (FileContext *)context;
|
|
DWORD result = ERROR_SUCCESS;
|
|
LONG pos = 0;
|
|
|
|
if ((pos = ftell(ctx->fd)) < 0)
|
|
result = GetLastError();
|
|
|
|
if (offset)
|
|
*offset = pos;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Handles the open request for a file channel and returns a valid channel
|
|
* identifier to the requestor if the file is opened successfully
|
|
*/
|
|
DWORD request_fs_file_channel_open(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = NULL;
|
|
PCHAR filePath, mode;
|
|
DWORD res = ERROR_SUCCESS;
|
|
DWORD flags = 0;
|
|
Channel *newChannel = NULL;
|
|
PoolChannelOps chops = { 0 };
|
|
FileContext *ctx;
|
|
LPSTR expandedFilePath = NULL;
|
|
|
|
do
|
|
{
|
|
// Allocate a response
|
|
response = packet_create_response(packet);
|
|
|
|
// Get the channel flags
|
|
flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);
|
|
|
|
// Allocate storage for the file context
|
|
if (!(ctx = (FileContext *)malloc(sizeof(FileContext))))
|
|
{
|
|
res = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
// Get the file path and the mode
|
|
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
|
mode = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_MODE);
|
|
|
|
// No file path? bogus.
|
|
if (!filePath)
|
|
{
|
|
res = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// Expand the file path
|
|
if (!(expandedFilePath = fs_expand_path(filePath)))
|
|
{
|
|
res = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
if (!mode)
|
|
mode = "rb";
|
|
|
|
// Invalid file?
|
|
if (!(ctx->fd = fopen(expandedFilePath, mode)))
|
|
{
|
|
res = GetLastError();
|
|
break;
|
|
}
|
|
|
|
memset(&chops, 0, sizeof(chops));
|
|
|
|
// Initialize the pool operation handlers
|
|
chops.native.context = ctx;
|
|
chops.native.write = file_channel_write;
|
|
chops.native.close = file_channel_close;
|
|
chops.read = file_channel_read;
|
|
chops.eof = file_channel_eof;
|
|
chops.seek = file_channel_seek;
|
|
chops.tell = file_channel_tell;
|
|
|
|
// Check the response allocation & allocate a un-connected
|
|
// channel
|
|
if ((!response) ||
|
|
(!(newChannel = channel_create_pool(0, flags,
|
|
&chops))))
|
|
{
|
|
res = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
// Add the channel identifier to the response
|
|
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,
|
|
channel_get_id(newChannel));
|
|
|
|
} while (0);
|
|
|
|
// Transmit the packet if it's valid
|
|
packet_transmit_response(res, remote, response);
|
|
|
|
// Clean up on failure
|
|
if (res != ERROR_SUCCESS)
|
|
{
|
|
if (newChannel)
|
|
channel_destroy(newChannel, NULL);
|
|
if (ctx)
|
|
free(ctx);
|
|
}
|
|
|
|
// Free the expanded file path if it was allocated
|
|
if (expandedFilePath)
|
|
free(expandedFilePath);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* Gets information about the file path that is supplied and returns it to the
|
|
* requestor
|
|
*
|
|
* TLVs:
|
|
*
|
|
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
|
*/
|
|
DWORD request_fs_stat(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = packet_create_response(packet);
|
|
struct stat buf;
|
|
LPCSTR filePath;
|
|
LPSTR expanded = NULL;
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
|
|
|
// Validate parameters
|
|
if (!filePath)
|
|
result = ERROR_INVALID_PARAMETER;
|
|
else if (!(expanded = fs_expand_path(filePath)))
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
else
|
|
{
|
|
// Stat the file using the Microsoft stat wrapper so that we don't have to
|
|
// do translations
|
|
if (stat(expanded, &buf) < 0)
|
|
result = GetLastError();
|
|
else
|
|
packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf,
|
|
sizeof(buf));
|
|
}
|
|
|
|
// Set the result and transmit the response
|
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
|
|
|
packet_transmit(remote, response, NULL);
|
|
|
|
if (expanded)
|
|
free(expanded);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Removes the supplied file from disk
|
|
*
|
|
* TLVs:
|
|
*
|
|
* req: TLV_TYPE_FILE_PATH - The file that is to be removed.
|
|
*/
|
|
DWORD request_fs_delete_file(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = packet_create_response(packet);
|
|
LPCSTR path;
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
path = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
|
|
|
if (!path)
|
|
result = ERROR_INVALID_PARAMETER;
|
|
#ifdef _WIN32
|
|
else if (!DeleteFile(path))
|
|
#else
|
|
else if (!unlink(path))
|
|
#endif
|
|
result = GetLastError();
|
|
|
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
|
|
|
packet_transmit(remote, response, NULL);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Expands a file path and returns the expanded path to the requestor
|
|
*
|
|
* req: TLV_TYPE_FILE_PATH - The file path to expand
|
|
*/
|
|
DWORD request_fs_file_expand_path(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = packet_create_response(packet);
|
|
DWORD result = ERROR_SUCCESS;
|
|
LPSTR expanded = NULL;
|
|
LPSTR regular;
|
|
|
|
regular = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
|
|
|
do
|
|
{
|
|
// No regular path?
|
|
if (!regular)
|
|
{
|
|
result = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// Allocate storage for the expanded path
|
|
if (!(expanded = fs_expand_path(regular)))
|
|
{
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, expanded);
|
|
|
|
} while (0);
|
|
|
|
// Transmit the response to the mofo
|
|
packet_transmit_response(result, remote, response);
|
|
|
|
if (expanded)
|
|
free(expanded);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|