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

248 lines
5.2 KiB
Ruby

require 'rex/proto/http'
require 'msf/core'
require 'msf/base'
require 'msf/ui'
module Msf
module Ui
module Web
require 'msf/ui/web/comm'
###
#
# This class implements a user interface driver on a web interface.
#
###
class Driver < Msf::Ui::Driver
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/web"
@@Eid = 0
#
# Returns the next unique exploit identifier.
#
def self.next_eid
@@Eid += 1
@@Eid.to_s
end
#
# The msfweb resource handler that wrappers the default Erb handler.
#
class ResourceHandler < Rex::Proto::Http::Handler::Erb
def initialize(server, root_path, framework, driver, opts = {})
opts['ErbCallback'] = ::Proc.new { |erb, cli, request, response|
query_string = request.qstring
meta_vars = request.meta_vars
erb.result(binding)
}
super(server, root_path, opts)
self.framework = framework
self.driver = driver
end
attr_accessor :framework # :nodoc:
attr_accessor :driver # :nodoc:
end
#
# The default port to listen for HTTP requests on.
#
DefaultPort = 55555
#
# The default host to listen for HTTP requests on.
#
DefaultHost = "127.0.0.1"
#
# The default root directory for requests.
#
DefaultRoot = "/"
#
# The default local directory for msfweb.
#
DefaultLocalDirectory = Msf::Config.data_directory + File::SEPARATOR + "msfweb"
#
# The default index script.
#
DefaultIndex = "index.rhtml"
#
# 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
# Initialize configuration
Msf::Config.init
# Initialize logging
initialize_logging
# Initialize attributes
self.framework = Msf::Simple::Framework.create
# Initialize the termination event.
self.term_event = Rex::Sync::Event.new
# Include common helper stuff. If there is no common stuff to be
# included, then we'll just catch the exception and move on with our
# life.
begin
if ($:.include?(server_local_directory) == false)
$:.unshift(server_local_directory)
require 'msfweb_common'
end
rescue
end
end
#
# Starts the HTTP server and waits for termination.
#
def run
self.service = Rex::ServiceManager.start(Rex::Proto::Http::Server,
port = (opts['ServerPort'] || DefaultPort).to_i,
host = (opts['ServerHost'] || DefaultHost))
ilog("Web server started on #{host}:#{port}", LogSource)
# Mount the server root directory on the web server instance. We pass
# it a custom ErbCallback so that we can have it run in a context that
# has the framework instance defined.
service.mount(
server_root,
ResourceHandler,
false,
server_local_directory,
framework,
self)
# Add a resource that will be responsible for waiting for channels to
# have input that needs to be read from and written back to http
# clients. Since this call will block for an extended period of time,
# we set the long call flag to cause it to run in the context of a
# thread.
service.add_resource("/internal/comm_read",
'Proc' => Proc.new { |client, request|
begin
Comm.read_channels(client, request)
rescue ::Exception
dlog("comm_read: #{$!}")
end
},
'LongCall' => true)
# Add a resource for writing to channels.
service.add_resource("/internal/comm_write",
'Proc' => Proc.new { |client, request|
begin
Comm.write_channel(client, request)
rescue ::Exception
dlog("comm_write: #{$!}")
end
})
# Add a resource that will be used to create a channel for a given
# resource.
service.add_resource("/internal/comm_create",
'Proc' => Proc.new { |client, request|
begin
Comm.create_channel(client, request)
rescue ::Exception
dlog("comm_create: #{$!}")
end
})
# Give the comm an opportunity to set up so that it can receive
# notifications about session creation and so on.
Comm.setup(framework)
# Wait for the termination event to be set.
term_event.wait
# Stop the source and clean it up.
Rex::ServiceManager.stop_service(service)
service.deref
true
end
#
# Sets the event that will cause the web service to terminate.
#
def terminate
term_event.set
end
#
# Returns the root resource name, such as '/msfweb'.
#
def server_root
opts['ServerRoot'] || DefaultRoot
end
#
# Returns the server index, such as 'index.rhtml'.
#
def server_index
opts['ServerIndex'] || DefaultIndex
end
#
# Returns the local directory that will hold the files to be serviced.
#
def server_local_directory
opts['ServerLocalDirectory'] || DefaultLocalDirectory
end
#
# The framework instance associated with this driver.
#
attr_reader :framework
protected
attr_writer :framework # :nodoc:
attr_accessor :opts # :nodoc:
#
# The internal event used to cause the web service to stop.
#
attr_accessor :term_event
#
# The internal service context.
#
attr_accessor :service
#
# Initializes logging for the web server.
#
def initialize_logging
level = (opts['LogLevel'] || 0).to_i
Msf::Logging.enable_log_source(LogSource, level)
end
end
end
end
end