Merge branch 'shellwords-is-stupid' of https://github.com/jlee-r7/metasploit-framework into jlee-r7-shellwords-is-stupid

unstable
sinn3r 2012-06-08 02:08:43 -05:00
commit 3d5a519a2f
3 changed files with 65 additions and 18 deletions

View File

@ -16,20 +16,21 @@ public class stdapi_sys_process_execute implements Command {
private static int pid = 0; private static int pid = 0;
public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception { public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
StringBuffer cmdbuf = new StringBuffer();
String cmd = request.getStringValue(TLVType.TLV_TYPE_PROCESS_PATH); String cmd = request.getStringValue(TLVType.TLV_TYPE_PROCESS_PATH);
String argsString = request.getStringValue(TLVType.TLV_TYPE_PROCESS_ARGUMENTS, ""); String argsString = request.getStringValue(TLVType.TLV_TYPE_PROCESS_ARGUMENTS, "");
StringTokenizer st = new StringTokenizer(argsString);
String[] cmdarray = new String[st.countTokens() + 1];
cmdarray[0] = cmd;
for (int i = 0; i < cmdarray.length - 1; i++) {
cmdarray[i + 1] = st.nextToken();
}
int flags = request.getIntValue(TLVType.TLV_TYPE_PROCESS_FLAGS); int flags = request.getIntValue(TLVType.TLV_TYPE_PROCESS_FLAGS);
cmdbuf.append(cmd);
if (argsString.length() > 0) {
cmdbuf.append(argsString);
}
if (cmd.length() == 0) if (cmd.length() == 0)
return ERROR_FAILURE; return ERROR_FAILURE;
Process proc = execute(cmdarray); Process proc = execute(cmdbuf.toString());
if ((flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) != 0) { if ((flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) != 0) {
ProcessChannel channel = new ProcessChannel(meterpreter, proc); ProcessChannel channel = new ProcessChannel(meterpreter, proc);
@ -47,8 +48,8 @@ public class stdapi_sys_process_execute implements Command {
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
protected Process execute(String[] cmdarray) throws IOException { protected Process execute(String cmdstr) throws IOException {
Process proc = Runtime.getRuntime().exec(cmdarray); Process proc = Runtime.getRuntime().exec(cmdstr);
return proc; return proc;
} }
} }

View File

@ -3,18 +3,64 @@ class Post
module Common module Common
# Execute given command as hidden and channelize, output of command given as a multiline string. #
# For certain versions of Meterpreter options can not be included in the cmd var # Executes +cmd+ on the remote system
def cmd_exec(cmd, opts=nil, time_out=15) #
# On Windows meterpreter, this will go through CreateProcess as the
# "commandLine" parameter. This means it will follow the same rules as
# Windows' path disambiguation. For example, if you were to call this method
# thusly:
#
# cmd_exec("c:\\program files\\sub dir\\program name")
#
# Windows would look for these executables, in this order, passing the rest
# of the line as arguments:
#
# c:\program.exe
# c:\program files\sub.exe
# c:\program files\sub dir\program.exe
# c:\program files\sub dir\program name.exe
#
# On POSIX meterpreter, if +args+ is set or if +cmd+ contains shell
# metacharacters, the server will run the whole thing in /bin/sh. Otherwise,
# (cmd is a single path and there are no arguments), it will execve the given
# executable.
#
# On Java, it is passed through Runtime.getRuntime().exec(String) and PHP
# uses proc_open() both of which have similar semantics to POSIX.
#
# On shell sessions, this passes +cmd+ directly the session's
# +shell_command_token+ method.
#
# Returns a (possibly multi-line) String.
#
def cmd_exec(cmd, args=nil, time_out=15)
case session.type case session.type
when /meterpreter/ when /meterpreter/
if opts.nil? and cmd =~ /\s*/ #
opts = Shellwords.shellwords(cmd) # The meterpreter API requires arguments to come seperately from the
cmd = opts.shift # executable path. This has no effect on Windows where the two are just
opts = opts.join(" ") # blithely concatenated and passed to CreateProcess or its brethren. On
# POSIX, this allows the server to execve just the executable when a
# shell is not needed. Determining when a shell is not needed is not
# always easy, so it assumes anything with arguments needs to go through
# /bin/sh.
#
# This problem was originally solved by using Shellwords.shellwords but
# unfortunately, it is retarded. When a backslash occurs inside double
# quotes (as is often the case with Windows commands) it inexplicably
# removes them. So. Shellwords is out.
#
# By setting +args+ to an empty string, we can get POSIX to send it
# through /bin/sh, solving all the pesky parsing troubles, without
# affecting Windows.
#
if args.nil? and cmd =~ /[^a-zA-Z0-9\/._-]/
args = ""
end end
session.response_timeout = time_out session.response_timeout = time_out
process = session.sys.process.execute(cmd, opts, {'Hidden' => true, 'Channelized' => true}) process = session.sys.process.execute(cmd, args, {'Hidden' => true, 'Channelized' => true})
o = "" o = ""
while (d = process.channel.read) while (d = process.channel.read)
break if d == "" break if d == ""
@ -23,7 +69,7 @@ module Common
process.channel.close process.channel.close
process.close process.close
when /shell/ when /shell/
o = session.shell_command_token("#{cmd} #{opts}", time_out) o = session.shell_command_token("#{cmd} #{args}", time_out)
o.chomp! if o o.chomp! if o
end end
return "" if o.nil? return "" if o.nil?