From 514e760b965b1f25e7a864e6717cee3ea5c9d419 Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Mon, 28 Nov 2005 21:38:48 +0000 Subject: [PATCH] implemented msfd as a plugin git-svn-id: file:///home/svn/incoming/trunk@3151 4d416f70-5f16-0410-b530-b9f4589650da --- lib/msf/base/simple/framework.rb | 31 ++++++++- msfcli | 5 ++ msfconsole | 5 +- msfd | 37 +++------- msfweb | 4 ++ plugins/msfd.rb | 114 +++++++++++++++++++++++++++++++ 6 files changed, 166 insertions(+), 30 deletions(-) create mode 100644 plugins/msfd.rb diff --git a/lib/msf/base/simple/framework.rb b/lib/msf/base/simple/framework.rb index 60fc3e0ccd..cec2c61e7f 100644 --- a/lib/msf/base/simple/framework.rb +++ b/lib/msf/base/simple/framework.rb @@ -12,6 +12,30 @@ module Simple ### module Framework + ### + # + # Extends the framework.plugins class instance to automatically check in + # the framework plugin's directory. + # + ### + module PluginManager + + # + # Loads the supplied plugin by checking to see if it exists in the + # framework default plugin path as necessary. + # + def load(path, opts = {}) + def_path = Msf::Config.plugin_directory + File::SEPARATOR + path + + if (File.exists?(def_path) or File.exists?(def_path + ".rb")) + super(def_path, opts) + else + super + end + end + + end + include GeneralEventSubscriber ModuleSimplifiers = @@ -40,7 +64,12 @@ module Framework # Extends a framework object that may already exist. # def self.simplify(framework, opts) - framework.extend(Msf::Simple::Framework) + + # If the framework instance has not already been extended, do it now. + if (framework.kind_of?(Msf::Simple::Framework) == false) + framework.extend(Msf::Simple::Framework) + framework.plugins.extend(Msf::Simple::Framework::PluginManager) + end # Initialize the simplified framework framework.init_simplified() diff --git a/msfcli b/msfcli index 2290ffb03a..ba1cc584c2 100755 --- a/msfcli +++ b/msfcli @@ -1,4 +1,9 @@ #!/usr/bin/ruby +# +# This user interface allows users to interact with the framework through a +# command line interface (CLI) rather than having to use a prompting console +# or web-based interface. +# $:.unshift(File.join(File.dirname(__FILE__), '../lib')) diff --git a/msfconsole b/msfconsole index c3deddc1f8..dfa52af30f 100755 --- a/msfconsole +++ b/msfconsole @@ -1,6 +1,9 @@ #!/usr/bin/ruby +# +# This user interface provides users with a command console interface to the +# framework. +# -# Ghetto include for lib relative to the msfconsole script $:.unshift(File.join(File.dirname(__FILE__), '../lib')) require 'rex' diff --git a/msfd b/msfd index 32e15ba37e..673c635fac 100755 --- a/msfd +++ b/msfd @@ -1,4 +1,10 @@ #!/usr/bin/ruby +# +# This user interface listens on a port and provides clients that connect to +# it with an msfconsole instance. The nice thing about this interface is that +# it allows multiple clients to share one framework instance and thus makes it +# possible for sessions to to be shared from a single vantage point. +# $:.unshift(File.join(File.dirname(__FILE__), '../lib')) @@ -12,7 +18,7 @@ arguments = Rex::Parser::Arguments.new( "-f" => [ false, "Run the daemon in the foreground" ], "-h" => [ false, "Help banner" ]) -opts = {} +opts = { 'RunInForeground' => true } foreground = false # Parse command line arguments. @@ -35,32 +41,7 @@ arguments.parse(ARGV) { |opt, idx, val| # Create an instance of the framework $framework = Msf::Simple::Framework.create -server = Rex::Socket::TcpServer.create( - 'LocalHost' => opts['ServerHost'], - 'LocalPort' => opts['ServerPort'] || 55554) - exit if (Process.fork()) unless foreground -begin - client = server.accept - - Thread.new(client) { |cli| - begin - Msf::Ui::Console::Driver.new( - Msf::Ui::Console::Driver::DefaultPrompt, - Msf::Ui::Console::Driver::DefaultPromptChar, - 'Framework' => $framework, - 'LocalInput' => Rex::Ui::Text::Input::Socket.new(cli), - 'LocalOutput' => Rex::Ui::Text::Output::Socket.new(cli)).run - - begin - cli.shutdown - cli.close - rescue IOError - end - rescue - puts "Error: #{$!}\n\n#{$@.join("\n")}" - end - } - -end while true +# Run the plugin instance in the foreground. +$framework.plugins.load('msfd', opts).run diff --git a/msfweb b/msfweb index 8469ec891d..2f8fada4e1 100755 --- a/msfweb +++ b/msfweb @@ -1,4 +1,8 @@ #!/usr/bin/ruby +# +# This user interface provides users with a web-based interface to the +# framework that can be shared. +# $:.unshift(File.join(File.dirname(__FILE__), '../lib')) diff --git a/plugins/msfd.rb b/plugins/msfd.rb new file mode 100644 index 0000000000..ae5092316c --- /dev/null +++ b/plugins/msfd.rb @@ -0,0 +1,114 @@ +#!/usr/bin/ruby +# +# This plugin provides an msf daemon interface that spawns a listener on a +# defined port (default 55554) and gives each connecting client its own +# console interface. These consoles all share the same framework instance. +# + +module Msf + +### +# +# This class implements the msfd plugin interface. +# +### +class Plugin::Msfd < Msf::Plugin + + # + # Initializes the msfd plugin. The following options are supported in the + # hash by this plugin: + # + # ServerHost + # + # The local hostname to listen on for connections. The default is + # 127.0.0.1. + # + # ServerPort + # + # The local port to listen on for connections. The default is 55554. + # + # RunInForeground + # + # Instructs the plugin to now execute the daemon in a worker thread and to + # instead allow the caller to manage executing the daemon through the + # ``run'' method. + # + def initialize(framework, opts) + super + + # Start listening for connections. + self.server = Rex::Socket::TcpServer.create( + 'LocalHost' => opts['ServerHost'] || '127.0.0.1', + 'LocalPort' => opts['ServerPort'] || 55554) + + # If the run in foreground flag is not specified, then go ahead and fire + # it off in a worker thread. + if (opts['RunInForeground'] != true) + Thread.new { + run + } + end + end + + # + # Returns 'msfd' + # + def name + "msfd" + end + + # + # Returns the msfd plugin description. + # + def desc + "Provides a console interface to users over a listening TCP port." + end + + # + # Runs the msfd plugin by blocking on new connections and then spawning + # threads to handle the console interface for each client. + # + def run + begin + client = server.accept + + # Spawn a thread for the client connection + Thread.new(client) { |cli| + begin + Msf::Ui::Console::Driver.new( + Msf::Ui::Console::Driver::DefaultPrompt, + Msf::Ui::Console::Driver::DefaultPromptChar, + 'Framework' => framework, + 'LocalInput' => Rex::Ui::Text::Input::Socket.new(cli), + 'LocalOutput' => Rex::Ui::Text::Output::Socket.new(cli)).run + + begin + cli.shutdown + cli.close + rescue IOError + end + rescue + elog("Msfd client error: #{$!}\n\n#{$@.join("\n")}", 'core') + end + } + + end while true + end + + # + # Closes the listener service. + # + def cleanup + self.server.close + end + +protected + + # + # The listening socket instance. + # + attr_accessor :server + +end + +end