Files
metasploit-gs/lib/msf/core/module_set.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

291 lines
9.8 KiB
Ruby
Raw Normal View History

2012-10-01 13:09:30 -05:00
# -*- coding: binary -*-
require 'pathname'
2012-10-02 16:38:25 -05:00
###
#
# A module set contains zero or more named module classes of an arbitrary
# type.
#
###
class Msf::ModuleSet < Hash
2012-10-02 18:21:24 -05:00
include Msf::Framework::Offspring
2012-10-02 16:38:25 -05:00
# Wrapper that detects if a symbolic module is in use. If it is, it creates an instance to demand load the module
2023-09-24 17:42:00 -04:00
# and then returns the now-loaded class afterwards.
2012-10-01 13:09:30 -05:00
#
2012-10-02 16:38:25 -05:00
# @param [String] name the module reference name
# @return [Msf::Module] Class of the of the Msf::Module with the given reference name
2012-10-02 16:38:25 -05:00
def [](name)
module_class = super
if module_class.nil?
load_module_class(name)
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
super
end
2012-10-01 13:09:30 -05:00
2013-05-21 08:19:47 -05:00
# Create an instance of the supplied module by its reference name
2012-10-02 16:38:25 -05:00
#
2013-05-21 08:19:47 -05:00
# @param reference_name [String] The module reference name.
2012-12-03 22:23:40 -06:00
# @return [Msf::Module,nil] Instance of the named module or nil if it
# could not be created.
2023-03-24 14:00:05 +00:00
def create(reference_name, cache_type: Msf::ModuleManager::Cache::FILESYSTEM)
klass = load_module_class(reference_name, cache_type: cache_type)
2012-10-02 16:38:25 -05:00
instance = nil
2013-05-21 08:19:47 -05:00
# If the klass is valid for this reference_name, try to create it
unless klass.nil?
2012-10-02 16:38:25 -05:00
instance = klass.new
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Notify any general subscribers of the creation event
if instance
self.framework.events.on_module_created(instance)
2015-04-28 22:21:31 -05:00
else
self.delete(reference_name)
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
instance
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
# "can't add a new key into hash during iteration"
#
# @yield [module_reference_name, module]
2013-05-21 08:19:47 -05:00
# @yieldparam [String] module_reference_name the reference_name of the module.
2012-10-02 16:38:25 -05:00
# @yieldparam [Class] module The module class: a subclass of Msf::Module.
# @return [void]
def each(&block)
list = []
module_metadata.keys.sort.each do |sidx|
2012-10-02 16:38:25 -05:00
list << [sidx, self[sidx]]
2012-10-01 13:09:30 -05:00
end
2012-10-02 16:38:25 -05:00
list.each(&block)
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Enumerates each module class in the set.
#
# @param opts (see #each_module_list)
# @yield (see #each_module_list)
# @yieldparam (see #each_module_list)
# @return (see #each_module_list)
def each_module(opts = {}, &block)
self.mod_sorted = module_metadata.sort
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
each_module_list(mod_sorted, opts, &block)
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Custom each_module filtering if an advanced set supports doing extended filtering.
#
# @param opts (see #each_module_list)
# @param [String] name the module reference name
# @param [Array<String, Class>] entry pair of the module reference name and the module class.
# @return [false] if the module should not be filtered; it should be yielded by {#each_module_list}.
# @return [true] if the module should be filtered; it should not be yielded by {#each_module_list}.
def each_module_filter(opts, name, entry)
return false
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Enumerates each module class in the set based on their relative ranking to one another. Modules that are ranked
# higher are shown first.
#
# @param opts (see #each_module_list)
# @yield (see #each_module_list)
# @yieldparam (see #each_module_list)
# @return (see #each_module_list)
def each_module_ranked(opts = {}, &block)
2015-04-28 22:27:09 -05:00
each_module_list(rank_modules, opts, &block)
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Forces all modules in this set to be loaded.
#
# @return [void]
def force_load_set
each_module { |name, mod| }
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Initializes a module set that will contain modules of a specific type and expose the mechanism necessary to create
# instances of them.
#
# @param [String] type The type of modules cached by this {Msf::ModuleSet}.
def initialize(type = nil)
2012-10-01 13:09:30 -05:00
#
2012-10-02 16:38:25 -05:00
# Defaults
2012-10-01 13:09:30 -05:00
#
2012-10-02 16:38:25 -05:00
self.ambiguous_module_reference_name_set = Set.new
# Hashes that convey the supported architectures and platforms for a
# given module
self.architectures_by_module = {}
self.platforms_by_module = {}
self.mod_sorted = nil
self.mod_extensions = []
2012-10-01 13:09:30 -05:00
#
2012-10-02 16:38:25 -05:00
# Arguments
2012-10-01 13:09:30 -05:00
#
2012-10-02 16:38:25 -05:00
self.module_type = type
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# @!attribute [r] module_type
# The type of modules stored by this {Msf::ModuleSet}.
#
# @return [String] type of modules
attr_reader :module_type
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Gives the module set an opportunity to handle a module reload event
#
# @param [Class] mod the module class: a subclass of Msf::Module
# @return [void]
def on_module_reload(mod)
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Dummy placeholder to recalculate aliases and other fun things.
#
# @return [void]
def recalculate
end
2012-10-01 13:09:30 -05:00
2013-05-21 08:19:47 -05:00
# Checks to see if the supplied module reference name is valid.
2012-10-02 16:38:25 -05:00
#
2013-05-21 08:19:47 -05:00
# @param reference_name [String] The module reference name.
2012-10-02 16:38:25 -05:00
# @return [true] if the module can be {#create created} and cached.
# @return [false] otherwise
2013-05-21 08:19:47 -05:00
def valid?(reference_name)
(self[reference_name]) ? true : false
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2013-05-21 08:19:47 -05:00
# Adds a module with a the supplied reference_name.
2012-10-02 16:38:25 -05:00
#
2013-05-21 08:19:47 -05:00
# @param [Class<Msf::Module>] klass The module class.
# @param [String] reference_name The module reference name.
# @param [Hash{String => Object}] info optional module information.
# @option info [Array<String>] 'files' List of paths to files that defined
# +klass+.
# @return [Class] The klass parameter modified to have
2016-04-20 11:02:15 -07:00
# Msf::Module.framework, Msf::Module#refname, Msf::Module#file_path,
# and Msf::Module#orig_cls set.
2013-05-21 08:19:47 -05:00
def add_module(klass, reference_name, info = {})
# Set the module's reference_name so that it can be referenced when
2012-10-02 16:38:25 -05:00
# instances are created.
2013-05-21 08:19:47 -05:00
klass.framework = framework
klass.refname = reference_name
klass.file_path = ((info and info['files']) ? info['files'][0] : nil)
klass.orig_cls = klass
2012-10-02 16:38:25 -05:00
2012-10-04 11:14:08 -05:00
# don't want to trigger a create, so use fetch
2013-05-21 08:19:47 -05:00
cached_module = self.fetch(reference_name, nil)
2012-10-02 16:38:25 -05:00
if cached_module
2013-05-21 08:19:47 -05:00
ambiguous_module_reference_name_set.add(reference_name)
2012-10-02 16:38:25 -05:00
# TODO this isn't terribly helpful since the refnames will always match, that's why they are ambiguous.
2013-05-21 08:19:47 -05:00
wlog("The module #{klass.refname} is ambiguous with #{self[reference_name].refname}.")
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2013-05-21 08:19:47 -05:00
self[reference_name] = klass
2013-05-21 08:19:47 -05:00
klass
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
def module_refnames
module_metadata.keys
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
protected
2012-10-02 16:38:25 -05:00
# Enumerates the modules in the supplied array with possible limiting factors.
#
# @param [Array<Array<String, Class>>] ary Array of module reference name and module class pairs
# @param [Hash{String => Object}] opts
# @option opts [Array<String>] 'Arch' List of 1 or more architectures that the module must support. The module need
# only support one of the architectures in the array to be included, not all architectures.
# @option opts [Array<String>] 'Platform' List of 1 or more platforms that the module must support. The module need
# only support one of the platforms in the array to be include, not all platforms.
# @yield [module_reference_name, module]
# @yieldparam [String] module_reference_name the name of module
# @yieldparam [Class] module The module class: a subclass of {Msf::Module}.
# @return [void]
def each_module_list(ary, opts, &block)
ary.each do |entry|
name, module_metadata = entry
2012-10-02 16:38:25 -05:00
# Filter out incompatible architectures
if (opts['Arch'])
if (!architectures_by_module[name])
architectures_by_module[name] = Array.wrap(module_metadata.arch)
2012-10-01 13:09:30 -05:00
end
next if ((architectures_by_module[name] & opts['Arch']).empty? == true)
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Filter out incompatible platforms
if (opts['Platform'])
if (!platforms_by_module[name])
platforms_by_module[name] = module_metadata.platform_list
2012-10-01 13:09:30 -05:00
end
next if ((platforms_by_module[name] & opts['Platform']).empty? == true)
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# Custom filtering
next if (each_module_filter(opts, name, entry) == true)
2012-10-01 13:09:30 -05:00
block.call(name, self[name])
end
2012-10-02 16:38:25 -05:00
end
2012-10-01 13:09:30 -05:00
2012-10-02 16:38:25 -05:00
# @!attribute [rw] ambiguous_module_reference_name_set
# Set of module reference names that are ambiguous because two or more paths have modules with the same reference
# name
#
# @return [Set<String>] set of module reference names loaded from multiple paths.
attr_accessor :ambiguous_module_reference_name_set
# @!attribute [rw] architectures_by_module
# Maps a module to the list of architectures it supports.
#
# @return [Hash{Class => Array<String>}] Maps module class to Array of architecture Strings.
attr_accessor :architectures_by_module
attr_accessor :mod_extensions
# @!attribute [rw] platforms_by_module
# Maps a module to the list of platforms it supports.
#
# @return [Hash{Class => Array<String>}] Maps module class to Array of platform Strings.
attr_accessor :platforms_by_module
# @!attribute [rw] mod_sorted
# Array of module names and module classes ordered by their names.
#
# @return [Array<Array<String, Class>>] Array of arrays where the inner array is a pair of the module reference
# name and the module class.
attr_accessor :mod_sorted
# @!attribute [w] module_type
# The type of modules stored by this {Msf::ModuleSet}.
#
# @return [String] type of modules
attr_writer :module_type
# Ranks modules based on their constant rank value, if they have one. Modules without a Rank are treated as if they
# had {Msf::NormalRanking} for Rank.
#
# @return [Array<Array<String, Class>>] Array of arrays where the inner array is a pair of the module reference name
# and the module class.
def rank_modules
2024-01-22 12:40:24 +00:00
module_metadata.sort_by do |refname, metadata|
[metadata.rank || Msf::NormalRanking, refname]
end.reverse!
end
def module_metadata
Msf::Modules::Metadata::Cache.instance.module_metadata(module_type)
end
def load_module_class(reference_name, cache_type: Msf::ModuleManager::Cache::FILESYSTEM)
klass = fetch(reference_name, nil)
# If there is no module associated with this class, then try to demand load it.
if klass.nil?
framework.modules.load_cached_module(module_type, reference_name, cache_type: cache_type)
klass = fetch(reference_name, nil)
end
klass
end
2012-10-01 13:09:30 -05:00
end