Merge pull request #19108 from smashery/new_cmd_exec

New process launch API
This commit is contained in:
adfoster-r7
2024-10-17 00:08:06 +01:00
committed by GitHub
35 changed files with 723 additions and 185 deletions
+4 -4
View File
@@ -41,9 +41,9 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 2.0.175)
metasploit-payloads (= 2.0.183)
metasploit_data_models
metasploit_payloads-mettle (= 1.0.31)
metasploit_payloads-mettle (= 1.0.32)
mqtt
msgpack (~> 1.6.0)
mutex_m
@@ -295,7 +295,7 @@ GEM
activemodel (~> 7.0)
activesupport (~> 7.0)
railties (~> 7.0)
metasploit-payloads (2.0.175)
metasploit-payloads (2.0.183)
metasploit_data_models (6.0.3)
activerecord (~> 7.0)
activesupport (~> 7.0)
@@ -306,7 +306,7 @@ GEM
railties (~> 7.0)
recog
webrick
metasploit_payloads-mettle (1.0.31)
metasploit_payloads-mettle (1.0.32)
method_source (1.1.0)
mime-types (3.5.2)
mime-types-data (~> 3.2015)
+2 -2
View File
@@ -88,9 +88,9 @@ metasploit-concern, 5.0.2, "New BSD"
metasploit-credential, 6.0.9, "New BSD"
metasploit-framework, 6.4.31, "New BSD"
metasploit-model, 5.0.2, "New BSD"
metasploit-payloads, 2.0.175, "3-clause (or ""modified"") BSD"
metasploit-payloads, 2.0.183, "3-clause (or ""modified"") BSD"
metasploit_data_models, 6.0.3, "New BSD"
metasploit_payloads-mettle, 1.0.31, "3-clause (or ""modified"") BSD"
metasploit_payloads-mettle, 1.0.32, "3-clause (or ""modified"") BSD"
method_source, 1.1.0, MIT
mime-types, 3.5.2, MIT
mime-types-data, 3.2024.0604, MIT
+43
View File
@@ -735,6 +735,49 @@ Shell Banner:
end
end
# Perform command line escaping wherein most chars are able to be escaped by quoting them,
# but others don't have a valid way of existing inside quotes, so we need to "glue" together
# a series of sections of the original command line; some sections inside quotes, and some outside
# @param arg [String] The command line arg to escape
# @param quote_requiring [Array<String>] The chars that can successfully be escaped inside quotes
# @param unquotable_char [String] The character that can't exist inside quotes
# @param escaped_unquotable_char [String] The escaped form of unquotable_char
# @param quote_char [String] The char used for quoting
def self._glue_cmdline_escape(arg, quote_requiring, unquotable_char, escaped_unquotable_char, quote_char)
current_token = ""
result = ""
in_quotes = false
arg.each_char do |char|
if char == unquotable_char
if in_quotes
# This token has been in an inside-quote context, so let's properly wrap that before continuing
current_token = "#{quote_char}#{current_token}#{quote_char}"
end
result += current_token
result += escaped_unquotable_char # Escape the offending percent
# Start a new token - we'll assume we're remaining outside quotes
current_token = ''
in_quotes = false
next
elsif quote_requiring.include?(char)
# Oh, it turns out we should have been inside quotes for this token.
# Let's note that, for when we actually append the token
in_quotes = true
end
current_token += char
end
if in_quotes
# The final token has been in an inside-quote context, so let's properly wrap that before continuing
current_token = "#{quote_char}#{current_token}#{quote_char}"
end
result += current_token
result
end
attr_accessor :arch
attr_accessor :platform
attr_accessor :max_threads
@@ -5,9 +5,44 @@ module Msf::Sessions
self.platform = "unix"
super
end
def shell_command_token(cmd,timeout = 10)
shell_command_token_unix(cmd,timeout)
end
# Convert the executable and argument array to a command that can be run in this command shell
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
def to_cmd(cmd_and_args)
self.class.to_cmd(cmd_and_args)
end
# Escape an individual argument per Unix shell rules
# @param arg [String] Shell argument
def escape_arg(arg)
self.class.escape_arg(arg)
end
# Convert the executable and argument array to a command that can be run in this command shell
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
def self.to_cmd(cmd_and_args)
escaped = cmd_and_args.map do |arg|
escape_arg(arg)
end
escaped.join(' ')
end
# Escape an individual argument per Unix shell rules
# @param arg [String] Shell argument
def self.escape_arg(arg)
quote_requiring = ['\\', '`', '(', ')', '<', '>', '&', '|', ' ', '@', '"', '$', ';']
result = CommandShell._glue_cmdline_escape(arg, quote_requiring, "'", "\\'", "'")
if result == ''
result = "''"
end
result
end
end
end
+106 -1
View File
@@ -1,4 +1,3 @@
module Msf::Sessions
class CommandShellWindows < CommandShell
@@ -6,9 +5,115 @@ module Msf::Sessions
self.platform = "windows"
super
end
def self.space_chars
[' ', '\t', '\v']
end
def shell_command_token(cmd,timeout = 10)
shell_command_token_win32(cmd,timeout)
end
# Convert the executable and argument array to a command that can be run in this command shell
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
def to_cmd(cmd_and_args)
self.class.to_cmd(cmd_and_args)
end
# Escape a process for the command line
# @param executable [String] The process to launch
def self.escape_cmd(executable)
needs_quoting = space_chars.any? do |char|
executable.include?(char)
end
if needs_quoting
executable = "\"#{executable}\""
end
executable
end
# Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.
# @param args [Array<String>] The arguments to the process
# @remark The difference between this and `to_cmd` is that the output of `to_cmd` is expected to be passed
# to cmd.exe, whereas this is expected to be passed directly to the Win32 API, anticipating that it
# will in turn be interpreted by CommandLineToArgvW.
def self.argv_to_commandline(args)
escaped_args = args.map do |arg|
escape_arg(arg)
end
escaped_args.join(' ')
end
# Escape an individual argument per Windows shell rules
# @param arg [String] Shell argument
def self.escape_arg(arg)
needs_quoting = space_chars.any? do |char|
arg.include?(char)
end
# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote
# We need to send double the number of backslashes to make it work as expected
# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
arg = arg.gsub(/(\\*)"/, '\\1\\1"')
# Quotes need to be escaped
arg = arg.gsub('"', '\\"')
if needs_quoting
# At the end of the argument, we're about to add another quote - so any backslashes need to be doubled here too
arg = arg.gsub(/(\\*)$/, '\\1\\1')
arg = "\"#{arg}\""
end
# Empty string needs to be coerced to have a value
arg = '""' if arg == ''
arg
end
# Convert the executable and argument array to a command that can be run in this command shell
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
def self.to_cmd(cmd_and_args)
# The space, caret and quote chars need to be inside double-quoted strings.
# The percent character needs to be escaped using a caret char, while being outside a double-quoted string.
#
# Situations where these two situations combine are going to be the trickiest cases: something that has quote-requiring
# characters (e.g. spaces), but which also needs to avoid expanding an environment variable. In this case,
# the string needs to end up being partially quoted; with parts of the string in quotes, but others (i.e. bits with percents) not.
# For example:
# 'env var is %temp%, yes, %TEMP%' needs to end up as '"env var is "^%temp^%", yes, "^%TEMP^%'
#
# There is flexibility in how you might implement this, but I think this one looks the most "human" to me,
# which would make it less signaturable.
#
# To do this, we'll consider each argument character-by-character. Each time we encounter a percent sign, we break out of any quotes
# (if we've been inside them in the current "token"), and then start a new "token".
quote_requiring = ['"', '^', ' ', "\t", "\v", '&', '<', '>', '|']
escaped_cmd_and_args = cmd_and_args.map do |arg|
# Escape quote chars by doubling them up, except those preceeded by a backslash (which are already effectively escaped, and handled below)
arg = arg.gsub(/([^\\])"/, '\\1""')
arg = arg.gsub(/^"/, '""')
result = CommandShell._glue_cmdline_escape(arg, quote_requiring, '%', '^%', '"')
# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote
# We need to send double the number of backslashes to make it work as expected
# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
result.gsub!(/(\\*)"/, '\\1\\1"')
# Empty string needs to be coerced to have a value
result = '""' if result == ''
result
end
escaped_cmd_and_args.join(' ')
end
end
end
+85
View File
@@ -38,6 +38,91 @@ class Msf::Sessions::PowerShell < Msf::Sessions::CommandShell
include Mixin
# Convert the executable and argument array to a command that can be run in this command shell
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
def to_cmd(cmd_and_args)
self.class.to_cmd(cmd_and_args)
end
# Convert the executable and argument array to a command that can be run in this command shell
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
def self.to_cmd(cmd_and_args)
# The principle here is that we want to launch a process such that it receives *exactly* what is in `args`.
# This means we need to:
# - Escape all special characters
# - Not escape environment variables
# - Side-step any PowerShell magic
# If someone specifically wants to use the PowerShell magic, they can use other APIs
needs_wrapping_chars = ['$', '`', '(', ')', '@', '>', '<', '{','}', '&', ',', ' ', ';']
result = ""
cmd_and_args.each_with_index do |arg, index|
needs_single_quoting = false
if arg.include?("'")
arg = arg.gsub("'", "''")
needs_single_quoting = true
end
if arg.include?('"')
# PowerShell acts weird around quotes and backslashes
# First we need to escape backslashes immediately prior to a double-quote, because
# they're treated differently than backslashes anywhere else
arg = arg.gsub(/(\\+)"/, '\\1\\1"')
# Then we can safely prepend a backslash to escape our double-quote
arg = arg.gsub('"', '\\"')
needs_single_quoting = true
end
needs_wrapping_chars.each do |char|
if arg.include?(char)
needs_single_quoting = true
end
end
# PowerShell magic - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.4#stop-parsing-token---
if arg == '--%'
needs_single_quoting = true
end
will_be_double_quoted_by_powershell = [' ', '\t', '\v'].any? do |bad_char|
arg.include?(bad_char)
end
if will_be_double_quoted_by_powershell
# This is horrible, and I'm so so sorry.
# If an argument ends with a series of backslashes, and it will be quoted by PowerShell when *it* launches the process (e.g. because the arg contains a space),
# PowerShell will not correctly handle backslashes immediately preceeding the quote that it *itself* adds. So we need to be responsible for this.
arg = arg.gsub(/(\\*)$/, '\\1\\1')
end
if needs_single_quoting
arg = "'#{arg}'"
end
if arg == ''
# Pass in empty strings
arg = '\'""\''
end
if index == 0
if needs_single_quoting
# If the executable name (i.e. index 0) has beeen wrapped, then we'll have converted it to a string.
# We then need to use the call operator ('&') to call it.
# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.3#call-operator-
result = "& #{arg}"
else
result = arg
end
else
result = "#{result} #{arg}"
end
end
result
end
#
# Execute any specified auto-run scripts for this session
#
+65
View File
@@ -52,6 +52,71 @@ module Msf::Post::Common
"#{rhost}:#{rport}"
end
# Create a new process, receiving the program's output
# @param executable [String] The path to the executable; either absolute or relative to the session's current directory
# @param args [Array<String>] The arguments to the executable
# @time_out [Integer] Number of seconds before the call will time out
# @param opts [Hash] Optional settings to parameterise the process launch
# @option Hidden [Boolean] Is the process launched without creating a visible window
# @option Channelized [Boolean] The process is launched with pipes connected to a channel, e.g. for sending input/receiving output
# @option Suspended [Boolean] Start the process suspended
# @option UseThreadToken [Boolean] Use the thread token (as opposed to the process token) to launch the process
# @option Desktop [Boolean] Run on meterpreter's current desktop
# @option Session [Integer] Execute process in a given session as the session user
# @option Subshell [Boolean] Execute process in a subshell
# @option Pty [Boolean] Execute process in a pty (if available)
# @option ParentId [Integer] Spoof the parent PID (if possible)
# @option InMemory [Boolean,String] Execute from memory (`path` is treated as a local file to upload, and the actual path passed
# to meterpreter is this parameter's value, if provided as a String)
def create_process(executable, args: [], time_out: 15, opts: {})
case session.type
when 'meterpreter'
session.response_timeout = time_out
opts = {
'Hidden' => true,
'Channelized' => true,
# Well-behaving meterpreters will ignore the Subshell flag when using arg arrays.
# This is still provided for supporting old meterpreters.
'Subshell' => true
}.merge(opts)
if session.platform == 'windows'
if session.arch == 'php'
opts[:legacy_args] = Msf::Sessions::CommandShellWindows.to_cmd(args)
opts[:legacy_path] = Msf::Sessions::CommandShellWindows.to_cmd([executable])
elsif session.arch == 'python'
opts[:legacy_path] = executable
# Yes, Unix. Old Python meterp had a bug where it used posix shell splitting
# syntax even on Windows. For backwards-compatibility, we can trick it into
# doing the right thing by using Unix escaping.
opts[:legacy_args] = Msf::Sessions::CommandShellUnix.to_cmd(args)
else
opts[:legacy_args] = Msf::Sessions::CommandShellWindows.argv_to_commandline(args)
opts[:legacy_path] = Msf::Sessions::CommandShellWindows.escape_cmd(executable)
end
else
opts[:legacy_args] = Msf::Sessions::CommandShellUnix.to_cmd(args)
opts[:legacy_path] = Msf::Sessions::CommandShellUnix.to_cmd([executable])
end
if opts['Channelized']
o = session.sys.process.capture_output(executable, args, opts, time_out)
else
session.sys.process.execute(executable, args, opts)
end
when 'powershell'
cmd = session.to_cmd([executable] + args)
o = session.shell_command(cmd, time_out)
o.chomp! if o
when 'shell'
cmd = session.to_cmd([executable] + args)
o = session.shell_command_token(cmd, time_out)
o.chomp! if o
end
return "" if o.nil?
return o
end
#
# Executes +cmd+ on the remote system
#
+17 -7
View File
@@ -580,7 +580,7 @@ module Msf::Post::File
if session.type == 'meterpreter' && session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_FS_CHMOD)
session.fs.file.chmod(path, mode)
else
cmd_exec("chmod #{mode.to_s(8)} '#{path}'")
create_process('chmod', args: [mode.to_s(8), path])
end
end
@@ -740,6 +740,7 @@ module Msf::Post::File
else
file_mode = 'Create'
end
file_name = file_name.gsub("'","''")
pwsh_code = <<~PSH
try {
$encoded='#{encoded_chunk}';
@@ -911,7 +912,7 @@ protected
success = _win_ansi_write_file(b64_filename, b64_data, chunk_size)
return false unless success
vprint_status("Uploaded Base64-encoded file. Decoding using certutil")
success = _shell_command_with_success_code("certutil -f -decode #{b64_filename} #{file_name}")
success = _shell_process_with_success_code('certutil', ['-f', '-decode', b64_filename, file_name])
return false unless success
rescue ::Exception => e
print_error("Exception while running #{__method__}: #{e}")
@@ -937,10 +938,10 @@ protected
success = _win_ansi_write_file(b64_filename, b64_data, chunk_size)
return false unless success
vprint_status("Uploaded Base64-encoded file. Decoding using certutil")
success = _shell_command_with_success_code("certutil -decode #{b64_filename} #{tmp_filename}")
success = _shell_process_with_success_code('certutil', ['-decode', b64_filename, tmp_filename])
return false unless success
vprint_status("Certutil succeeded. Appending using copy")
success = _shell_command_with_success_code("copy /b #{file_name}+#{tmp_filename} #{file_name}")
success = _shell_process_with_success_code('copy', ['/b', "#{file_name}+#{tmp_filename}", file_name])
return false unless success
rescue ::Exception => e
print_error("Exception while running #{__method__}: #{e}")
@@ -980,7 +981,7 @@ protected
# Short-circuit an empty string. The : builtin is part of posix
# standard and should theoretically exist everywhere.
if data.empty?
return _shell_command_with_success_code(": #{redirect} #{file_name}")
return _shell_command_with_success_code(": #{redirect} #{session.escape_arg(file_name)}")
end
d = data.dup
@@ -1081,7 +1082,7 @@ protected
# The first command needs to use the provided redirection for either
# appending or truncating.
cmd = command.sub('CONTENTS') { chunks.shift }
succeeded = _shell_command_with_success_code("#{cmd} #{redirect} \"#{file_name}\"")
succeeded = _shell_command_with_success_code("#{cmd} #{redirect} #{session.escape_arg(file_name)}")
return false unless succeeded
# After creating/truncating or appending with the first command, we
@@ -1090,7 +1091,7 @@ protected
vprint_status("Next chunk is #{chunk.length} bytes")
cmd = command.sub('CONTENTS') { chunk }
succeeded = _shell_command_with_success_code("#{cmd} >> '#{file_name}'")
succeeded = _shell_command_with_success_code("#{cmd} >> #{session.escape_arg(file_name)}")
unless succeeded
print_warning("Write partially succeeded then failed. May need to manually clean up #{file_name}")
return false
@@ -1107,6 +1108,15 @@ protected
return result&.include?(token)
end
def _shell_process_with_success_code(executable, args)
cmd = session.to_cmd([executable] + args)
token = "_#{::Rex::Text.rand_text_alpha(32)}"
result = session.shell_command_token("#{cmd} && echo #{token}")
return result&.include?(token)
end
#
# Calculate the maximum line length for a unix shell.
#
@@ -93,11 +93,11 @@ module SingleCommandShell
output
end
def to_cmd(cmd, args)
def to_cmd(cmd_and_args)
if platform == 'windows'
result = Msf::Sessions::CommandShellWindows.to_cmd(cmd, args)
result = Msf::Sessions::CommandShellWindows.to_cmd(cmd_and_args)
else
result = Msf::Sessions::CommandShellUnix.to_cmd(cmd, args)
result = Msf::Sessions::CommandShellUnix.to_cmd(cmd_and_args)
end
end
@@ -107,15 +107,24 @@ class Process < Rex::Post::Process
#
# Executes an application using the arguments provided
# @param path [String] Path on the remote system to the executable to run
# @param arguments [String,Array<String>] Arguments to the process. When passed as a String (rather than an array of Strings),
# this is treated as a string containing all arguments.
# @param opts [Hash] Optional settings to parameterise the process launch
# @option Hidden [Boolean] Is the process launched without creating a visible window
# @option Channelized [Boolean] The process is launched with pipes connected to a channel, e.g. for sending input/receiving output
# @option Suspended [Boolean] Start the process suspended
# @option UseThreadToken [Boolean] Use the thread token (as opposed to the process token) to launch the process
# @option Desktop [Boolean] Run on meterpreter's current desktopt
# @option Session [Integer] Execute process in a given session as the session user
# @option Subshell [Boolean] Execute process in a subshell
# @option Pty [Boolean] Execute process in a pty (if available)
# @option ParentId [Integer] Spoof the parent PID (if possible)
# @option InMemory [Boolean,String] Execute from memory (`path` is treated as a local file to upload, and the actual path passed
# to meterpreter is this parameter's value, if provided as a String)
# @option :legacy_args [String] When arguments is an array, this is the command to execute if the receiving Meterpreter does not support arguments as an array
#
# Hash arguments supported:
#
# Hidden => true/false
# Channelized => true/false
# Suspended => true/false
# InMemory => true/false
#
def Process.execute(path, arguments = nil, opts = nil)
def Process.execute(path, arguments = '', opts = nil)
request = Packet.create_request(COMMAND_ID_STDAPI_SYS_PROCESS_EXECUTE)
flags = 0
@@ -164,11 +173,26 @@ class Process < Rex::Post::Process
end
end
request.add_tlv(TLV_TYPE_PROCESS_PATH, client.unicode_filter_decode( path ));
# Add arguments
# If process arguments were supplied
if (arguments != nil)
request.add_tlv(TLV_TYPE_PROCESS_ARGUMENTS, arguments);
if arguments.kind_of?(Array)
request.add_tlv(TLV_TYPE_PROCESS_UNESCAPED_PATH, client.unicode_filter_decode( path ));
# This flag is needed to disambiguate how to handle escaping special characters in the path when no arguments are provided
flags |= PROCESS_EXECUTE_FLAG_ARG_ARRAY
arguments.each do |arg|
request.add_tlv(TLV_TYPE_PROCESS_ARGUMENT, arg);
end
if opts[:legacy_path]
request.add_tlv(TLV_TYPE_PROCESS_PATH, opts[:legacy_path])
end
if opts[:legacy_args]
request.add_tlv(TLV_TYPE_PROCESS_ARGUMENTS, opts[:legacy_args])
end
elsif arguments.kind_of?(String)
request.add_tlv(TLV_TYPE_PROCESS_PATH, client.unicode_filter_decode( path ));
request.add_tlv(TLV_TYPE_PROCESS_ARGUMENTS, arguments)
else
raise ArgumentError.new('Unknown type for arguments')
end
request.add_tlv(TLV_TYPE_PROCESS_FLAGS, flags);
@@ -194,7 +218,7 @@ class Process < Rex::Post::Process
#
# Execute an application and capture the output
#
def Process.capture_output(path, arguments = nil, opts = nil, time_out = 15)
def Process.capture_output(path, arguments = '', opts = nil, time_out = 15)
start = Time.now.to_i
process = execute(path, arguments, opts)
data = ""
@@ -119,6 +119,7 @@ PROCESS_EXECUTE_FLAG_DESKTOP = (1 << 4)
PROCESS_EXECUTE_FLAG_SESSION = (1 << 5)
PROCESS_EXECUTE_FLAG_SUBSHELL = (1 << 6)
PROCESS_EXECUTE_FLAG_PTY = (1 << 7)
PROCESS_EXECUTE_FLAG_ARG_ARRAY = (1 << 8)
# Registry
TLV_TYPE_HKEY = TLV_META_TYPE_QWORD | 1000
@@ -151,25 +152,27 @@ TLV_TYPE_ENV_GROUP = TLV_META_TYPE_GROUP | 1102
DELETE_KEY_FLAG_RECURSIVE = (1 << 0)
# Process
TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2000
TLV_TYPE_ALLOCATION_TYPE = TLV_META_TYPE_UINT | 2001
TLV_TYPE_PROTECTION = TLV_META_TYPE_UINT | 2002
TLV_TYPE_PROCESS_PERMS = TLV_META_TYPE_UINT | 2003
TLV_TYPE_PROCESS_MEMORY = TLV_META_TYPE_RAW | 2004
TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2005
TLV_TYPE_MEMORY_STATE = TLV_META_TYPE_UINT | 2006
TLV_TYPE_MEMORY_TYPE = TLV_META_TYPE_UINT | 2007
TLV_TYPE_ALLOC_PROTECTION = TLV_META_TYPE_UINT | 2008
TLV_TYPE_PID = TLV_META_TYPE_UINT | 2300
TLV_TYPE_PROCESS_NAME = TLV_META_TYPE_STRING | 2301
TLV_TYPE_PROCESS_PATH = TLV_META_TYPE_STRING | 2302
TLV_TYPE_PROCESS_GROUP = TLV_META_TYPE_GROUP | 2303
TLV_TYPE_PROCESS_FLAGS = TLV_META_TYPE_UINT | 2304
TLV_TYPE_PROCESS_ARGUMENTS = TLV_META_TYPE_STRING | 2305
TLV_TYPE_PROCESS_ARCH = TLV_META_TYPE_UINT | 2306
TLV_TYPE_PARENT_PID = TLV_META_TYPE_UINT | 2307
TLV_TYPE_PROCESS_SESSION = TLV_META_TYPE_UINT | 2308
TLV_TYPE_PROCESS_ARCH_NAME = TLV_META_TYPE_STRING | 2309
TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2000
TLV_TYPE_ALLOCATION_TYPE = TLV_META_TYPE_UINT | 2001
TLV_TYPE_PROTECTION = TLV_META_TYPE_UINT | 2002
TLV_TYPE_PROCESS_PERMS = TLV_META_TYPE_UINT | 2003
TLV_TYPE_PROCESS_MEMORY = TLV_META_TYPE_RAW | 2004
TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2005
TLV_TYPE_MEMORY_STATE = TLV_META_TYPE_UINT | 2006
TLV_TYPE_MEMORY_TYPE = TLV_META_TYPE_UINT | 2007
TLV_TYPE_ALLOC_PROTECTION = TLV_META_TYPE_UINT | 2008
TLV_TYPE_PID = TLV_META_TYPE_UINT | 2300
TLV_TYPE_PROCESS_NAME = TLV_META_TYPE_STRING | 2301
TLV_TYPE_PROCESS_PATH = TLV_META_TYPE_STRING | 2302
TLV_TYPE_PROCESS_GROUP = TLV_META_TYPE_GROUP | 2303
TLV_TYPE_PROCESS_FLAGS = TLV_META_TYPE_UINT | 2304
TLV_TYPE_PROCESS_ARGUMENTS = TLV_META_TYPE_STRING | 2305
TLV_TYPE_PROCESS_ARCH = TLV_META_TYPE_UINT | 2306
TLV_TYPE_PARENT_PID = TLV_META_TYPE_UINT | 2307
TLV_TYPE_PROCESS_SESSION = TLV_META_TYPE_UINT | 2308
TLV_TYPE_PROCESS_ARCH_NAME = TLV_META_TYPE_STRING | 2309
TLV_TYPE_PROCESS_ARGUMENT = TLV_META_TYPE_STRING | 2310
TLV_TYPE_PROCESS_UNESCAPED_PATH = TLV_META_TYPE_STRING | 2311
TLV_TYPE_DRIVER_ENTRY = TLV_META_TYPE_GROUP | 2320
TLV_TYPE_DRIVER_BASENAME = TLV_META_TYPE_STRING | 2321
+2 -2
View File
@@ -74,9 +74,9 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '2.0.175'
spec.add_runtime_dependency 'metasploit-payloads', '2.0.183'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.31'
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.32'
# Needed by msfgui and other rpc components
# Locked until build env can handle newer version. See: https://github.com/msgpack/msgpack-ruby/issues/334
spec.add_runtime_dependency 'msgpack', '~> 1.6.0'
@@ -26,7 +26,7 @@ module MetasploitModule
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::CommandShell,
'Session' => Msf::Sessions::CommandShellUnix,
'PayloadType' => 'cmd_bash',
'RequiredCmd' => 'bash-tcp',
'Payload' =>
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1061712
CachedSize = 1061912
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1061712
CachedSize = 1061912
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1061712
CachedSize = 1061912
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1061884
CachedSize = 1062084
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1061884
CachedSize = 1062084
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1061884
CachedSize = 1062084
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1516268
CachedSize = 1516524
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1516268
CachedSize = 1516524
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1516268
CachedSize = 1516524
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1519288
CachedSize = 1519544
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1519288
CachedSize = 1519544
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 1519288
CachedSize = 1519544
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -5,7 +5,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 813091
CachedSize = 813075
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -5,7 +5,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 813091
CachedSize = 813075
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -5,7 +5,7 @@
# Module generated by tools/modules/generate_mettle_payloads.rb
module MetasploitModule
CachedSize = 813091
CachedSize = 813075
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions
@@ -7,7 +7,7 @@
module MetasploitModule
CachedSize = 34854
CachedSize = 34928
include Msf::Payload::Single
include Msf::Payload::Php::ReverseTcp
+1 -1
View File
@@ -27,6 +27,6 @@ class MetasploitModule < Msf::Post
def run
print_status("Executing #{datastore['COMMAND']} on #{session.inspect}...")
res = cmd_exec(datastore['COMMAND'])
print_status("Response: #{res}")
print_status("Response: \n#{res}")
end
end
+39
View File
@@ -0,0 +1,39 @@
RSpec.describe Msf::Sessions::CommandShellUnix do
describe 'to_cmd processing' do
it 'should not do anything for simple args' do
expect(described_class.to_cmd(['./test'] + [])).to eq('./test')
expect(described_class.to_cmd(['sh'] + [])).to eq('sh')
expect(described_class.to_cmd(['./test'] + ['basic','args'])).to eq('./test basic args')
expect(described_class.to_cmd(['basic','args'])).to eq('basic args')
end
it 'should escape spaces' do
expect(described_class.to_cmd(['/home/user/some folder/some program'] + [])).to eq("'/home/user/some folder/some program'")
expect(described_class.to_cmd(['./test'] + ['with space'])).to eq("./test 'with space'")
end
it 'should escape logical operators' do
expect(described_class.to_cmd(['./test'] + ['&&', 'echo', 'words'])).to eq("./test '&&' echo words")
expect(described_class.to_cmd(['./test'] + ['||', 'echo', 'words'])).to eq("./test '||' echo words")
expect(described_class.to_cmd(['./test'] + ['&echo', 'words'])).to eq("./test '&echo' words")
expect(described_class.to_cmd(['./test'] + ['run&echo', 'words'])).to eq("./test 'run&echo' words")
end
it 'should quote if single quotes are present' do
expect(described_class.to_cmd(['./test'] + ["it's"])).to eq("./test it\\'s")
expect(described_class.to_cmd(['./test'] + ["it's a param"])).to eq("./test it\\''s a param'")
end
it 'should escape redirectors' do
expect(described_class.to_cmd(['./test'] + ['>', 'out.txt'])).to eq("./test '>' out.txt")
expect(described_class.to_cmd(['./test'] + ['<', 'in.txt'])).to eq("./test '<' in.txt")
end
it 'should not expand env vars' do
expect(described_class.to_cmd(['./test'] + ['$PATH'])).to eq("./test '$PATH'")
expect(described_class.to_cmd(['./test'] + ["it's $PATH"])).to eq("./test it\\''s $PATH'")
expect(described_class.to_cmd(['./test'] + ["\"$PATH\""])).to eq("./test '\"$PATH\"'")
expect(described_class.to_cmd(['./test'] + ["it's \"$PATH\""])).to eq("./test it\\''s \"$PATH\"'")
end
end
end
+88
View File
@@ -0,0 +1,88 @@
RSpec.describe Msf::Sessions::CommandShellWindows do
describe 'to_cmd processing' do
it 'should not do anything for simple args' do
expect(described_class.to_cmd(['test.exe'] + [])).to eq('test.exe')
expect(described_class.to_cmd(['test.exe'] + ['basic','args'])).to eq('test.exe basic args')
end
it 'should quote spaces' do
expect(described_class.to_cmd(['C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE'] + [])).to eq('"C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE"')
expect(described_class.to_cmd(['test.exe'] + ['with space'])).to eq('test.exe "with space"')
end
it 'should escape logical operators' do
expect(described_class.to_cmd(['test.exe'] + ['&&', 'echo', 'words'])).to eq('test.exe "&&" echo words')
expect(described_class.to_cmd(['test.exe'] + ['||', 'echo', 'words'])).to eq('test.exe "||" echo words')
expect(described_class.to_cmd(['test.exe'] + ['&echo', 'words'])).to eq('test.exe "&echo" words')
expect(described_class.to_cmd(['test.exe'] + ['run&echo', 'words'])).to eq('test.exe "run&echo" words')
end
it 'should escape redirectors' do
expect(described_class.to_cmd(['test.exe'] + ['>', 'out.txt'])).to eq('test.exe ">" out.txt')
expect(described_class.to_cmd(['test.exe'] + ['<', 'in.txt'])).to eq('test.exe "<" in.txt')
end
it 'should escape carets' do
expect(described_class.to_cmd(['test.exe'] + ['with^caret'])).to eq('test.exe "with^caret"')
expect(described_class.to_cmd(['test.exe'] + ['with^^carets'])).to eq('test.exe "with^^carets"')
end
it 'should not expand env vars' do
expect(described_class.to_cmd(['test.exe'] + ['%temp%'])).to eq('test.exe ^%temp^%')
expect(described_class.to_cmd(['test.exe'] + ['env', 'var', 'is', '%temp%'])).to eq('test.exe env var is ^%temp^%')
end
it 'should handle the weird backslash escaping behaviour in front of quotes' do
expect(described_class.to_cmd(['test.exe'] + ['quote\\\\"'])).to eq('test.exe "quote\\\\\\\\""')
expect(described_class.to_cmd(['test.exe'] + ['will be quoted\\\\'])).to eq('test.exe "will be quoted\\\\\\\\"')
expect(described_class.to_cmd(['test.exe'] + ['will be quoted\\\\ '])).to eq('test.exe "will be quoted\\\\ "') # Should not be doubled up
expect(described_class.to_cmd(['test.exe'] + ['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])).to eq('test.exe """test""" "test\\\\"" "test\\\\\\\\"" "test words\\\\\\\\\\\\\\\\" "test words\\\\\\\\\\\\" \\\\')
end
it 'should handle combinations of quoting and percent-escaping' do
expect(described_class.to_cmd(['test.exe'] + ['env var is %temp%'])).to eq('test.exe "env var is "^%temp^%')
expect(described_class.to_cmd(['test.exe'] + ['env var is %temp%, yes, %TEMP%'])).to eq('test.exe "env var is "^%temp^%", yes, "^%TEMP^%')
expect(described_class.to_cmd(['test.exe'] + ['%temp%found at the start shouldn\'t %temp% be quoted'])).to eq('test.exe ^%temp^%"found at the start shouldn\'t "^%temp^%" be quoted"')
end
it 'should handle single percents' do
expect(described_class.to_cmd(['test.exe'] + ['%single percent'])).to eq('test.exe ^%"single percent"')
expect(described_class.to_cmd(['test.exe'] + ['100%'])).to eq('test.exe 100^%')
end
it 'should handle empty args' do
expect(described_class.to_cmd(['test.exe'] + [''])).to eq('test.exe ""')
expect(described_class.to_cmd(['test.exe'] + ['', ''])).to eq('test.exe "" ""')
end
end
describe 'argv_to_commandline processing' do
it 'should not do anything for simple args' do
expect(described_class.argv_to_commandline([])).to eq('')
expect(described_class.argv_to_commandline(['basic','args'])).to eq('basic args')
expect(described_class.argv_to_commandline(['!@#$%^&*(){}><.,\''])).to eq('!@#$%^&*(){}><.,\'')
end
it 'should quote space characters' do
expect(described_class.argv_to_commandline([])).to eq('')
expect(described_class.argv_to_commandline(['basic','args'])).to eq('basic args')
end
it 'should escape double-quote characters' do
expect(described_class.argv_to_commandline(['"one','"two"'])).to eq('\\"one \\"two\\"')
expect(described_class.argv_to_commandline(['"one "two"'])).to eq('"\\"one \\"two\\""')
end
it 'should handle the weird backslash escaping behaviour in front of quotes' do
expect(described_class.argv_to_commandline(['\\\\"'])).to eq('\\\\\\\\\\"')
expect(described_class.argv_to_commandline(['space \\\\'])).to eq('"space \\\\\\\\"')
expect(described_class.argv_to_commandline(['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])).to eq('\"test\" test\\\\\\" test\\\\\\\\\\" "test words\\\\\\\\\\\\\\\\" "test words\\\\\\\\\\\\" \\\\')
end
it 'should handle empty args' do
expect(described_class.argv_to_commandline([''])).to eq('""')
expect(described_class.argv_to_commandline(['', ''])).to eq('"" ""')
end
end
end
+52
View File
@@ -0,0 +1,52 @@
RSpec.describe Msf::Sessions::PowerShell do
describe 'to_cmd processing' do
it 'should not do anything for simple args' do
expect(described_class.to_cmd([".\\test.exe"] + ['abc', '123'])).to eq(".\\test.exe abc 123")
expect(described_class.to_cmd(["C:\\SysinternalsSuite\\procexp.exe"] + [])).to eq("C:\\SysinternalsSuite\\procexp.exe")
end
it 'should double single-quotes' do
expect(described_class.to_cmd([".\\test.exe"] + ["'abc'"])).to eq(".\\test.exe '''abc'''")
end
it 'should escape less than' do
expect(described_class.to_cmd([".\\test.exe"] + ["'abc'", '>', 'out.txt'])).to eq(".\\test.exe '''abc''' '>' out.txt")
end
it 'should escape other special chars' do
expect(described_class.to_cmd([".\\test.exe"] + ["'abc'", '<', '(', ')', '$test', '`words`', 'abc,def'])).to eq(".\\test.exe '''abc''' '<' '(' ')' '$test' '`words`' 'abc,def'")
end
it 'should backslash escape double-quotes' do
expect(described_class.to_cmd([".\\test.exe"] + ['"abc'])).to eq(".\\test.exe '\\\"abc'")
end
it 'should correctly backslash escape backslashes and double-quotes' do
expect(described_class.to_cmd([".\\test.exe"] + ['\\"abc'])).to eq(".\\test.exe '\\\\\\\"abc'")
expect(described_class.to_cmd([".\\test.exe"] + ['\\\\"abc'])).to eq(".\\test.exe '\\\\\\\\\\\"abc'")
expect(described_class.to_cmd([".\\test.exe"] + ['\\\\"ab\\\\c'])).to eq(".\\test.exe '\\\\\\\\\\\"ab\\\\c'")
end
it 'should quote the executable and add the call operator' do
expect(described_class.to_cmd([".\\test$.exe"] + ['abc'])).to eq("& '.\\test$.exe' abc")
expect(described_class.to_cmd([".\\test'.exe"] + ['abc'])).to eq("& '.\\test''.exe' abc")
expect(described_class.to_cmd(["C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE"] + [])).to eq("& 'C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE'")
end
it 'should not expand environment variables' do
expect(described_class.to_cmd([".\\test.exe"] + ['$env:path'])).to eq(".\\test.exe '$env:path'")
end
it 'should not respect PowerShell Magic' do
expect(described_class.to_cmd([".\\test.exe"] + ['--%', 'not', '$parsed'])).to eq(".\\test.exe '--%' not '$parsed'")
end
it 'should not split comma args' do
expect(described_class.to_cmd([".\\test.exe"] + ['arg1,notarg2'])).to eq(".\\test.exe 'arg1,notarg2'")
end
it 'should handle empty strings' do
expect(described_class.to_cmd([".\\test.exe"] + ['', 'a', '', 'b'])).to eq(".\\test.exe '\"\"' a '\"\"' b")
end
end
end
+1 -1
View File
@@ -22,7 +22,7 @@ module Acceptance
def initialize
super
@default_timeout = ENV['CI'] ? 120 : 40
@default_timeout = ENV['CI'] ? 480 : 40
@debug = false
@env ||= {}
@cmd ||= []
+104 -115
View File
@@ -21,15 +21,42 @@ class MetasploitModule < Msf::Post
)
end
def upload_show_args_binary
def upload_show_args_binary(details)
print_status 'Uploading precompiled binaries'
upload_file(show_args_binary[:path], "data/cmd_exec/#{show_args_binary[:path]}")
upload_file(details[:upload_path], "data/cmd_exec/#{details[:path]}")
unless session.platform.eql?('windows')
chmod(show_args_binary[:path])
chmod(details[:upload_path])
end
end
def show_args_binary_space
result = show_args_binary_base
result[:upload_path] = result[:path].gsub('_',' ')
result[:cmd] = result[:cmd].gsub('_',' ')
result
end
def show_args_binary_special
result = show_args_binary_base
chars = '~!@#$%^&*(){}`\'"<>,.;:=?+|'
if session.platform == 'windows'
chars = '~!@#$%^&(){}`\',.;=+'
end
result[:upload_path] = result[:path].gsub('show_args', chars)
result[:cmd] = result[:cmd].gsub('show_args', chars)
result
end
def show_args_binary
result = show_args_binary_base
result[:upload_path] = result[:path]
result
end
def show_args_binary_base
if session.platform == 'linux' || session.platform == 'unix'
{ path: 'show_args_linux', cmd: './show_args_linux' }
elsif session.platform == 'osx'
@@ -40,9 +67,10 @@ class MetasploitModule < Msf::Post
{ path: 'show_args.exe', cmd: 'show_args.exe' }
elsif session.platform == 'windows' && session.arch == 'php'
{ path: 'show_args.exe', cmd: '.\\show_args.exe' }
elsif session.platform == 'windows' && session.arch == 'java'
{ path: 'show_args.exe', cmd: '.\\show_args.exe' }
elsif session.platform == 'windows'
{ path: 'show_args.exe', cmd: './show_args.exe' }
elsif session.type == 'meterpreter' && session.arch == 'java'
else
raise "unknown platform #{session.platform}"
end
@@ -56,7 +84,11 @@ class MetasploitModule < Msf::Post
# Match the binary name, to support the binary name containing relative or absolute paths, i.e.
# "show_args.exe\r\none\r\ntwo",
match = output_binary.match?(expected[0]) && output_args == expected[1..]
if output_binary.nil?
vprint_status("#{__method__}: Malformed output: no process binary returned")
return false
end
match = output_binary.include?(expected[0]) && output_args == expected[1..]
if !match
vprint_status("#{__method__}: expected: #{expected.inspect} - actual: #{output_lines.inspect}")
end
@@ -68,7 +100,7 @@ class MetasploitModule < Msf::Post
# we are inconsistent reporting windows session types
windows_strings = ['windows', 'win']
vprint_status("Starting cmd_exec tests")
upload_show_args_binary
upload_show_args_binary(show_args_binary)
it "should return the result of echo" do
test_string = Rex::Text.rand_text_alpha(4)
@@ -82,11 +114,6 @@ class MetasploitModule < Msf::Post
end
it 'should execute the show_args binary with a string' do
# TODO: Fix this functionality
if session.type.eql?('meterpreter') && session.arch.eql?('python')
vprint_status("test skipped for Python Meterpreter - functionality not correct")
next true
end
output = cmd_exec("#{show_args_binary[:cmd]} one two")
valid_show_args_response?(output, expected: [show_args_binary[:path], 'one', 'two'])
end
@@ -130,12 +157,8 @@ class MetasploitModule < Msf::Post
it "should return the result of echo with single quotes" do
test_string = Rex::Text.rand_text_alpha(4)
if session.platform.eql? 'windows'
if session.arch == ARCH_PYTHON
output = cmd_exec("cmd.exe", "/c echo \"#{test_string}\"")
output == test_string
# TODO: Fix this functionality
elsif session.type.eql?('shell') || session.type.eql?('powershell')
vprint_status("test skipped for Windows CMD and Powershell - functionality not correct")
if session.type.eql?('powershell')
vprint_status("test skipped for Powershell - functionality not correct")
true
else
output = cmd_exec("cmd.exe", "/c echo '#{test_string}'")
@@ -150,12 +173,8 @@ class MetasploitModule < Msf::Post
it "should return the result of echo with double quotes" do
test_string = Rex::Text.rand_text_alpha(4)
if session.platform.eql? 'windows'
if session.platform.eql? 'windows' and session.arch == ARCH_PYTHON
output = cmd_exec("cmd.exe", "/c echo \"#{test_string}\"")
output == test_string
# TODO: Fix this functionality
elsif session.type.eql?('shell') || session.type.eql?('powershell')
vprint_status("test skipped for Windows CMD and Powershell - functionality not correct")
if session.type.eql?('powershell')
vprint_status("test skipped for Powershell - functionality not correct")
true
else
output = cmd_exec("cmd.exe", "/c echo \"#{test_string}\"")
@@ -189,96 +208,66 @@ class MetasploitModule < Msf::Post
end
end
# TODO: These tests are in preparation for Smashery's create process API
# def test_create_process
# upload_show_args_binary
#
# test_string = Rex::Text.rand_text_alpha(4)
#
# it 'should accept blank strings and return the create_process output' do
# if session.arch.eql?("php")
# # TODO: Fix this functionality
#
# vprint_status("test skipped for PHP - functionality not correct")
# true
# end
# output = create_process(show_args_binary[:cmd], args: [test_string, '', test_string, '', test_string])
# valid_show_args_response?(output, expected: [show_args_binary[:path], test_string, '', test_string, '', test_string])
# end
#
# it 'should accept multiple args and return the create_process output' do
# output = create_process(show_args_binary[:cmd], args: [test_string, test_string])
# valid_show_args_response?(output, expected: [show_args_binary[:path], test_string, test_string])
# end
#
# it 'should accept spaces and return the create_process output' do
# output = create_process(show_args_binary[:cmd], args: ['with spaces'])
# valid_show_args_response?(output, expected: [show_args_binary[:path], 'with spaces'])
# end
#
# it 'should accept environment variables and return the create_process output' do
# output = create_process(show_args_binary[:cmd], args: ['$PATH'])
# valid_show_args_response?(output, expected: [show_args_binary[:path], '$PATH'])
# end
#
# it 'should accept environment variables within a string and return the create_process output' do
# output = create_process(show_args_binary[:cmd], args: ["it's $PATH"])
# valid_show_args_response?(output, expected: [show_args_binary[:path], "it's $PATH"])
# end
#
# it 'should accept special characters and return the create_process output' do
# if session.platform.eql? 'windows'
# # TODO: Fix this functionality
# vprint_status('test skipped for Windows - functionality not correct')
# true
# end
# output = create_process(show_args_binary[:cmd], args: ['~!@#$%^&*(){`1234567890[]",.\'<>'])
# valid_show_args_response?(output, expected: [show_args_binary[:path], '~!@#$%^&*(){`1234567890[]",.\'<>'])
# end
#
# it 'should accept command line commands and return the create_process output' do
# if session.arch.eql?("php")
# # TODO: Fix this functionality
# vprint_status("test skipped for PHP - functionality not correct")
# true
# end
#
# output = create_process(show_args_binary[:cmd], args: ['run&echo'])
# valid_show_args_response?(output, expected: [show_args_binary[:path], 'run&echo'])
# end
#
# it 'should accept semicolons to separate multiple command on a single line and return the create_process output' do
# if session.arch.eql?("php")
# # TODO: Fix this functionality
# vprint_status("test skipped for PHP - functionality not correct")
# true
# end
#
# output = create_process(show_args_binary[:cmd], args: ['run&echo;test'])
# valid_show_args_response?(output, expected: [show_args_binary[:path], 'run&echo;test'])
# end
#
# it 'should accept spaces in the filename and return the create_process output' do
# if session.platform.eql? 'windows'
# # TODO: Fix this functionality
# vprint_status('test skipped for Windows CMD - functionality not correct')
# true
# end
#
# output = create_process('./show_args file', args: [test_string, test_string])
# valid_show_args_response?(output, expected: ['./show_args file', test_string, test_string])
# end
#
# it 'should accept special characters in the filename and return the create_process output' do
# if session.platform.eql? 'windows'
# # TODO: Fix this functionality
# vprint_status('test skipped for Windows CMD - functionality not correct')
# true
# end
#
# output = create_process('./~!@#$%^&*(){}', args: [test_string, test_string])
# valid_show_args_response?(output, expected: ['./~!@#$%^&*(){}', test_string, test_string])
# end
# end
# end
def test_create_process
upload_show_args_binary(show_args_binary)
upload_show_args_binary(show_args_binary_space)
upload_show_args_binary(show_args_binary_special)
test_string = Rex::Text.rand_text_alpha(4)
it 'should accept blank strings and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: [test_string, '', test_string, '', test_string])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], test_string, '', test_string, '', test_string])
end
it 'should accept multiple args and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: [test_string, test_string])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], test_string, test_string])
end
it 'should accept spaces and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ['with spaces'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], 'with spaces'])
end
it 'should accept environment variables and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ['$PATH'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '$PATH'])
end
it 'should accept environment variables within a string and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ["it's $PATH"])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], "it's $PATH"])
end
it 'should deal with weird windows edge cases' do
output = create_process(show_args_binary[:cmd], args: ['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])
end
it 'should accept special characters and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ['~!@#$%^&*(){`1234567890[]",.\'<>\\'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '~!@#$%^&*(){`1234567890[]",.\'<>\\'])
end
it 'should accept command line commands and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ['run&echo'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], 'run&echo'])
end
it 'should accept semicolons to separate multiple command on a single line and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ['run&echo;test'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], 'run&echo;test'])
end
it 'should accept spaces in the filename and return the create_process output' do
output = create_process(show_args_binary_space[:cmd], args: [test_string, test_string])
valid_show_args_response?(output, expected: [show_args_binary_space[:cmd], test_string, test_string])
end
it 'should accept special characters in the filename and return the create_process output' do
output = create_process(show_args_binary_special[:cmd], args: [test_string, test_string])
valid_show_args_response?(output, expected: [show_args_binary_special[:cmd], test_string, test_string])
end
end
end