initial support for compat filtering, may be buggy

git-svn-id: file:///home/svn/incoming/trunk@2971 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Miller 2005-10-19 01:48:10 +00:00
parent be7c2d129d
commit b06a2ca030
14 changed files with 210 additions and 17 deletions

View File

@ -38,6 +38,18 @@ end
###
class Exploit < Msf::Module
module CompatDefaults
#
# Default compatibility specifications for payloads
#
Payload =
{
# Support reverse, bind, find, and noconn connection types
# for all exploits unless expressly disabled.
'ConnectionType' => 'reverse bind find noconn',
}
end
#
# The various check codes that can be returned from the ``check'' routine.
#
@ -327,6 +339,10 @@ class Exploit < Msf::Module
next
end
# Are we compatible in terms of conventions and connections and
# what not?
next if (compatible?(framework.payloads.instance(name)) == false)
# This one be compatible!
payloads << [ name, mod ]
}
@ -569,6 +585,23 @@ protected
attr_writer :default_target
attr_writer :payload_info
#
# Overrides the base class method and serves to initialize default
# compatibilities for exploits
#
def init_compat
super
#
# Merge in payload compatible defaults
#
p = module_info['Compat']['Payload']
CompatDefaults::Payload.each_pair { |k,v|
(p[k]) ? p[k] << v : p[k] = v
}
end
end
end

View File

@ -45,6 +45,13 @@ module Handler
return "none"
end
#
# Returns the transport-independent handler type.
#
def self.general_handler_type
"none"
end
#
# Returns the handler's name, if any.
#

View File

@ -21,6 +21,10 @@ module BindTcp
return "bind_tcp"
end
def self.general_handler_type
"bind"
end
def initialize(info = {})
super

View File

@ -17,6 +17,10 @@ module FindPort
return "find_port"
end
def self.general_handler_type
"find"
end
def initialize(info = {})
super

View File

@ -19,6 +19,10 @@ module FindTag
return "find_tag"
end
def self.general_handler_type
"find"
end
def initialize(info = {})
super

View File

@ -18,6 +18,10 @@ module None
def self.handler_type
return "none"
end
def self.general_handler_type
return "none"
end
end

View File

@ -22,6 +22,10 @@ module ReverseTcp
return "reverse_tcp"
end
def self.general_handler_type
"reverse"
end
def initialize(info = {})
super

View File

