Class: Msf::Sessions::CommandShell

Inherits:
Object
  • Object
show all
Includes:
Msf::Session::Basic, Msf::Session::Provider::SingleCommandShell, Msf::Session::Scriptable
Defined in:
lib/msf/base/sessions/command_shell.rb

Overview

This class provides basic interaction with a command shell on the remote endpoint. This session is initialized with a stream that will be used as the pipe for reading and writing the command shell.

Direct Known Subclasses

CommandShellUnix, CommandShellWindows

Instance Attribute Summary collapse

Attributes included from Msf::Session::Interactive

#ring, #rstream

Attributes included from Rex::Ui::Interactive

#completed, #interacting, #on_command_proc, #on_print_proc

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, #routes, #sid, #sname, #target_host, #target_port, #username, #uuid, #workspace

Attributes included from Framework::Offspring

#framework

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Msf::Session::Scriptable

#execute_script, included

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

#set_shell_token_index, #shell_command_token, #shell_command_token_unix, #shell_command_token_win32, #shell_read_until_token

Methods included from Msf::Session::Interactive

#cleanup, #interactive?, #kill, #tunnel_local, #tunnel_peer

Methods included from Rex::Ui::Interactive

#detach, #interact

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_debug, #print_error, #print_good, #print_line, #print_status, #print_warning

Methods included from Msf::Session

#alive?, #cleanup, #dead?, #inspect, #interactive?, #kill, #log_file_name, #log_from_local, #log_from_remote, #log_source, #name, #name=, #register?, #session_host, #session_host=, #session_port, #session_port=, #set_from_exploit, #set_via, #tunnel_local, #tunnel_peer, #tunnel_to_s, #via_exploit, #via_payload

Constructor Details

#initialize(*args) ⇒ CommandShell

Returns a new instance of CommandShell


50
51
52
53
54
# File 'lib/msf/base/sessions/command_shell.rb', line 50

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

Instance Attribute Details

#archObject

Returns the value of attribute arch


236
237
238
# File 'lib/msf/base/sessions/command_shell.rb', line 236

def arch
  @arch
end

#platformObject

Returns the value of attribute platform


237
238
239
# File 'lib/msf/base/sessions/command_shell.rb', line 237

def platform
  @platform
end

Class Method Details

.typeObject

Returns the type of session.


46
47
48
# File 'lib/msf/base/sessions/command_shell.rb', line 46

def self.type
  "shell"
end

Instance Method Details

#descObject

Returns the session description.


59
60
61
# File 'lib/msf/base/sessions/command_shell.rb', line 59

def desc
  "Command shell"
end

#execute_file(full_path, args) ⇒ Object

:category: Msf::Session::Scriptable implementors

Executes the supplied script, must be specified as full path.

Msf::Session::Scriptable implementor


38
39
40
41
# File 'lib/msf/base/sessions/command_shell.rb', line 38

def execute_file(full_path, args)
  o = Rex::Script::Shell.new(self, full_path)
  o.run(args)
end

#process_autoruns(datastore) ⇒ Object

Execute any specified auto-run scripts for this session


204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/msf/base/sessions/command_shell.rb', line 204

def process_autoruns(datastore)
  # Read the initial output and mash it into a single line
  if (not self.info or self.info.empty?)
    initial_output = shell_read(-1, 0.01)
    if (initial_output)
      initial_output.force_encoding("ASCII-8BIT") if initial_output.respond_to?(:force_encoding)
      initial_output.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"_")
      initial_output.gsub!(/[\r\n\t]+/, ' ')
      initial_output.strip!

      # Set the inital output to .info
      self.info = initial_output
    end
  end

  if (datastore['InitialAutoRunScript'] && datastore['InitialAutoRunScript'].empty? == false)
    args = Shellwords.shellwords( datastore['InitialAutoRunScript'] )
    print_status("Session ID #{sid} (#{tunnel_to_s}) processing InitialAutoRunScript '#{datastore['InitialAutoRunScript']}'")
    execute_script(args.shift, *args)
  end

  if (datastore['AutoRunScript'] && datastore['AutoRunScript'].empty? == false)
    args = Shellwords.shellwords( datastore['AutoRunScript'] )
    print_status("Session ID #{sid} (#{tunnel_to_s}) processing AutoRunScript '#{datastore['AutoRunScript']}'")
    execute_script(args.shift, *args)
  end
