Class: Msf::Sessions::CommandShellWindows

Inherits:
CommandShell show all
Defined in:
lib/msf/base/sessions/command_shell_windows.rb

Instance Attribute Summary

Attributes inherited from CommandShell

#arch, #banner, #max_threads, #platform

Attributes included from Msf::Session::Interactive

#rstream

Attributes included from Rex::Ui::Interactive

#completed, #interacting, #next_session, #on_command_proc, #on_print_proc, #on_run_command_error_proc, #orig_suspend, #orig_usr1, #orig_winch

Attributes included from Rex::Ui::Subscriber::Input

#user_input

Attributes included from Rex::Ui::Subscriber::Output

#user_output

Attributes included from Msf::Session

#alive, #db_record, #exploit, #exploit_datastore, #exploit_task, #exploit_uuid, #framework, #info, #machine_id, #payload_uuid, #routes, #sid, #sname, #target_host, #target_port, #username, #uuid, #via, #workspace

Attributes included from Framework::Offspring

#framework

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from CommandShell

#_file_transfer, _glue_cmdline_escape, #_interact, #_interact_stream, #abort_foreground_supported, binary_exists, #binary_exists, #bootstrap, can_cleanup_files, #cleanup, #cmd_background, #cmd_background_help, #cmd_download, #cmd_download_help, #cmd_help, #cmd_help_help, #cmd_irb, #cmd_irb_help, #cmd_pry, #cmd_pry_help, #cmd_resource, #cmd_resource_help, #cmd_sessions, #cmd_sessions_help, #cmd_shell, #cmd_shell_help, #cmd_source, #cmd_source_help, #cmd_upload, #cmd_upload_help, #commands, #desc, #docs_dir, #execute_file, #process_autoruns, #run_builtin_cmd, #run_single, #shell_close, #shell_command, #shell_init, #shell_read, #shell_write, type, #type

Methods included from Rex::Ui::Text::Resource

#load_resource

Methods included from Scriptable

#execute_file, #execute_script, included, #legacy_script_to_post_module

Methods included from Msf::Session::Provider::SingleCommandShell

#command_termination, #set_is_echo_shell, #shell_close, #shell_command_token_base, #shell_command_token_unix, #shell_command_token_win32, #shell_init, #shell_read, #shell_read_until_token, #shell_write

Methods included from Msf::Session::Basic

#_interact, #desc, #type

Methods included from Msf::Session::Interactive

#_interact, #_interact_complete, #_interrupt, #_suspend, #_usr1, #abort_foreground, #abort_foreground_supported, #cleanup, #comm_channel, #interactive?, #kill, #run_cmd, #tunnel_local, #tunnel_peer, #user_want_abort?

Methods included from Rex::Ui::Interactive

#_interact, #_interact_complete, #_interrupt, #_local_fd, #_remote_fd, #_stream_read_local_write_remote, #_stream_read_remote_write_local, #_suspend, #_winch, #detach, #handle_suspend, #handle_usr1, #handle_winch, #interact, #interact_stream, #prompt, #prompt_yesno, #restore_suspend, #restore_usr1, #restore_winch

Methods included from Rex::Ui::Subscriber

#copy_ui, #init_ui, #reset_ui

Methods included from Rex::Ui::Subscriber::Input

#gets

Methods included from Rex::Ui::Subscriber::Output

#flush, #print, #print_blank_line, #print_error, #print_good, #print_line, #print_status, #print_warning

Methods included from Msf::Session

#alive?, #cleanup, #comm_channel, #dead?, #desc, #inspect, #interactive?, #kill, #log_file_name, #log_source, #name, #name=, #register?, #session_host, #session_host=, #session_port, #session_port=, #session_type, #set_from_exploit, #set_via, #tunnel_local, #tunnel_peer, #tunnel_to_s, type, #type, #via_exploit, #via_payload

Constructor Details

#initialize(*args) ⇒ CommandShellWindows

Returns a new instance of CommandShellWindows.



4
5
6
7
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 4

def initialize(*args)
  self.platform = "windows"
  super
end

Class Method Details

.argv_to_commandline(args) ⇒ Object

Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.

Parameters:

  • args (Array<String>)

    The arguments to the process



42
43
44
45
46
47
48
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 42

def self.argv_to_commandline(args)
  escaped_args = args.map do |arg|
    escape_arg(arg)
  end

  escaped_args.join(' ')
end

.escape_arg(arg) ⇒ Object

Escape an individual argument per Windows shell rules

Parameters:

  • arg (String)

    Shell argument



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 52

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

.escape_cmd(executable) ⇒ Object

Escape a process for the command line

Parameters:

  • executable (String)

    The process to launch



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 25

def self.escape_cmd(executable)
  needs_quoting = space_chars.any? do |char|
    executable.include?(char)
  end

  if needs_quoting
    executable = "\"#{executable}\""
  end

  executable
end

.space_charsObject



9
10
11
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 9

def self.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

Parameters:

  • cmd_and_args (Array<String>)

    The process path and the arguments to the process



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 79

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

Instance Method Details

#shell_command_token(cmd, timeout = 10) ⇒ Object



13
14
15
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 13

def shell_command_token(cmd,timeout = 10)
  shell_command_token_win32(cmd,timeout)
end

#to_cmd(cmd_and_args) ⇒ Object

Convert the executable and argument array to a command that can be run in this command shell

Parameters:

  • cmd_and_args (Array<String>)

    The process path and the arguments to the process



19
20
21
# File 'lib/msf/base/sessions/command_shell_windows.rb', line 19

def to_cmd(cmd_and_args)
  self.class.to_cmd(cmd_and_args)
end