metasploit-framework/lib/msf/ui/web/driver.rb

232 lines
3.9 KiB
Ruby
Raw Normal View History

require 'rex/proto/http'
require 'msf/core'
require 'msf/base'
require 'msf/ui'
module Msf
module Ui
module Web
require 'msf/ui/web/comm'
require 'rex/io/bidirectional_pipe'
###
#
# This class implements a console instance for use by the web interface
#
###
class WebConsole
attr_accessor :pipe
attr_accessor :console
attr_accessor :console_id
attr_accessor :last_access
attr_accessor :framework
attr_accessor :thread
class WebConsolePipe < Rex::IO::BidirectionalPipe
attr_accessor :input
attr_accessor :output
attr_accessor :prompt
attr_accessor :killed
def eof?
self.pipe_input.eof?
end
def intrinsic_shell?
true
end
def supports_readline
false
end
def _print_prompt
end
def pgets
self.pipe_input.gets
end
end
#
# Provides some overrides for web-based consoles
#
module WebConsoleShell
def supports_color?
false
end
end
def initialize(framework, console_id)
# Configure the framework
self.framework = framework
# Configure the ID
self.console_id = console_id
# Create a new pipe
self.pipe = WebConsolePipe.new
self.pipe.input = self.pipe.pipe_input
# Create a read subscriber
self.pipe.create_subscriber('msfweb')
# Initialize the console with our pipe
self.console = Msf::Ui::Console::Driver.new(
'msf',
'>',
{
'Framework' => self.framework,
'LocalInput' => self.pipe,
'LocalOutput' => self.pipe,
'AllowCommandPassthru' => false,
}
)
self.console.extend(WebConsoleShell)
self.thread = Thread.new { self.console.run }
update_access()
end
def update_access
self.last_access = Time.now
end
def read
update_access
self.pipe.read_subscriber('msfweb')
end
def write(buf)
update_access
self.pipe.write_input(buf)
end
def execute(cmd)
self.console.run_single(cmd)
end
def prompt
self.pipe.prompt
end
def tab_complete(cmd)
self.console.tab_complete(cmd)
end
def shutdown
self.pipe.killed = true
self.pipe.close
self.thread.kill
end
end
###
#
# This class implements a user interface driver on a web interface.
#
###
class Driver < Msf::Ui::Driver
attr_accessor :framework # :nodoc:
attr_accessor :consoles # :nodoc:
attr_accessor :last_console # :nodoc:
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/web"
#
# Initializes a web driver instance and prepares it for listening to HTTP
# requests. The constructor takes a hash of options that can control how
# the web server will operate.
#
def initialize(opts = {})
# Call the parent
super()
# Set the passed options hash for referencing later on.
self.opts = opts
# Initalize the consoles set
self.consoles = {}
# Initialize configuration
Msf::Config.init
# Initialize logging
initialize_logging
# Initialize attributes
self.framework = Msf::Simple::Framework.create
# Initialize the console count
self.last_console = 0
# Give the comm an opportunity to set up so that it can receive
# notifications about session creation and so on.
Comm.setup(framework)
end
def create_console
# Destroy any unused consoles
clean_consoles
console = WebConsole.new(self.framework, self.last_console)
self.last_console += 1
self.consoles[console.console_id.to_s] = console
console.console_id.to_s
end
def write_console(id, buf)
self.consoles[id] ? self.consoles.write(buf) : nil
end
def read_console(id)
self.consoles[id] ? self.consoles.read() : nil
end
def clean_consoles(timeout=300)
self.consoles.each_pair do |id, con|
if (con.last_access + timeout < Time.now)
con.shutdown
self.consoles.delete(id)
end
end
end
#
# Stub
#
def run
true
end
protected
attr_accessor :opts # :nodoc:
#
# Initializes logging for the web interface
#
def initialize_logging
level = (opts['LogLevel'] || 0).to_i
Msf::Logging.enable_log_source(LogSource, level)
end
end
end
end
end