end

#reset_ring_sequenceObject


232
233
234
# File 'lib/msf/base/sessions/command_shell.rb', line 232

def reset_ring_sequence
  self.ring_seq = 0
end

#run_cmd(cmd) ⇒ Object

Explicitly runs a command.


66
67
68
# File 'lib/msf/base/sessions/command_shell.rb', line 66

def run_cmd(cmd)
  shell_command(cmd)
end

#shell_closeObject

:category: Msf::Session::Provider::SingleCommandShell implementors

Closes the shell.


196
197
198
199
# File 'lib/msf/base/sessions/command_shell.rb', line 196

def shell_close()
  rstream.close rescue nil
  self.kill
end

#shell_command(cmd) ⇒ Object

:category: Msf::Session::Provider::SingleCommandShell implementors

Explicitly run a single command, return the output.


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/msf/base/sessions/command_shell.rb', line 91

def shell_command(cmd)
  # Send the command to the session's stdin.
  shell_write(cmd + "\n")

  timeo = 5
  etime = ::Time.now.to_f + timeo
  buff = ""

  # Keep reading data until no more data is available or the timeout is
  # reached.
  while (::Time.now.to_f < etime and (self.respond_to?(:ring) or ::IO.select([rstream], nil, nil, timeo)))
    res = shell_read(-1, 0.01)
    buff << res if res
    timeo = etime - ::Time.now.to_f
  end

  buff
end

#shell_initObject

:category: Msf::Session::Provider::SingleCommandShell implementors

The shell will have been initialized by default.


82
83
84
# File 'lib/msf/base/sessions/command_shell.rb', line 82

def shell_init
  return true
end

#shell_read(length = -1,, timeout = 1) ⇒ Object

:category: Msf::Session::Provider::SingleCommandShell implementors

Read from the command shell.


115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/msf/base/sessions/command_shell.rb', line 115

def shell_read(length=-1, timeout=1)
  return shell_read_ring(length,timeout) if self.respond_to?(:ring)

  begin
    rv = rstream.get_once(length, timeout)
    framework.events.on_session_output(self, rv) if rv
    return rv
  rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
    #print_error("Socket error: #{e.class}: #{e}")
    shell_close
    raise e
  end
end

#shell_read_ring(length = -1,, timeout = 1) ⇒ Object

Read from the command shell.


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/msf/base/sessions/command_shell.rb', line 132

def shell_read_ring(length=-1, timeout=1)
  self.ring_buff ||= ""

  # Short-circuit bad length values
  return "" if length == 0

  # Return data from the stored buffer if available
  if self.ring_buff.length >= length and length > 0
    buff = self.ring_buff.slice!(0,length)
    return buff
  end

  buff = self.ring_buff
  self.ring_buff = ""

  begin
    ::Timeout.timeout(timeout) do
      while( (length > 0 and buff.length < length) or (length == -1 and buff.length == 0))
        ring.select
        nseq,data = ring.read_data(self.ring_seq)
        if data
          self.ring_seq = nseq
          buff << data
        end
      end
    end
  rescue ::Timeout::Error
  rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
    shell_close
    raise e
  end

  # Store any leftovers in the ring buffer backlog
  if length > 0 and buff.length > length
    self.ring_buff = buff[length, buff.length - length]
    buff = buff[0,length]
  end

  buff
end

#shell_write(buf) ⇒ Object

:category: Msf::Session::Provider::SingleCommandShell implementors

Writes to the command shell.


178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/msf/base/sessions/command_shell.rb', line 178

def shell_write(buf)
  return if not buf

  begin
    framework.events.on_session_command(self, buf.strip)
    rstream.write(buf)
  rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE => e
    #print_error("Socket error: #{e.class}: #{e}")
    shell_close
    raise e
  end
end

#typeObject

Calls the class method.


73
74
75
# File 'lib/msf/base/sessions/command_shell.rb', line 73

def type
  self.class.type
end