Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New process launch API #701

Merged
merged 11 commits into from
Oct 10, 2024
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

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
Loading