Class: Msf::Sessions::WinrmCommandShell::WinRMStreamAdapter
- Inherits:
-
Object
- Object
- Msf::Sessions::WinrmCommandShell::WinRMStreamAdapter
- Defined in:
- lib/msf/base/sessions/winrm_command_shell.rb
Overview
Abstract WinRM to look like a stream so CommandShell can be happy
Instance Attribute Summary collapse
-
#interactive_command_id ⇒ Object
rubocop:enable Lint/SuppressedException.
-
#keep_alive_thread ⇒ Object
rubocop:enable Lint/SuppressedException.
-
#on_shell_ended ⇒ Object
rubocop:enable Lint/SuppressedException.
-
#shell ⇒ Object
rubocop:enable Lint/SuppressedException.
Instance Method Summary collapse
- #_get_once(length) ⇒ Object
-
#close ⇒ Object
Close the shell; cleanly terminating it on the server if possible.
-
#get_once(length = -1,, timeout = 1) ⇒ Object
:category: Msf::Session::Provider::SingleCommandShell implementors.
-
#initialize(shell, interactive_command_id, on_shell_ended) ⇒ WinRMStreamAdapter
constructor
A new instance of WinRMStreamAdapter.
- #localinfo ⇒ Object
- #peerinfo ⇒ Object
-
#refresh_stdout ⇒ Object
Trigger the background thread to go get more stdout.
-
#start_keep_alive_loop(framework) ⇒ Object
Start a background thread for regularly checking for stdout.
-
#stop_keep_alive_loop ⇒ Object
Stop the background thread.
- #write(buf) ⇒ Object
Constructor Details
#initialize(shell, interactive_command_id, on_shell_ended) ⇒ WinRMStreamAdapter
Returns a new instance of WinRMStreamAdapter.
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 17 def initialize(shell, interactive_command_id, on_shell_ended) # To buffer input received while a session is backgrounded, we stick responses in a list @buffer_mutex = Mutex.new @buffer = [] @check_stdin_event = Rex::Sync::Event.new(false, true) @received_stdout_event = Rex::Sync::Event.new(false, true) self.interactive_command_id = interactive_command_id self.shell = shell self.on_shell_ended = on_shell_ended end |
Instance Attribute Details
#interactive_command_id ⇒ Object
rubocop:enable Lint/SuppressedException
156 157 158 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 156 def interactive_command_id @interactive_command_id end |
#keep_alive_thread ⇒ Object
rubocop:enable Lint/SuppressedException
156 157 158 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 156 def keep_alive_thread @keep_alive_thread end |
#on_shell_ended ⇒ Object
rubocop:enable Lint/SuppressedException
156 157 158 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 156 def on_shell_ended @on_shell_ended end |
#shell ⇒ Object
rubocop:enable Lint/SuppressedException
156 157 158 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 156 def shell @shell end |
Instance Method Details
#_get_once(length) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 74 def _get_once(length) result = '' @buffer_mutex.synchronize do result = @buffer.join('') @buffer = [] if (length > -1) && (result.length > length) # Return up to length, and keep the rest in the buffer extra = result[length..-1] result = result[0, length] @buffer << extra end end result end |
#close ⇒ Object
Close the shell; cleanly terminating it on the server if possible
The shell may already be dead, or unreachable at this point, so do a best effort, and capture exceptions rubocop:disable Lint/SuppressedException
149 150 151 152 153 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 149 def close stop_keep_alive_loop shell.cleanup_command(interactive_command_id) rescue WinRM::WinRMWSManFault end |
#get_once(length = -1,, timeout = 1) ⇒ Object
:category: Msf::Session::Provider::SingleCommandShell implementors
Read from the command shell.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 51 def get_once(length = -1, timeout = 1) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) result = '' loop do result = _get_once(length) time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) elapsed = time - start_time time_remaining = timeout - elapsed break if (result != '' || time_remaining <= 0) # rubocop:disable Lint/SuppressedException begin # We didn't receive anything - let's wait for some more @received_stdout_event.wait(time_remaining) rescue ::Timeout::Error end # rubocop:enable Lint/SuppressedException # If we didn't get anything, let's hurry the background thread along refresh_stdout unless result end result end |
#localinfo ⇒ Object
32 33 34 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 32 def localinfo shell.transport.localinfo end |
#peerinfo ⇒ Object
28 29 30 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 28 def peerinfo shell.transport.peerinfo end |
#refresh_stdout ⇒ Object
Trigger the background thread to go get more stdout
37 38 39 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 37 def refresh_stdout @check_stdin_event.set end |
#start_keep_alive_loop(framework) ⇒ Object
Start a background thread for regularly checking for stdout
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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 90 def start_keep_alive_loop(framework) self.keep_alive_thread = framework.threads.spawn('WinRM-shell-keepalive', false, shell) do |_thr_shell| loop_delay = 0.5 loop do tmp_buffer = [] output_seen = false shell.read_stdout(interactive_command_id) do |stdout, stderr| if stdout || stderr output_seen = true end tmp_buffer << stdout if stdout tmp_buffer << stderr if stderr end @buffer_mutex.synchronize do @buffer.concat(tmp_buffer) end # If our last request received stdout, let's be ready for some more if output_seen @received_stdout_event.set loop_delay = 0.5 else # Gradual backoff loop_delay *= 4 loop_delay = [loop_delay, 30].min end # Wait loop_delay seconds, or until an interactive thread wakes us up begin @check_stdin_event.wait(loop_delay) # rubocop:disable Lint/SuppressedException rescue ::Timeout::Error end # rubocop:enable Lint/SuppressedException Thread.pass rescue WinRM::WinRMWSManFault => e print_error(e.fault_description) on_shell_ended.call rescue EOFError # Shell has been terminated on_shell_ended.call rescue Rex::HostUnreachable => e on_shell_ended.call(e.) rescue StandardError => e on_shell_ended.call(e.) end end end |
#stop_keep_alive_loop ⇒ Object
Stop the background thread
140 141 142 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 140 def stop_keep_alive_loop keep_alive_thread.kill end |
#write(buf) ⇒ Object
41 42 43 44 |
# File 'lib/msf/base/sessions/winrm_command_shell.rb', line 41 def write(buf) shell.send_stdin(buf, interactive_command_id) refresh_stdout end |