115 lines
3.5 KiB
Ruby
115 lines
3.5 KiB
Ruby
module Msf::Module::Compatibility
|
|
#
|
|
# 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 == Msf::MODULE_ENCODER)
|
|
ch = self.compat['Encoder']
|
|
elsif (mod.type == Msf::MODULE_NOP)
|
|
ch = self.compat['Nop']
|
|
elsif (mod.type == Msf::MODULE_PAYLOAD)
|
|
ch = self.compat['Payload']
|
|
if self.respond_to?("target") and self.target and self.target['Payload'] and self.target['Payload']['Compat']
|
|
ch = ch.merge(self.target['Payload']['Compat'])
|
|
end
|
|
else
|
|
return true
|
|
end
|
|
|
|
# Enumerate each compatibility item in our hash to find out
|
|
# if we're compatible with this sucker.
|
|
ch.each_pair do |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]
|
|
|
|
# Reject a filled compat item on one side, but not the other
|
|
if (v and not mval)
|
|
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}")
|
|
return false
|
|
end
|
|
|
|
# Track how many of our values matched the module
|
|
mcnt = 0
|
|
|
|
# Values are whitespace separated
|
|
sv = v.split(/\s+/)
|
|
mv = mval.split(/\s+/)
|
|
|
|
sv.each do |x|
|
|
|
|
dlog("Checking compat [#{mod.refname} with #{self.refname}]: #{x} to #{mv.join(", ")}", 'core', LEV_3)
|
|
|
|
# Verify that any negate values are not matched
|
|
if (x[0,1] == '-' and mv.include?(x[1, x.length-1]))
|
|
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{x}, value was #{mval}", 'core', LEV_1)
|
|
return false
|
|
end
|
|
|
|
mcnt += 1 if mv.include?(x)
|
|
end
|
|
|
|
# No values matched, reject this module
|
|
if (mcnt == 0)
|
|
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}, value was #{mval}", 'core', LEV_1)
|
|
return false
|
|
end
|
|
|
|
end
|
|
|
|
dlog("Module #{mod.refname} is compatible with #{self.refname}", "core", LEV_1)
|
|
|
|
|
|
# If we get here, we're compatible.
|
|
return true
|
|
end
|
|
|
|
protected
|
|
|
|
#
|
|
# 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']
|
|
|
|
if (c == nil)
|
|
c = module_info['Compat'] = Hash.new
|
|
end
|
|
|
|
# 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
|
|
end |