Skip to content

Commit

Permalink
Merge pull request #701 from smashery/new_cmd_exec
Browse files Browse the repository at this point in the history
New process launch API
  • Loading branch information
adfoster-r7 authored Oct 10, 2024
2 parents 99a5bb0 + 64bd2f1 commit 80d73d4
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 118 deletions.
200 changes: 171 additions & 29 deletions c/meterpreter/source/extensions/stdapi/server/sys/process/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,167 @@ DWORD request_sys_process_close(Remote *remote, Packet *packet)
return ERROR_SUCCESS;
}

BOOL needs_quoting(PCHAR str)
{
// Initial value is to need quoting, in case it's an empty arg
BOOL bNeedsQuoting = TRUE;
char* pArgIndex = str;
// Check whether we'll need to quote the argument
while (*pArgIndex != '\0')
{
// The arg is not empty
bNeedsQuoting = FALSE;
if (*pArgIndex == '\v' || *pArgIndex == ' ' || *pArgIndex == '\t')
{
bNeedsQuoting = TRUE;
break;
}
++pArgIndex;
}

return bNeedsQuoting;
}

DWORD get_commandline(Packet *packet, DWORD flags, PCHAR* commandLine)
{
// Check new-style arguments first
DWORD dwTlvIndex = 0;
Tlv argTlv;
char* pArgStart;
char* pArgIndex;
BOOL bNeedsQuoting;
size_t commandLineLength = 0;
size_t commandLineWriteIndex = 0;
PCHAR path, arguments = NULL;
DWORD backslashCount;

if (flags & PROCESS_EXECUTE_FLAG_ARG_ARRAY)
{
path = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_UNESCAPED_PATH);
// Calculate the potential size of our command line.
// The path may need quoting, so two extra chars there, plus null terminator.
commandLineLength = strlen(path) + 3;

// Now look at arguments
while (ERROR_SUCCESS == met_api->packet.enum_tlv(packet, dwTlvIndex++, TLV_TYPE_PROCESS_ARGUMENT, &argTlv))
{
commandLineLength += strlen((char*)argTlv.buffer);
commandLineLength += 3; // Two quotes bookending it, plus a space between the arguments
}

// In the worst case, we've got a lot of backslashes just before a quote character, which will need to double in size.
// So, allocate for the worst-case expansion.
commandLineLength *= 2;

if (!(*commandLine = (PCHAR)malloc(commandLineLength)))
{
return ERROR_NOT_ENOUGH_MEMORY;
}

// Append the path to the command line, possibly quoting, but no escaping
bNeedsQuoting = needs_quoting(path);
if (bNeedsQuoting)
{
(*commandLine)[commandLineWriteIndex++] = '"';
}

strncpy_s((*commandLine) + commandLineWriteIndex, commandLineLength - commandLineWriteIndex, path, strlen(path));
commandLineWriteIndex += strlen(path);
if (bNeedsQuoting)
{
(*commandLine)[commandLineWriteIndex++] = '"';
}

dwTlvIndex = 0;
while (ERROR_SUCCESS == met_api->packet.enum_tlv(packet, dwTlvIndex++, TLV_TYPE_PROCESS_ARGUMENT, &argTlv))
{
if (dwTlvIndex != 0)
{
// Add a space between arguments
(*commandLine)[commandLineWriteIndex++] = ' ';
}

pArgStart = (char*)argTlv.buffer;
bNeedsQuoting = needs_quoting(pArgStart);

// Now build up the command line
pArgIndex = pArgStart;
backslashCount = 0;
if (bNeedsQuoting)
{
(*commandLine)[commandLineWriteIndex++] = '"';
}

while (*pArgIndex != '\0')
{
if (*pArgIndex == '\\')
{
++backslashCount;
}
else
{
if (*pArgIndex == '"')
{
// We've encountered a double quote - if there are any backslashes immediately preceding, double them
for (DWORD i = 0; i < backslashCount; ++i)
{
(*commandLine)[commandLineWriteIndex++] = '\\';
}
// Now actually escape the double-quote
(*commandLine)[commandLineWriteIndex++] = '\\';
}

backslashCount = 0;
}
// Now write out whatever the character was
(*commandLine)[commandLineWriteIndex++] = *pArgIndex;

++pArgIndex;
}
if (bNeedsQuoting)
{
// We're about to add another quote - check for backslash doubling again
for (DWORD i = 0; i < backslashCount; ++i)
{
(*commandLine)[commandLineWriteIndex++] = '\\';
}
(*commandLine)[commandLineWriteIndex++] = '"';

}
}
(*commandLine)[commandLineWriteIndex++] = '\0';
dprintf("[PROCESS] Created command line: %s", *commandLine);
}
else
{
path = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH);
arguments = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS);
// If the remote endpoint provided arguments, combine them with the
// executable to produce a command line
if (path && arguments)
{
commandLineLength = strlen(path) + strlen(arguments) + 2;

if (!(*commandLine = (PCHAR)malloc(commandLineLength)))
{
return ERROR_NOT_ENOUGH_MEMORY;
}

_snprintf(*commandLine, commandLineLength, "%s %s", path, arguments);
}
else if (path)
{
*commandLine = path;
}
else
{
return ERROR_INVALID_PARAMETER;
}
dprintf("[PROCESS] Using legacy command line: %s", *commandLine);
}
return ERROR_SUCCESS;
}

