From 22542607cfe7f1e5af7a439c1b15e053bdab43a4 Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Tue, 22 Nov 2005 03:20:09 +0000 Subject: [PATCH] very basic start to msfweb git-svn-id: file:///home/svn/incoming/trunk@3056 4d416f70-5f16-0410-b530-b9f4589650da --- lib/msf/base/logging.rb | 4 +- lib/msf/ui.rb | 1 + lib/msf/ui/web.rb | 14 +++ lib/msf/ui/web/driver.rb | 135 +++++++++++++++++++++++++++ lib/msf/ui/web/request_dispatcher.rb | 108 +++++++++++++++++++++ lib/rex/logging/log_dispatcher.rb | 4 +- lib/rex/proto/http/request.rb | 2 +- msfweb | 38 ++++++++ plugins/sample.rb | 25 ++++- 9 files changed, 323 insertions(+), 8 deletions(-) create mode 100644 lib/msf/ui/web.rb create mode 100644 lib/msf/ui/web/driver.rb create mode 100644 lib/msf/ui/web/request_dispatcher.rb create mode 100755 msfweb diff --git a/lib/msf/base/logging.rb b/lib/msf/base/logging.rb index 02b1abf986..90bb46ef1b 100644 --- a/lib/msf/base/logging.rb +++ b/lib/msf/base/logging.rb @@ -34,11 +34,11 @@ class Logging # # Enables a log source. # - def self.enable_log_source(src) + def self.enable_log_source(src, level = 0) f = Rex::Logging::Sinks::Flatfile.new( Msf::Config.log_directory + File::SEPARATOR + "#{src}.log") - register_log_source(src, f) + register_log_source(src, f, level) end # diff --git a/lib/msf/ui.rb b/lib/msf/ui.rb index 09958df6a7..cf2e532cc0 100644 --- a/lib/msf/ui.rb +++ b/lib/msf/ui.rb @@ -7,3 +7,4 @@ require 'rex/ui' require 'msf/ui/banner' require 'msf/ui/driver' require 'msf/ui/console' +require 'msf/ui/web' diff --git a/lib/msf/ui/web.rb b/lib/msf/ui/web.rb new file mode 100644 index 0000000000..d9e294aeba --- /dev/null +++ b/lib/msf/ui/web.rb @@ -0,0 +1,14 @@ +module Msf +module Ui +module Web + +# +# The log source used by the web service. +# +LogSource = "msfweb" + +end +end +end + +require 'msf/ui/web/driver' diff --git a/lib/msf/ui/web/driver.rb b/lib/msf/ui/web/driver.rb new file mode 100644 index 0000000000..1e289d91de --- /dev/null +++ b/lib/msf/ui/web/driver.rb @@ -0,0 +1,135 @@ +require 'msf/core' +require 'msf/base' +require 'msf/ui' +require 'msf/ui/web/request_dispatcher' + +module Msf +module Ui +module Web + + +### +# +# This class implements a user interface driver on a web interface. +# +### +class Driver < Msf::Ui::Driver + + include RequestDispatcher + + ConfigCore = "framework/core" + ConfigGroup = "framework/ui/web" + + # + # 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 = "/msfweb" + + # + # 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 logging + initialize_logging + + # Initialize attributes + self.framework = Msf::Simple::Framework.create + + # Initialize the termination event. + self.term_event = Rex::Sync::Event.new + 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) + + service.add_resource( + opts['ServerRoot'] || DefaultRoot, + 'Proc' => Proc.new { |cli, req| + on_request(cli, req) + }) + + # 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 + + # + # 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 + + # + # Called when an HTTP request comes in from a client that needs to be + # dispatched. + # + def on_request(cli, req) + dispatch_request(cli, req) + end + +end + +end +end +end diff --git a/lib/msf/ui/web/request_dispatcher.rb b/lib/msf/ui/web/request_dispatcher.rb new file mode 100644 index 0000000000..6f4aacf2ce --- /dev/null +++ b/lib/msf/ui/web/request_dispatcher.rb @@ -0,0 +1,108 @@ +module Msf +module Ui +module Web + +### +# +# This module takes a web request and processes it. +# +### +module RequestDispatcher + + # + # Dispatch the supplied request. + # + def dispatch_request(cli, req) + qstring = req.qstring || {} + + dlog("#{cli.peerhost}: Processing request cat=#{qstring['cat']} m=#{qstring['m']}.", + LogSource) + + case qstring['cat'] + when "e" # exploits + dispatch_exploit_req(cli, req, qstring) + when "p" # payloads + dispatch_payload_req(cli, req, qstring) + when "s" # sessions + dispatch_session_req(cli, req, qstring) + end + end + + ## + # + # Exploit-related request dispatching. + # + ## + + # + # Dispatch an exploit request based on the particular method that was + # specified. + # + def dispatch_exploit_req(cli, req, qstring) + case qstring['m'] + when "lst" + send_exploit_list(cli, req, qstring) + end + end + + # + # Transmits the exploit list to the client. + # + def send_exploit_list(cli, req, qstring) + body = "" + + framework.exploits.each_module { |name, mod| + inst = mod.new + + body += "" + } + + body += "
#{name}#{inst.name}
" + + send_ok(cli, body) + end + + ## + # + # Payload-related request dispatching. + # + ## + + # + # Dispatch a payload request based on the particular method that was + # specified. + # + def dispatch_payload_req(cli, req, qstring) + end + + ## + # + # Session-related request dispatching. + # + ## + + # + # Dispatch a session request based on the particular method that was + # specified. + # + def dispatch_session_req(cli, req, qstring) + end + +protected + + # + # Transmits the supplied body in a 200/OK response to the client. + # + def send_ok(cli, body) + resp = Rex::Proto::Http::Response::OK.new + + resp.body = body + + cli.send_response(resp) + end + +end + +end +end +end diff --git a/lib/rex/logging/log_dispatcher.rb b/lib/rex/logging/log_dispatcher.rb index 800ffe2089..de201202c2 100644 --- a/lib/rex/logging/log_dispatcher.rb +++ b/lib/rex/logging/log_dispatcher.rb @@ -153,8 +153,10 @@ def rlog(msg, src = 'core', level = 0, from = caller) $dispatcher.log(LOG_RAW, src, level, msg, from) end -def register_log_source(src, sink) +def register_log_source(src, sink, level = nil) $dispatcher[src] = sink + + set_log_level(src, level) if (level) end def deregister_log_source(src) diff --git a/lib/rex/proto/http/request.rb b/lib/rex/proto/http/request.rb index 042e6eb584..66f18bdd96 100644 --- a/lib/rex/proto/http/request.rb +++ b/lib/rex/proto/http/request.rb @@ -136,7 +136,7 @@ protected var = vv val = '' - if (md = vv.match(/(.+?)=(.+?)/)) + if (md = vv.match(/(.+?)=(.*)/)) var = md[1] val = md[2] end diff --git a/msfweb b/msfweb new file mode 100755 index 0000000000..5c5f16ae03 --- /dev/null +++ b/msfweb @@ -0,0 +1,38 @@ +#!/usr/bin/ruby + +$:.unshift(File.join(File.dirname(__FILE__), '../lib')) + +require 'rex' +require 'msf/ui' + +# Declare the argument parser for msfweb +arguments = Rex::Parser::Arguments.new( + "-a" => [ true, "Bind to this IP address instead of loopback" ], + "-p" => [ true, "Bind to this port instead of 55555" ], + "-v" => [ true, "A number between 0 and 3 that controls log verbosity" ], + "-h" => [ false, "Help banner" ]) + +opts = {} + +# Parse command line arguments. +arguments.parse(ARGV) { |opt, idx, val| + case opt + when "-a" + opts['ServerHost'] = val + when "-p" + opts['ServerPort'] = val + when "-v" + opts['LogLevel'] = val + when "-h" + print( + "\nUsage: msfweb \n" + + arguments.usage) + exit + end +} + +# Create the driver instance. +driver = Msf::Ui::Web::Driver.new(opts) + +# Run with it. +driver.run diff --git a/plugins/sample.rb b/plugins/sample.rb index 56f37256d4..1c56c40489 100644 --- a/plugins/sample.rb +++ b/plugins/sample.rb @@ -2,20 +2,37 @@ module Msf ### # -# This class illustrates a sample plugin. +# This class illustrates a sample plugin. Plugins can change the behavior of +# the framework by adding new features, new user interface commands, or +# through any other arbitrary means. They are designed to have a very loose +# definition in order to make them as useful as possible. # ### class Plugin::Sample < Msf::Plugin - def initialize(framework) # :nodoc: + # + # The constructor is called when an instance of the plugin is created. The + # framework instance that the plugin is being associated with is passed in + # the framework parameter. Plugins should call the parent constructor when + # inheriting from Msf::Plugin to ensure that the framework attribute on + # their instance gets set. + # + def initialize(framework) super end - def name # :nodoc: + # + # This method returns a short, friendly name for the plugin. + # + def name "sample" end - def desc # :nodoc: + # + # This method returns a brief description of the plugin. It should be no + # more than 60 characters, but there are no hard limits. + # + def desc "Demonstrates using framework plugins" end