555a9f2559
[Fixes #36737359] Refactor Msf::ModuleManager into concerns so its easier to understand and duplicate code can be made DRY. The refactoring also ensures that when loading from directories, Fastlibs, or reloading, the wrapper module will always be named so that activesupport/dependencies will function.
111 lines
3.1 KiB
Ruby
111 lines
3.1 KiB
Ruby
require 'msf/core/modules/loader/archive'
|
|
require 'msf/core/modules/loader/directory'
|
|
|
|
# Deals with loading modules for the {Msf::ModuleManager}
|
|
module Msf::ModuleManager::Loading
|
|
extend ActiveSupport::Concern
|
|
|
|
#
|
|
# CONSTANTS
|
|
#
|
|
|
|
# Classes that can be used to load modules.
|
|
LOADER_CLASSES = [
|
|
Msf::Modules::Loader::Archive,
|
|
Msf::Modules::Loader::Directory
|
|
]
|
|
|
|
#
|
|
# Returns the set of modules that failed to load.
|
|
#
|
|
def failed
|
|
return module_load_error_by_reference_name
|
|
end
|
|
|
|
def file_changed?(path)
|
|
changed = false
|
|
|
|
module_details = self.cache[path]
|
|
|
|
# if uncached then it counts as changed
|
|
# Payloads can't be cached due to stage/stager matching
|
|
if module_details.nil? or module_details[:mtype] == MODULE_PAYLOAD
|
|
changed = true
|
|
else
|
|
begin
|
|
current_modification_time = ::File.mtime(path).to_i
|
|
rescue ::Errno::ENOENT
|
|
# if the file does not exist now, that's a change
|
|
changed = true
|
|
else
|
|
cached_modification_time = module_details[:mtime].to_i
|
|
|
|
# if the file's modification time's different from the cache, then it's changed
|
|
if current_modification_time != cached_modification_time
|
|
changed = true
|
|
end
|
|
end
|
|
end
|
|
|
|
changed
|
|
end
|
|
|
|
attr_accessor :module_load_error_by_reference_name
|
|
|
|
# Called when a module is initially loaded such that it can be
|
|
# categorized accordingly.
|
|
#
|
|
def on_module_load(mod, type, name, modinfo)
|
|
# Payload modules require custom loading as the individual files
|
|
# may not directly contain a logical payload that a user would
|
|
# reference, such as would be the case with a payload stager or
|
|
# stage. As such, when payload modules are loaded they are handed
|
|
# off to a special payload set. The payload set, in turn, will
|
|
# automatically create all the permutations after all the payload
|
|
# modules have been loaded.
|
|
|
|
if (type != Msf::MODULE_PAYLOAD)
|
|
# Add the module class to the list of modules and add it to the
|
|
# type separated set of module classes
|
|
add_module(mod, name, modinfo)
|
|
end
|
|
|
|
module_set_by_type[type].add_module(mod, name, modinfo)
|
|
end
|
|
|
|
protected
|
|
|
|
# Return list of {LOADER_CLASSES} instances that load modules into this module manager
|
|
def loaders
|
|
unless instance_variable_defined? :@loaders
|
|
@loaders = LOADER_CLASSES.collect { |klass|
|
|
klass.new(self)
|
|
}
|
|
end
|
|
|
|
@loaders
|
|
end
|
|
|
|
# Load all of the modules from the supplied directory or archive
|
|
#
|
|
# @param [String] path Path to a directory or Fastlib archive
|
|
# @param [Hash] options
|
|
# @option options [Boolean] :force Whether the force loading the modules even if they are unchanged and already
|
|
# loaded.
|
|
# @return [Hash{String => Integer}] Maps module type to number of modules loaded
|
|
def load_modules(path, options={})
|
|
options.assert_valid_keys(:force)
|
|
|
|
count_by_type = {}
|
|
|
|
loaders.each do |loader|
|
|
if loader.loadable?(path)
|
|
count_by_type = loader.load_modules(path, options)
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
count_by_type
|
|
end
|
|
end |