/*
* Executes a process using the supplied parameters, optionally creating a
* channel through which output is filtered.
Expand All @@ -122,7 +283,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
PROCESS_INFORMATION pi;
STARTUPINFOEXW si;
HANDLE in[2], out[2];
PCHAR path, arguments, commandLine = NULL;
PCHAR commandLine = NULL;
wchar_t* commandLine_w = NULL;
DWORD flags = 0, createFlags = 0, ppid = 0;
BOOL inherit = FALSE;
Expand Down Expand Up @@ -158,11 +319,16 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
{
break;
}


// Get the execution arguments
arguments = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS);
path = met_api->packet.get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH);
flags = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS);
// Get the execution command line
result = get_commandline(packet, flags, &commandLine);
if (result != ERROR_SUCCESS)
{
break;
}

ppid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PARENT_PID);

if (met_api->packet.get_tlv(packet, TLV_TYPE_VALUE_DATA, &inMemoryData) == ERROR_SUCCESS)
Expand Down Expand Up @@ -199,30 +365,6 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
} while (0);
}

// If the remote endpoint provided arguments, combine them with the
// executable to produce a command line
if (path && arguments)
{
size_t commandLineLength = strlen(path) + strlen(arguments) + 2;

if (!(commandLine = (PCHAR)malloc(commandLineLength)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}

_snprintf(commandLine, commandLineLength, "%s %s", path, arguments);
}
else if (path)
{
commandLine = path;
}
else
{
result = ERROR_INVALID_PARAMETER;
break;
}

// If the channelized flag is set, create a pipe for stdin/stdout/stderr
// such that input can be directed to and from the remote endpoint
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
Expand Down Expand Up @@ -610,7 +752,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
}

// Free the command line if necessary
if (path && arguments && commandLine)
if (commandLine)
{
free(commandLine);
}
Expand Down
4 changes: 4 additions & 0 deletions c/meterpreter/source/extensions/stdapi/stdapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#define PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN (1 << 3)
#define PROCESS_EXECUTE_FLAG_DESKTOP (1 << 4)
#define PROCESS_EXECUTE_FLAG_SESSION (1 << 5)
#define PROCESS_EXECUTE_FLAG_ARG_ARRAY (1 << 8)

#define TLV_TYPE_BASE_ADDRESS MAKE_CUSTOM_TLV( TLV_META_TYPE_QWORD, TLV_TYPE_EXTENSION_STDAPI, 2000 )
#define TLV_TYPE_ALLOCATION_TYPE MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_STDAPI, 2001 )
Expand All @@ -72,6 +73,9 @@
#define TLV_TYPE_PROCESS_ARCH MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_STDAPI, 2306 )
#define TLV_TYPE_PARENT_PID MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_STDAPI, 2307 )
#define TLV_TYPE_PROCESS_SESSION MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_STDAPI, 2308 )
#define TLV_TYPE_PROCESS_ARCH_NAME MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 2309 )
#define TLV_TYPE_PROCESS_ARGUMENT MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 2310 )
#define TLV_TYPE_PROCESS_UNESCAPED_PATH MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 2311 )

// Driver enum stuff
#define TLV_TYPE_DRIVER_ENTRY MAKE_CUSTOM_TLV( TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_STDAPI, 2320 )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public List getValues(int type) {
ArrayList values = new ArrayList();
ArrayList indices = (ArrayList) valueMap.get(new Integer(type));
if (indices == null) {
throw new IllegalArgumentException("Cannot find type " + type);
return values;
}

for (int i = 0; i < indices.size(); ++i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,21 +145,23 @@ public interface TLVType {
public static final int TLV_TYPE_ENV_GROUP = TLVPacket.TLV_META_TYPE_GROUP | 1102;

// Process
public static final int TLV_TYPE_BASE_ADDRESS = TLVPacket.TLV_META_TYPE_QWORD | 2000;
public static final int TLV_TYPE_ALLOCATION_TYPE = TLVPacket.TLV_META_TYPE_UINT | 2001;
public static final int TLV_TYPE_PROTECTION = TLVPacket.TLV_META_TYPE_UINT | 2002;
public static final int TLV_TYPE_PROCESS_PERMS = TLVPacket.TLV_META_TYPE_UINT | 2003;
public static final int TLV_TYPE_PROCESS_MEMORY = TLVPacket.TLV_META_TYPE_RAW | 2004;
public static final int TLV_TYPE_ALLOC_BASE_ADDRESS = TLVPacket.TLV_META_TYPE_QWORD | 2005;
public static final int TLV_TYPE_MEMORY_STATE = TLVPacket.TLV_META_TYPE_UINT | 2006;
public static final int TLV_TYPE_MEMORY_TYPE = TLVPacket.TLV_META_TYPE_UINT | 2007;
public static final int TLV_TYPE_ALLOC_PROTECTION = TLVPacket.TLV_META_TYPE_UINT | 2008;
public static final int TLV_TYPE_PID = TLVPacket.TLV_META_TYPE_UINT | 2300;
public static final int TLV_TYPE_PROCESS_NAME = TLVPacket.TLV_META_TYPE_STRING | 2301;
public static final int TLV_TYPE_PROCESS_PATH = TLVPacket.TLV_META_TYPE_STRING | 2302;
public static final int TLV_TYPE_PROCESS_GROUP = TLVPacket.TLV_META_TYPE_GROUP | 2303;
public static final int TLV_TYPE_PROCESS_FLAGS = TLVPacket.TLV_META_TYPE_UINT | 2304;
public static final int TLV_TYPE_PROCESS_ARGUMENTS = TLVPacket.TLV_META_TYPE_STRING | 2305;
public static final int TLV_TYPE_BASE_ADDRESS = TLVPacket.TLV_META_TYPE_QWORD | 2000;
public static final int TLV_TYPE_ALLOCATION_TYPE = TLVPacket.TLV_META_TYPE_UINT | 2001;
public static final int TLV_TYPE_PROTECTION = TLVPacket.TLV_META_TYPE_UINT | 2002;
public static final int TLV_TYPE_PROCESS_PERMS = TLVPacket.TLV_META_TYPE_UINT | 2003;
public static final int TLV_TYPE_PROCESS_MEMORY = TLVPacket.TLV_META_TYPE_RAW | 2004;
public static final int TLV_TYPE_ALLOC_BASE_ADDRESS = TLVPacket.TLV_META_TYPE_QWORD | 2005;
public static final int TLV_TYPE_MEMORY_STATE = TLVPacket.TLV_META_TYPE_UINT | 2006;
public static final int TLV_TYPE_MEMORY_TYPE = TLVPacket.TLV_META_TYPE_UINT | 2007;
public static final int TLV_TYPE_ALLOC_PROTECTION = TLVPacket.TLV_META_TYPE_UINT | 2008;
public static final int TLV_TYPE_PID = TLVPacket.TLV_META_TYPE_UINT | 2300;
public static final int TLV_TYPE_PROCESS_NAME = TLVPacket.TLV_META_TYPE_STRING | 2301;
public static final int TLV_TYPE_PROCESS_PATH = TLVPacket.TLV_META_TYPE_STRING | 2302;
public static final int TLV_TYPE_PROCESS_GROUP = TLVPacket.TLV_META_TYPE_GROUP | 2303;
public static final int TLV_TYPE_PROCESS_FLAGS = TLVPacket.TLV_META_TYPE_UINT | 2304;
public static final int TLV_TYPE_PROCESS_ARGUMENTS = TLVPacket.TLV_META_TYPE_STRING | 2305;
public static final int TLV_TYPE_PROCESS_ARGUMENT = TLVPacket.TLV_META_TYPE_STRING | 2310;
public static final int TLV_TYPE_PROCESS_UNESCAPED_PATH = TLVPacket.TLV_META_TYPE_STRING | 2311;

public static final int TLV_TYPE_IMAGE_FILE = TLVPacket.TLV_META_TYPE_STRING | 2400;
public static final int TLV_TYPE_IMAGE_FILE_PATH = TLVPacket.TLV_META_TYPE_STRING | 2401;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,47 @@
import com.metasploit.meterpreter.command.Command;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class stdapi_sys_process_execute implements Command {

private static final int PROCESS_EXECUTE_FLAG_CHANNELIZED = (1 << 1);
private static final int PROCESS_EXECUTE_FLAG_ARG_ARRAY = (1 << 8);

private static int pid = 0;

public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
StringBuilder cmdbuf = new StringBuilder();
String cmd = request.getStringValue(TLVType.TLV_TYPE_PROCESS_PATH);
String argsString = request.getStringValue(TLVType.TLV_TYPE_PROCESS_ARGUMENTS, "");
int flags = request.getIntValue(TLVType.TLV_TYPE_PROCESS_FLAGS);
Process proc;
if ((flags & PROCESS_EXECUTE_FLAG_ARG_ARRAY) != 0) {
String cmd = request.getStringValue(TLVType.TLV_TYPE_PROCESS_UNESCAPED_PATH);
if (cmd.length() == 0) {
return ERROR_FAILURE;
}

cmdbuf.append(cmd);
if (argsString.length() > 0) {
cmdbuf.append(" ");
cmdbuf.append(argsString);
}

List rawArgs = request.getValues(TLVType.TLV_TYPE_PROCESS_ARGUMENT);
ArrayList<String> args = new ArrayList<String>();
for (int i = 0; i < rawArgs.size(); ++i) {
args.add((String) rawArgs.get(i));
}
proc = execute(cmd, args);
} else {
String cmd = request.getStringValue(TLVType.TLV_TYPE_PROCESS_PATH);
if (cmd.length() == 0) {
return ERROR_FAILURE;
}

if (cmd.length() == 0) {
return ERROR_FAILURE;
String argsString = request.getStringValue(TLVType.TLV_TYPE_PROCESS_ARGUMENTS, "");
StringBuilder cmdbuf = new StringBuilder();
cmdbuf.append(cmd);
if (argsString.length() > 0) {
cmdbuf.append(" ");
cmdbuf.append(argsString);
}
proc = execute(cmdbuf.toString());
}

Process proc = execute(cmdbuf.toString());

if ((flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) != 0) {
ProcessChannel channel = new ProcessChannel(meterpreter, proc);
Expand All @@ -49,6 +65,15 @@ public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket respons
return ERROR_SUCCESS;
}

protected Process execute(String cmd, ArrayList<String> args) throws IOException {
ArrayList<String> cmdAndArgs = new ArrayList<String>();
cmdAndArgs.add(cmd);
cmdAndArgs.addAll(args);
ProcessBuilder builder = new ProcessBuilder(cmdAndArgs);
builder.directory(Loader.getCWD());
return builder.start();
}

protected Process execute(String cmdstr) throws IOException {
Process proc = Runtime.getRuntime().exec(cmdstr);
return proc;
Expand Down
Loading

0 comments on commit 80d73d4

Please sign in to comment.