Land #5914, prevent loading cached modules outside of the load path

bug/bundler_fix
Brent Cook 2015-09-03 09:29:13 -05:00
commit 895b692b0d
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
3 changed files with 65 additions and 55 deletions

View File

@ -9,52 +9,62 @@ module Msf
def init_module_paths(opts={})
if @module_paths_inited
fail "Module paths already initialized. To add more module paths call `modules.add_module_path`"
else
# Ensure the module cache is accurate
self.modules.refresh_cache_from_database
add_engine_module_paths(Rails.application, opts)
Rails.application.railties.engines.each do |engine|
add_engine_module_paths(engine, opts)
end
# Initialize the user module search path
if (Msf::Config.user_module_directory)
self.modules.add_module_path(Msf::Config.user_module_directory, opts)
end
# If additional module paths have been defined globally, then load them.
# They should be separated by semi-colons.
if self.datastore['MsfModulePaths']
self.datastore['MsfModulePaths'].split(";").each { |path|
self.modules.add_module_path(path, opts)
}
end
@module_paths_inited = true
return
end
allowed_module_paths = []
extract_engine_module_paths(Rails.application).each do |path|
allowed_module_paths << path
end
if Msf::Config.user_module_directory
allowed_module_paths << Msf::Config.user_module_directory
end
Rails.application.railties.engines.each do |engine|
extract_engine_module_paths(engine).each do |path|
allowed_module_paths << path
end
end
# If additional module paths have been defined globally, then load them.
# They should be separated by semi-colons.
self.datastore['MsfModulePaths'].to_s.split(";").each do |path|
allowed_module_paths << path
end
# If the caller had additional paths to search, load them.
# They should be separated by semi-colons.
opts.delete(:module_paths).to_s.split(";").each do |path|
allowed_module_paths << path
end
# Remove any duplicate paths
allowed_module_paths.uniq!
# Update the module cache from the database
self.modules.refresh_cache_from_database(allowed_module_paths)
# Load each of the module paths
allowed_module_paths.each do |path|
self.modules.add_module_path(path, opts)
end
@module_paths_inited = true
end
private
# Add directories `engine.paths['modules']` from `engine`.
# Extract directories `engine.paths['modules']` from `engine`.
#
# @param engine [Rails::Engine] a rails engine or application
# @param options [Hash] options for {Msf::ModuleManager::ModulePaths#add_module_paths}
# @return [void]
def add_engine_module_paths(engine, options={})
modules_paths = engine.paths['modules']
if modules_paths
modules_directories = modules_paths.existent_directories
modules_directories.each do |modules_directory|
modules.add_module_path(modules_directory, options)
end
end
# @return [Array<String>] The list of module paths to load
def extract_engine_module_paths(engine)
engine.paths['modules'] ? engine.paths['modules'].existent_directories : []
end
end
end
end
end
end

View File

@ -113,15 +113,15 @@ module Msf::ModuleManager::Cache
framework.db.update_all_module_details
end
refresh_cache_from_database
refresh_cache_from_database(self.module_paths)
end
end
# Refreshes the in-memory cache from the database cache.
#
# @return [void]
def refresh_cache_from_database
self.module_info_by_path_from_database!
def refresh_cache_from_database(allowed_paths=[""])
self.module_info_by_path_from_database!(allowed_paths)
end
protected
@ -149,10 +149,12 @@ module Msf::ModuleManager::Cache
# @return [Hash{String => Hash{Symbol => Object}}] Maps path (Mdm::Module::Detail#file) to module information. Module
# information is a Hash derived from Mdm::Module::Detail. It includes :modification_time, :parent_path, :type,
# :reference_name.
def module_info_by_path_from_database!
def module_info_by_path_from_database!(allowed_paths=[""])
self.module_info_by_path = {}
if framework_migrated?
allowed_paths = allowed_paths.map{|x| x + "/"}
ActiveRecord::Base.connection_pool.with_connection do
# TODO record module parent_path in Mdm::Module::Detail so it does not need to be derived from file.
# Use find_each so Mdm::Module::Details are returned in batches, which will
@ -162,6 +164,9 @@ module Msf::ModuleManager::Cache
type = module_detail.mtype
reference_name = module_detail.refname
# Skip cached modules that are not in our allowed load paths
next if allowed_paths.select{|x| path.index(x) == 0}.empty?
typed_path = Msf::Modules::Loader::Base.typed_path(type, reference_name)
# join to '' so that typed_path_prefix starts with file separator
typed_path_suffix = File.join('', typed_path)

View File

@ -186,15 +186,7 @@ class Driver < Msf::Ui::Driver
# framework.db.active will be true if after_establish_connection ran directly when connection_established? was
# already true or if framework.db.connect called after_establish_connection.
if framework.db.active
unless opts['DeferModuleLoads']
self.framework.modules.refresh_cache_from_database
if self.framework.modules.cache_empty?
print_status("The initial module cache will be built in the background, this can take 2-5 minutes...")
end
end
elsif !framework.db.error.nil?
if !! framework.db.error
if framework.db.error.to_s =~ /RubyGem version.*pg.*0\.11/i
print_error("***")
print_error("*")
@ -217,12 +209,15 @@ class Driver < Msf::Ui::Driver
# Initialize the module paths only if we didn't get passed a Framework instance and 'DeferModuleLoads' is false
unless opts['Framework'] || opts['DeferModuleLoads']
# Configure the framework module paths
self.framework.init_module_paths
self.framework.modules.add_module_path(opts['ModulePath']) if opts['ModulePath']
self.framework.init_module_paths(module_paths: opts['ModulePath'])
end
# Rebuild the module cache in a background thread
self.framework.threads.spawn("ModuleCacheRebuild", true) do
self.framework.modules.refresh_cache_from_module_files
if framework.db.active && !opts['DeferModuleLoads']
if self.framework.modules.cache_empty?
self.framework.threads.spawn("ModuleCacheRebuild", true) do
self.framework.modules.refresh_cache_from_module_files
end
print_status("The initial module cache will be built in the background, this can take 2-5 minutes...")
end
end