Module: Msf::Sessions::WindowsEscaping
- Included in:
- CommandShellWindows, CommandShellWindows
- Defined in:
- lib/msf/base/sessions/windows_escaping.rb
Instance Method Summary collapse
-
#argv_to_commandline(args) ⇒ Object
Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.
-
#escape_arg(arg) ⇒ Object
Escape an individual argument per Windows shell rules.
-
#escape_cmd(executable) ⇒ Object
Escape a process for the command line.
- #shell_command_token(cmd, timeout = 10) ⇒ Object
- #space_chars ⇒ Object
-
#to_cmd(cmd_and_args) ⇒ Object
Convert the executable and argument array to a command that can be run in this command shell.
Instance Method Details
#argv_to_commandline(args) ⇒ Object
Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.
30 31 32 33 34 |
# File 'lib/msf/base/sessions/windows_escaping.rb', line 30 def argv_to_commandline(args) escaped_args = args.map { |arg| escape_arg(arg) } escaped_args.join(' ') end |
#escape_arg(arg) ⇒ Object
Escape an individual argument per Windows shell rules
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/msf/base/sessions/windows_escaping.rb', line 38 def escape_arg(arg) needs_quoting = space_chars.any? { |char| arg.include?(char) } # 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 |
#escape_cmd(executable) ⇒ Object
Escape a process for the command line
13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/msf/base/sessions/windows_escaping.rb', line 13 def escape_cmd(executable) needs_quoting = space_chars.any? do |char| executable.include?(char) end if needs_quoting executable = "\"#{executable}\"" end executable end |
#shell_command_token(cmd, timeout = 10) ⇒ Object
7 8 9 |
# File 'lib/msf/base/sessions/windows_escaping.rb', line 7 def shell_command_token(cmd,timeout = 10) shell_command_token_win32(cmd,timeout) end |
#space_chars ⇒ Object
3 4 5 |
# File 'lib/msf/base/sessions/windows_escaping.rb', line 3 def space_chars [' ', '\t', '\v'] end |
#to_cmd(cmd_and_args) ⇒ Object
Convert the executable and argument array to a command that can be run in this command shell
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/msf/base/sessions/windows_escaping.rb', line 63 def 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 |