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