Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/base/sessions/command_shell_windows.rb
Views: 11784
module Msf::Sessions12class CommandShellWindows < CommandShell3def initialize(*args)4self.platform = "windows"5super6end78def self.space_chars9[' ', '\t', '\v']10end1112def shell_command_token(cmd,timeout = 10)13shell_command_token_win32(cmd,timeout)14end1516# Convert the executable and argument array to a command that can be run in this command shell17# @param cmd_and_args [Array<String>] The process path and the arguments to the process18def to_cmd(cmd_and_args)19self.class.to_cmd(cmd_and_args)20end2122# Escape a process for the command line23# @param executable [String] The process to launch24def self.escape_cmd(executable)25needs_quoting = space_chars.any? do |char|26executable.include?(char)27end2829if needs_quoting30executable = "\"#{executable}\""31end3233executable34end3536# Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.37# @param args [Array<String>] The arguments to the process38# @remark The difference between this and `to_cmd` is that the output of `to_cmd` is expected to be passed39# to cmd.exe, whereas this is expected to be passed directly to the Win32 API, anticipating that it40# will in turn be interpreted by CommandLineToArgvW.41def self.argv_to_commandline(args)42escaped_args = args.map do |arg|43escape_arg(arg)44end4546escaped_args.join(' ')47end4849# Escape an individual argument per Windows shell rules50# @param arg [String] Shell argument51def self.escape_arg(arg)52needs_quoting = space_chars.any? do |char|53arg.include?(char)54end5556# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote57# We need to send double the number of backslashes to make it work as expected58# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks59arg = arg.gsub(/(\\*)"/, '\\1\\1"')6061# Quotes need to be escaped62arg = arg.gsub('"', '\\"')6364if needs_quoting65# At the end of the argument, we're about to add another quote - so any backslashes need to be doubled here too66arg = arg.gsub(/(\\*)$/, '\\1\\1')67arg = "\"#{arg}\""68end6970# Empty string needs to be coerced to have a value71arg = '""' if arg == ''7273arg74end7576# Convert the executable and argument array to a command that can be run in this command shell77# @param cmd_and_args [Array<String>] The process path and the arguments to the process78def self.to_cmd(cmd_and_args)79# The space, caret and quote chars need to be inside double-quoted strings.80# The percent character needs to be escaped using a caret char, while being outside a double-quoted string.81#82# Situations where these two situations combine are going to be the trickiest cases: something that has quote-requiring83# characters (e.g. spaces), but which also needs to avoid expanding an environment variable. In this case,84# the string needs to end up being partially quoted; with parts of the string in quotes, but others (i.e. bits with percents) not.85# For example:86# 'env var is %temp%, yes, %TEMP%' needs to end up as '"env var is "^%temp^%", yes, "^%TEMP^%'87#88# There is flexibility in how you might implement this, but I think this one looks the most "human" to me,89# which would make it less signaturable.90#91# To do this, we'll consider each argument character-by-character. Each time we encounter a percent sign, we break out of any quotes92# (if we've been inside them in the current "token"), and then start a new "token".9394quote_requiring = ['"', '^', ' ', "\t", "\v", '&', '<', '>', '|']9596escaped_cmd_and_args = cmd_and_args.map do |arg|97# Escape quote chars by doubling them up, except those preceeded by a backslash (which are already effectively escaped, and handled below)98arg = arg.gsub(/([^\\])"/, '\\1""')99arg = arg.gsub(/^"/, '""')100101result = CommandShell._glue_cmdline_escape(arg, quote_requiring, '%', '^%', '"')102103# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote104# We need to send double the number of backslashes to make it work as expected105# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks106result.gsub!(/(\\*)"/, '\\1\\1"')107108# Empty string needs to be coerced to have a value109result = '""' if result == ''110111result112end113114escaped_cmd_and_args.join(' ')115end116end117118end119120121