framework plugins
git-svn-id: file:///home/svn/incoming/trunk@3053 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
0e9c5bab5b
commit
09a41d4d5c
|
@ -37,6 +37,7 @@ class Config < Hash
|
|||
'ModuleDirectory' => "modules",
|
||||
'LogDirectory' => "logs",
|
||||
'SessionLogDirectory' => "logs/sessions",
|
||||
'PluginDirectory' => "plugins"
|
||||
}
|
||||
|
||||
##
|
||||
|
@ -73,6 +74,13 @@ class Config < Hash
|
|||
self.new.log_directory
|
||||
end
|
||||
|
||||
#
|
||||
# Calls the instance method.
|
||||
#
|
||||
def self.plugin_directory
|
||||
self.new.plugin_directory
|
||||
end
|
||||
|
||||
#
|
||||
# Calls the instance method.
|
||||
#
|
||||
|
@ -157,6 +165,13 @@ class Config < Hash
|
|||
config_directory + FileSep + self['LogDirectory']
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the directory that plugins are stored in.
|
||||
#
|
||||
def plugin_directory
|
||||
install_root + FileSep + self['PluginDirectory']
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the directory in which session log files are to reside.
|
||||
#
|
||||
|
|
|
@ -28,6 +28,7 @@ require 'msf/core/option_container'
|
|||
require 'msf/core/framework'
|
||||
require 'msf/core/session_manager'
|
||||
require 'msf/core/session'
|
||||
require 'msf/core/plugin_manager'
|
||||
|
||||
# Wrappers
|
||||
require 'msf/core/encoded_payload'
|
||||
|
|
|
@ -45,6 +45,7 @@ class Framework
|
|||
self.reconmgr = ReconManager.new(self)
|
||||
self.datastore = DataStore.new
|
||||
self.jobs = Rex::JobContainer.new
|
||||
self.plugins = PluginManager.new(self)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -112,6 +113,12 @@ class Framework
|
|||
# of the framework.
|
||||
#
|
||||
attr_reader :jobs
|
||||
#
|
||||
# The framework instance's plugin manager. The plugin manager is
|
||||
# responsible for exposing an interface that allows for the loading and
|
||||
# unloading of plugins.
|
||||
#
|
||||
attr_reader :plugins
|
||||
|
||||
protected
|
||||
|
||||
|
@ -121,6 +128,7 @@ protected
|
|||
attr_writer :datastore # :nodoc:
|
||||
attr_writer :reconmgr # :nodoc:
|
||||
attr_writer :jobs # :nodoc:
|
||||
attr_writer :plugins # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
require 'rex/sync/ref'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This module represents an abstract plugin that can be loaded into the
|
||||
# context of a framework instance. Plugins are meant to provide an easy way
|
||||
# to augment the feature set of the framework by being able to load and unload
|
||||
# them during the course of a framework's lifetime. For instance, a plugin
|
||||
# could be loaded to alter the default behavior of new sessions, such as by
|
||||
# scripting meterpreter sessions that are created. The possiblities are
|
||||
# endless!
|
||||
#
|
||||
# All plugins must exist under the Msf::Plugin namespace. Plugins are
|
||||
# reference counted to allow them to be loaded more than once if they're a
|
||||
# singleton.
|
||||
#
|
||||
###
|
||||
class Plugin
|
||||
|
||||
include Framework::Offspring
|
||||
include Rex::Ref
|
||||
|
||||
#
|
||||
# Create an instance of the plugin using the supplied framework instance.
|
||||
# We use create instead of new directly so that singleton plugins can just
|
||||
# return their singleton instance.
|
||||
#
|
||||
def self.create(framework)
|
||||
new(framework)
|
||||
end
|
||||
|
||||
#
|
||||
# Initializes the plugin instance with the supplied framework instance.
|
||||
#
|
||||
def initialize(framework)
|
||||
self.framework = framework
|
||||
|
||||
refinit
|
||||
end
|
||||
|
||||
#
|
||||
# Allows the plugin to clean up as it is being unloaded.
|
||||
#
|
||||
def cleanup
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Accessors
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Returns the name of the plugin.
|
||||
#
|
||||
def name
|
||||
"unnamed"
|
||||
end
|
||||
|
||||
#
|
||||
# A short description of the plugin.
|
||||
#
|
||||
def desc
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
require 'msf/core/plugin'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This class manages the loading and unloading plugins. All plugins must
|
||||
# implement the Plugin base class interface.
|
||||
#
|
||||
###
|
||||
class PluginManager < Array
|
||||
|
||||
include Framework::Offspring
|
||||
|
||||
#
|
||||
# The hash of path names to classes that is used during load.
|
||||
#
|
||||
@@path_hash = {}
|
||||
|
||||
#
|
||||
# Check the hash using the supplied path name to see if there is already a
|
||||
# class association.
|
||||
#
|
||||
def self.check_path_hash(path)
|
||||
@@path_hash[path]
|
||||
end
|
||||
|
||||
#
|
||||
# Set the class that's associated with the supplied hash.
|
||||
#
|
||||
def self.set_path_hash(path, klass)
|
||||
@@path_hash[path] = klass
|
||||
end
|
||||
|
||||
#
|
||||
# Initializes the plugin manager.
|
||||
#
|
||||
def initialize(framework)
|
||||
self.framework = framework
|
||||
end
|
||||
|
||||
#
|
||||
# Loads a plugin from the supplied path and returns the instance that is
|
||||
# created as a result.
|
||||
#
|
||||
def load(path)
|
||||
# Check to see if a plugin from this path has already been loaded
|
||||
# before.
|
||||
if ((klass = self.class.check_path_hash(path)) == nil)
|
||||
old = Msf::Plugin.constants
|
||||
require(path)
|
||||
new = Msf::Plugin.constants
|
||||
|
||||
# No new classes added?
|
||||
if ((diff = new - old).empty?)
|
||||
raise RuntimeError, "No classes were loaded from #{path} in the Msf::Plugin namespace."
|
||||
end
|
||||
|
||||
# Grab the class
|
||||
klass = Msf::Plugin.const_get(diff[0])
|
||||
|
||||
# Cache the path to class association for future reference
|
||||
self.class.set_path_hash(path, klass)
|
||||
end
|
||||
|
||||
# Create an instance of the plugin and let it initialize
|
||||
instance = klass.create(framework)
|
||||
|
||||
# Add it to the list of plugins
|
||||
if (self.member?(instance) == false)
|
||||
self.unshift(instance)
|
||||
end
|
||||
|
||||
# Return the instance to the caller
|
||||
instance
|
||||
end
|
||||
|
||||
#
|
||||
# Unloads a plugin using the instance that was returned from a previous
|
||||
# call to load.
|
||||
#
|
||||
def unload(inst)
|
||||
# If the reference count drops to zero, remove it from the list of
|
||||
# loaded plugins. This will indirectly call the cleanup method on the
|
||||
# plugin.
|
||||
if (inst.deref == true)
|
||||
delete(inst)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -46,6 +46,7 @@ class Core
|
|||
"help" => "Help menu",
|
||||
"info" => "Displays information about one or more module",
|
||||
"jobs" => "Displays and manages jobs",
|
||||
"load" => "Load a framework plugin",
|
||||
"persist" => "Persist or restore framework state information",
|
||||
"quit" => "Exit the console",
|
||||
"route" => "Route traffic through a session",
|
||||
|
@ -55,6 +56,7 @@ class Core
|
|||
"set" => "Sets a variable to a value",
|
||||
"setg" => "Sets a global variable to a value",
|
||||
"show" => "Displays modules of a given type, or all modules",
|
||||
"unload" => "Unload a framework plugin",
|
||||
"unset" => "Unsets one or more variables",
|
||||
"unsetg" => "Unsets one or more global variables",
|
||||
"use" => "Selects a module by name",
|
||||
|
@ -185,6 +187,32 @@ class Core
|
|||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Loads a plugin from the supplied path. If no absolute path is supplied,
|
||||
# the framework root plugin directory is used.
|
||||
#
|
||||
def cmd_load(*args)
|
||||
if (args.length == 0)
|
||||
print(
|
||||
"Usage: load <path>\n\n" +
|
||||
"Load a plugin from the supplied path.")
|
||||
return false
|
||||
end
|
||||
|
||||
# Default to the supplied argument path.
|
||||
path = args[0]
|
||||
|
||||
# If no absolute path was supplied, use the plugin directory as a base.
|
||||
path = Msf::Config.plugin_directory + File::SEPARATOR + path if (path !~ /#{File::SEPARATOR}/)
|
||||
|
||||
# Load that plugin!
|
||||
if ((inst = framework.plugins.load(path)))
|
||||
print_status("Successfully loaded plugin: #{inst.name}")
|
||||
else
|
||||
print_error("Failed to load plugin from #{arg[0]}")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# This method persists or restores framework state from a persistent
|
||||
# storage medium, such as a flatfile.
|
||||
|
@ -598,6 +626,31 @@ class Core
|
|||
else
|
||||
print_error("No module selected.")
|
||||
end
|
||||
when "plugins"
|
||||
show_plugins
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Unloads a plugin by its name.
|
||||
#
|
||||
def cmd_unload(*args)
|
||||
if (args.length == 0)
|
||||
print(
|
||||
"Usage: unload [plugin name]\n\n" +
|
||||
"Unloads a plugin by its symbolic name.")
|
||||
return false
|
||||
end
|
||||
|
||||
# Walk the plugins array
|
||||
framework.plugins.each { |plugin|
|
||||
# Unload the plugin if it matches the name we're searching for
|
||||
if (plugin.name == args[0])
|
||||
print("Unloading plugin #{args[0]}...")
|
||||
framework.plugins.unload(plugin)
|
||||
print_line("unloaded.")
|
||||
break
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -829,6 +882,16 @@ protected
|
|||
end
|
||||
end
|
||||
|
||||
def show_plugins # :nodoc:
|
||||
tbl = generate_module_table("Plugins")
|
||||
|
||||
framework.plugins.each { |plugin|
|
||||
tbl << [ plugin.name, plugin.desc ]
|
||||
}
|
||||
|
||||
print(tbl.to_s)
|
||||
end
|
||||
|
||||
def show_module_set(type, module_set) # :nodoc:
|
||||
tbl = generate_module_table(type)
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This class illustrates a sample plugin.
|
||||
#
|
||||
###
|
||||
class Plugin::Sample < Msf::Plugin
|
||||
|
||||
def initialize(framework) # :nodoc:
|
||||
super
|
||||
end
|
||||
|
||||
def name # :nodoc:
|
||||
"sample"
|
||||
end
|
||||
|
||||
def desc # :nodoc:
|
||||
"Demonstrates using framework plugins"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue