Files
metasploit-gs/lib/msf/base/sessions/command_shell.rb
T

218 lines
4.3 KiB
Ruby
Raw Normal View History

require 'msf/base'
require 'msf/base/sessions/scriptable'
module Msf
module Sessions
###
2010-02-23 07:12:54 +00:00
#
# 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.
#
###
class CommandShell
#
# This interface supports basic interaction.
#
include Msf::Session::Basic
#
# This interface supports interacting with a single command shell.
#
include Msf::Session::Provider::SingleCommandShell
include Msf::Session::Scriptable
2005-11-15 15:11:43 +00:00
#
# Executes the supplied script, must be specified as full path.
2005-11-15 15:11:43 +00:00
#
# Msf::Session::Scriptable implementor
#
def execute_file(full_path, args)
o = Rex::Script::Shell.new(self, full_path)
o.run(args)
2005-07-19 14:33:25 +00:00
end
2010-02-24 01:19:59 +00:00
#
# Returns the type of session.
2010-02-24 01:19:59 +00:00
#
def self.type
"shell"
2010-02-24 01:19:59 +00:00
end
def initialize(*args)
self.platform ||= ""
self.arch ||= ""
super
end
2010-02-24 01:19:59 +00:00
2005-11-15 15:11:43 +00:00
#
# Returns the session description.
#
2005-07-16 08:12:58 +00:00
def desc
2005-07-16 16:06:44 +00:00
"Command shell"
2005-07-16 08:12:58 +00:00
end
2010-02-24 01:19:59 +00:00
#
# Explicitly runs a command.
#
def run_cmd(cmd)
2010-02-24 01:19:59 +00:00
shell_command(cmd)
end
2010-02-24 01:19:59 +00:00
2005-11-15 15:11:43 +00:00
#
# Calls the class method.
#
2005-07-16 08:12:58 +00:00
def type
2005-07-19 14:33:25 +00:00
self.class.type
2005-07-16 08:12:58 +00:00
end
#
2005-11-15 15:11:43 +00:00
# The shell will have been initialized by default.
#
2010-02-24 01:19:59 +00:00
def shell_init
return true
end
2010-02-24 01:19:59 +00:00
#
# Explicitly run a single command, return the output.
#
def shell_command(cmd)
# Send the command to the session's stdin.
2010-02-24 01:19:59 +00:00
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 ::IO.select([rstream], nil, nil, timeo))
res = shell_read(-1, 0.01)
buff << res if res
timeo = etime - ::Time.now.to_f
2010-02-24 01:19:59 +00:00
end
buff
2010-02-24 01:19:59 +00:00
end
#
2005-11-15 15:11:43 +00:00
# Read from the command shell.
#
def shell_read(length=-1, timeout=1)
begin
rv = rstream.get_once(length, timeout)
framework.events.on_session_output(self, rv) if rv
return rv
rescue ::Exception => e
shell_close
raise e
end
end
#
2005-11-15 15:11:43 +00:00
# Writes to the command shell.
#
2010-02-24 01:19:59 +00:00
def shell_write(buf)
return if not buf
begin
framework.events.on_session_command(self, buf.strip)
rstream.write(buf)
rescue ::Exception => e
shell_close
raise e
end
end
#
2005-11-15 15:11:43 +00:00
# Closes the shell.
#
2010-02-24 01:19:59 +00:00
def shell_close()
rstream.close rescue nil
self.kill
end
#
# Execute any specified auto-run scripts for this session
#
def process_autoruns(datastore)
# Read the initial output and mash it into a single line
2010-03-16 15:20:48 +00:00
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,"_")
2010-03-16 15:20:48 +00:00
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 = datastore['InitialAutoRunScript'].split
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 = datastore['AutoRunScript'].split
print_status("Session ID #{sid} (#{tunnel_to_s}) processing AutoRunScript '#{datastore['AutoRunScript']}'")
execute_script(args.shift, *args)
end
end
attr_accessor :arch
attr_accessor :platform
protected
# Override the basic session interaction to use shell_read and
# shell_write instead of operating on rstream directly.
def _interact
framework.events.on_session_interact(self)
fds = [rstream.fd, user_input.fd]
while self.interacting
sd = Rex::ThreadSafe.select(fds, nil, fds, 0.5)
next if not sd
if sd[0].include? rstream.fd
user_output.print(shell_read)
end
if sd[0].include? user_input.fd
shell_write(user_input.gets)
end
end
end
end
class CommandShellWindows < CommandShell
def initialize(*args)
self.platform = "windows"
super
end
def shell_command_token(cmd,timeout = 10)
shell_command_token_win32(cmd,timeout)
end
end
class CommandShellUnix < CommandShell
def initialize(*args)
self.platform = "unix"
super
end
def shell_command_token(cmd,timeout = 10)
shell_command_token_unix(cmd,timeout)
end
end
end
end