@ -89,6 +89,9 @@ class Module
set_defaults
# Initialize module compatibility hashes
init_compat
# Transform some of the fields to arrays as necessary
self.author = Author.transform(module_info['Author'])
self.arch = Rex::Transformer.transform(module_info['Arch'], Array,
@ -154,7 +157,7 @@ class Module
# Return the module's name
#
def name
return module_info['Name']
module_info['Name']
end
#
@ -162,21 +165,77 @@ class Module
# name is returned.
#
def alias
return module_info['Alias']
module_info['Alias']
end
#
# Return the module's description
#
def description
return module_info['Description']
module_info['Description']
end
#
# Return the module's version information
#
def version
return module_info['Version']
module_info['Version']
end
#
# Returns the hash that describes this module's compatibilities
#
def compat
module_info['Compat'] || {}
end
#
# Returns whether or not this module is compatible with the supplied
# module.
#
def compatible?(mod)
ch = nil
# Invalid module? Shoot, we can't compare that.
return true if (mod == nil)
# Determine which hash to used based on the supplied module type
if (mod.type == MODULE_ENCODER)
ch = self.compat['Encoder']
elsif (mod.type == MODULE_NOP)
ch = self.compat['Nop']
elsif (mod.type == MODULE_PAYLOAD)
ch = self.compat['Payload']
else
return true
end
# Enumerate each compatibility item in our hash to find out
# if we're compatible with this sucker.
ch.each_pair { |k,v|
# Get the value of the current key from the module, such as
# the ConnectionType for a stager (ws2ord, for instance).
mval = mod.module_info[k]
# Skip zee nils that the module has.
next if (mval == nil or v == nil)
# If the supplied module's value is not contained within the supported
# values for the this module or this module indicated a negation of
# the value stated by the supplied module, then we have detected
# ourselves a bit of an incompatibility and we just can't have that.
if (!(v =~ /#{mval}/) or
(v =~ /-#{mval}/))
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}, value was #{mval}",
'core', LEV_1)
return false
end
}
# If we get here, we're compatible.
return true
end
#
@ -302,6 +361,34 @@ protected
}.update(self.module_info)
end
#
# This method initializes the module's compatibility hashes by normalizing
# them into one single hash. As it stands, modules can define
# compatibility in their supplied info hash through:
#
# Compat - direct compat definitions
# PayloadCompat - payload compatibilities
# EncoderCompat - encoder compatibilities
# NopCompat - nop compatibilities
#
# In the end, the module specific compatibilities are merged as sub-hashes
# of the primary Compat hash key to make checks more uniform.
#
def init_compat
c = module_info['Compat'] = Hash.new if (module_info['Compat'] == nil)
# Initialize the module sub compatibilities
c['Payload'] = Hash.new if (c['Payload'] == nil)
c['Encoder'] = Hash.new if (c['Encoder'] == nil)
c['Nop'] = Hash.new if (c['Nop'] == nil)
# Update the compat-derived module specific compatibilities from
# the specific ones to make a uniform view of compatibilities
c['Payload'].update(module_info['PayloadCompat'] || {})
c['Encoder'].update(module_info['EncoderCompat'] || {})
c['Nop'].update(module_info['NopCompat'] || {})
end
#
# Register options with a specific owning class
#

View File

@ -31,6 +31,11 @@ class Payload < Msf::Module
def initialize(info = {})
super
# Update the module info hash with the connection type
# that is derived from the handler for this payload. This is
# used for compatibility filtering purposes.
self.module_info['ConnectionType'] = connection_type
end
##
@ -106,6 +111,21 @@ class Payload < Msf::Module
module_info['Convention']
end
#
# Returns the module's connection type, such as reverse, bind, noconn,
# or whatever else the case may be.
#
def connection_type
handler_klass.general_handler_type
end
#
# The method used to resolve symbols by the payload.
#
def symbol_lookup
module_info['SymbolLookup']
end
#
# Checks to see if the supplied convention is compatible with this
# payload's convention.
@ -133,7 +153,7 @@ class Payload < Msf::Module
# Return the connection associated with this payload, or none if there
# isn't one.
#
def handler
def handler_klass
return module_info['Handler'] || Msf::Handler::None
end

View File

@ -50,6 +50,10 @@ class PayloadSet < ModuleSet
# Hash that caches the sizes of payloads
self.sizes = {}
# Single instance cache of modules for use with doing quick referencing
# of attributes that would require an instance.
self._instances = {}
end
#
@ -91,11 +95,11 @@ class PayloadSet < ModuleSet
# Recalculate stagers and stages
_stagers.each_pair { |stager_name, p|
stager_mod, handler, stager_platform, stager_arch, stager_conv = p
stager_mod, handler, stager_platform, stager_arch, stager_inst = p
# Walk the array of stages
_stages.each_pair { |stage_name, p|
stage_mod, junk, stage_platform, stage_arch, stage_conv = p
stage_mod, junk, stage_platform, stage_arch, stage_inst = p
# No intersection between architectures on the payloads?
if ((stager_arch) and
@ -121,12 +125,10 @@ class PayloadSet < ModuleSet
# If the stage has a convention, make sure it's compatible with
# the stager's
if ((stage_conv) and
(stager_conv != stage_conv))
dlog("Stager #{stager_name} and stage #{stage_name} have incompatible conventions:",
if ((stage_inst) and
(stage_inst.compatible?(stager_inst) == false))
dlog("Stager #{stager_name} and stage #{stage_name} are incompatible.",
'core', LEV_3)
dlog(" Stager: #{stager_conv}.", 'core', LEV_3)
dlog(" Stage: #{stage_conv}.", 'core', LEV_3)
next
end
@ -182,10 +184,10 @@ class PayloadSet < ModuleSet
pinfo =
[
pmodule,
instance.handler,
instance.handler_klass,
instance.platform,
instance.arch,
instance.convention,
instance,
file_path
]
@ -201,8 +203,8 @@ class PayloadSet < ModuleSet
# connection, then it can also be staged. Insert it into
# the staged list.
if ((instance.payload_type == Payload::Type::Single) and
((instance.handler == Msf::Handler::None) or
(instance.handler == nil)))
((instance.handler_klass == Msf::Handler::None) or
(instance.handler_klass == nil)))
payload_type_modules[Payload::Type::Stage][name] = pinfo
end
end
@ -248,6 +250,20 @@ class PayloadSet < ModuleSet
dlog("Built staged payload #{full_name}.", 'core', LEV_1)
end
#
# Returns a single read-only instance of the supplied payload name such
# that specific attributes, like compatibility, can be evaluated. The
# payload instance returned should NOT be used for anything other than
# reading.
#
def instance(name)
if (self._instances[name] == nil)
self._instances[name] = create(name)
end
self._instances[name]
end
attr_reader :stages, :singles, :sizes
protected
@ -292,6 +308,7 @@ protected
attr_accessor :manager, :payload_type_modules
attr_writer :stages, :singles, :sizes
attr_accessor :_instances
end

View File

@ -21,6 +21,7 @@ module FindTagOrdinalTcp
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::FindTag,
'Convention' => 'sockedi',
'SymbolLookup' => 'ws2ord',
'Stager' =>
{
'Offsets' =>

View File

@ -25,6 +25,7 @@ module ReverseOrdinalTcp
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseTcp,
'Convention' => 'sockedi',
'SymbolLookup' => 'ws2ord',
'Stager' =>
{
'Offsets' =>

View File

@ -29,7 +29,10 @@ module DllInject
],
'Platform' => 'win',
'Arch' => ARCH_X86,
'Convention' => 'sockedi',
'PayloadCompat' =>
{
'Convention' => 'sockedi'
},
'Stage' =>
{
'Offsets' =>

View File

@ -18,6 +18,10 @@ module Shell
'Platform' => 'win',
'Arch' => ARCH_X86,
'Session' => Msf::Sessions::CommandShell,
'PayloadCompat' =>
{
'Convention' => 'sockedi'
},
'Stage' =>
{
'Offsets' =>