From b06a2ca0303dab9d8d709d8071dffd18755be2da Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Wed, 19 Oct 2005 01:48:10 +0000 Subject: [PATCH] initial support for compat filtering, may be buggy git-svn-id: file:///home/svn/incoming/trunk@2971 4d416f70-5f16-0410-b530-b9f4589650da --- lib/msf/core/exploit.rb | 33 +++++++ lib/msf/core/handler.rb | 7 ++ lib/msf/core/handler/bind_tcp.rb | 4 + lib/msf/core/handler/find_port.rb | 4 + lib/msf/core/handler/find_tag.rb | 4 + lib/msf/core/handler/none.rb | 4 + lib/msf/core/handler/reverse_tcp.rb | 4 + lib/msf/core/module.rb | 95 ++++++++++++++++++- lib/msf/core/payload.rb | 22 ++++- lib/msf/core/payload_set.rb | 39 +++++--- .../payloads/stagers/windows/findtag_ord.rb | 1 + .../stagers/windows/reverse_ord_tcp.rb | 1 + modules/payloads/stages/windows/dllinject.rb | 5 +- modules/payloads/stages/windows/shell.rb | 4 + 14 files changed, 210 insertions(+), 17 deletions(-) diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 2793d21145..96bc42d825 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -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 diff --git a/lib/msf/core/handler.rb b/lib/msf/core/handler.rb index e7bc99ceb3..3a30f2180d 100644 --- a/lib/msf/core/handler.rb +++ b/lib/msf/core/handler.rb @@ -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. # diff --git a/lib/msf/core/handler/bind_tcp.rb b/lib/msf/core/handler/bind_tcp.rb index 39747a19e1..5a38c1329d 100644 --- a/lib/msf/core/handler/bind_tcp.rb +++ b/lib/msf/core/handler/bind_tcp.rb @@ -21,6 +21,10 @@ module BindTcp return "bind_tcp" end + def self.general_handler_type + "bind" + end + def initialize(info = {}) super diff --git a/lib/msf/core/handler/find_port.rb b/lib/msf/core/handler/find_port.rb index 5b6110b47f..51e9ffff48 100644 --- a/lib/msf/core/handler/find_port.rb +++ b/lib/msf/core/handler/find_port.rb @@ -17,6 +17,10 @@ module FindPort return "find_port" end + def self.general_handler_type + "find" + end + def initialize(info = {}) super diff --git a/lib/msf/core/handler/find_tag.rb b/lib/msf/core/handler/find_tag.rb index e2429f22f6..de98476043 100644 --- a/lib/msf/core/handler/find_tag.rb +++ b/lib/msf/core/handler/find_tag.rb @@ -19,6 +19,10 @@ module FindTag return "find_tag" end + def self.general_handler_type + "find" + end + def initialize(info = {}) super diff --git a/lib/msf/core/handler/none.rb b/lib/msf/core/handler/none.rb index 912226f748..db213a26b0 100644 --- a/lib/msf/core/handler/none.rb +++ b/lib/msf/core/handler/none.rb @@ -18,6 +18,10 @@ module None def self.handler_type return "none" end + + def self.general_handler_type + return "none" + end end diff --git a/lib/msf/core/handler/reverse_tcp.rb b/lib/msf/core/handler/reverse_tcp.rb index 751b340380..ea99dc40a1 100644 --- a/lib/msf/core/handler/reverse_tcp.rb +++ b/lib/msf/core/handler/reverse_tcp.rb @@ -22,6 +22,10 @@ module ReverseTcp return "reverse_tcp" end + def self.general_handler_type + "reverse" + end + def initialize(info = {}) super diff --git a/lib/msf/core/module.rb b/lib/msf/core/module.rb index c7751949a8..67fbc0cfa6 100644 --- a/lib/msf/core/module.rb +++ b/lib/msf/core/module.rb @@ -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 # diff --git a/lib/msf/core/payload.rb b/lib/msf/core/payload.rb index 5121df15e3..79b47559f3 100644 --- a/lib/msf/core/payload.rb +++ b/lib/msf/core/payload.rb @@ -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 diff --git a/lib/msf/core/payload_set.rb b/lib/msf/core/payload_set.rb index 14684a8d6c..bf4fad7666 100644 --- a/lib/msf/core/payload_set.rb +++ b/lib/msf/core/payload_set.rb @@ -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 diff --git a/modules/payloads/stagers/windows/findtag_ord.rb b/modules/payloads/stagers/windows/findtag_ord.rb index debc0766fd..b24b3daa8f 100644 --- a/modules/payloads/stagers/windows/findtag_ord.rb +++ b/modules/payloads/stagers/windows/findtag_ord.rb @@ -21,6 +21,7 @@ module FindTagOrdinalTcp 'Arch' => ARCH_X86, 'Handler' => Msf::Handler::FindTag, 'Convention' => 'sockedi', + 'SymbolLookup' => 'ws2ord', 'Stager' => { 'Offsets' => diff --git a/modules/payloads/stagers/windows/reverse_ord_tcp.rb b/modules/payloads/stagers/windows/reverse_ord_tcp.rb index 7d63dc3ba7..160a6b1a1f 100644 --- a/modules/payloads/stagers/windows/reverse_ord_tcp.rb +++ b/modules/payloads/stagers/windows/reverse_ord_tcp.rb @@ -25,6 +25,7 @@ module ReverseOrdinalTcp 'Arch' => ARCH_X86, 'Handler' => Msf::Handler::ReverseTcp, 'Convention' => 'sockedi', + 'SymbolLookup' => 'ws2ord', 'Stager' => { 'Offsets' => diff --git a/modules/payloads/stages/windows/dllinject.rb b/modules/payloads/stages/windows/dllinject.rb index a96f62b33f..cc800ade2c 100644 --- a/modules/payloads/stages/windows/dllinject.rb +++ b/modules/payloads/stages/windows/dllinject.rb @@ -29,7 +29,10 @@ module DllInject ], 'Platform' => 'win', 'Arch' => ARCH_X86, - 'Convention' => 'sockedi', + 'PayloadCompat' => + { + 'Convention' => 'sockedi' + }, 'Stage' => { 'Offsets' => diff --git a/modules/payloads/stages/windows/shell.rb b/modules/payloads/stages/windows/shell.rb index 22d41a6c55..6a634a37e0 100644 --- a/modules/payloads/stages/windows/shell.rb +++ b/modules/payloads/stages/windows/shell.rb @@ -18,6 +18,10 @@ module Shell 'Platform' => 'win', 'Arch' => ARCH_X86, 'Session' => Msf::Sessions::CommandShell, + 'PayloadCompat' => + { + 'Convention' => 'sockedi' + }, 'Stage' => { 'Offsets' =>