From 8a2dc0a09fbe4ed9880b515d36df751042b09d57 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 27 Sep 2012 12:52:09 -0500 Subject: [PATCH] Give ruby Modules that wrap Metasploit modules a name [#36737359] active_support/dependencies cannot resolve missing constants in Metasploit modules because the wrapper module is anonymous. In order to make the wrapper module non-anonymous, the module must be assigned to a constant. Since we don't want modules colliding, the wrapper module needs a unique name, so use the module lookup name to derive the proper nested module names to namespace the wrapper module. All derived modules are nested under Msf::Modules. The name derivation handles invalid characters for constant names such as digits as the first character or non-alphanumeric character. The invalid constant name characters are converted to their hex value and prefixed with X, so '-' in a name become 'X2d'. --- .gitignore | 6 ++++ lib/msf/core/module_manager.rb | 60 +++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fe8a70dc10..36b7be3192 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Rubymine project directory +.idea +# Mac OS X files +.DS_Store data/meterpreter/ext_server_pivot.dll data/meterpreter/ext_server_pivot.x64.dll external/source/meterpreter/java/bin @@ -5,6 +9,8 @@ external/source/meterpreter/java/build external/source/meterpreter/java/extensions external/source/javapayload/bin external/source/javapayload/build +# Packaging directory +pkg tags *.swp *.orig diff --git a/lib/msf/core/module_manager.rb b/lib/msf/core/module_manager.rb index 38ef447514..3ce78cee7c 100644 --- a/lib/msf/core/module_manager.rb +++ b/lib/msf/core/module_manager.rb @@ -860,8 +860,9 @@ protected added = nil + wrap = self.class.wrapper_module(name) + begin - wrap = ::Module.new wrap.module_eval(load_module_source(file), file) if(wrap.const_defined?(:RequiredVersions)) mins = wrap.const_get(:RequiredVersions) @@ -1124,6 +1125,63 @@ protected attr_accessor :module_failed # :nodoc: attr_accessor :enabled_types # :nodoc: + # Returns a nested module to wrap the Metasploit(1|2|3) class so that it doesn't overwrite other (metasploit) module's + # classes. The wrapper module must be named so that active_support's autoloading code doesn't break when searching + # constants from inside the Metasploit(1|2|3) class. + # + # @return [Module] Msf::Modules:: + def self.wrapper_module(name) + relative_module_name = name.camelize + fully_qualified_module_name = "#{parent.name}::Modules::#{relative_module_name}" + + wrapper_module = Object + module_names = fully_qualified_module_name.split('::') + + until module_names.empty? + parent = wrapper_module + child_name = module_names.shift + + # constant names can't contain a leading digit or any non-alphanumeric characters, so convert to hexcode with + # 'X' prefix. + child_name = child_name.gsub(/^[0-9]|[^A-Za-z0-9]/) do |invalid_constant_name_character| + unpacked = invalid_constant_name_character.unpack('H*') + # unpack always returns an array, so get first value to get character's encoding + hex_code = unpacked[0] + + # as a convention start each hex-code with X so that it'll make a valid constant name since constants can't + # start with digits. + "X#{hex_code}" + end + + # don't look for constants in ancestors since the namespace modules should be defined directly on the parent and + # previously by this same method. + inherit = false + + if module_names.empty? and parent.const_defined?(child_name, inherit) + ilog("Removing #{child_name} constant from #{parent.name} so it can be reloaded", 'core', LEV_1) + # if this is the leaf module name then it needs to be destroyed and recreated if it already exists as this is + # a reload + # remove_const is private, so invoke in instance context + parent.instance_eval do + remove_const child_name + end + end + + if parent.const_defined?(child_name, inherit) + wrapper_module = parent.const_get(child_name) + else + # stub module to represent namespace + # use ruby Module, not Msf::Module + namespace_module = ::Module.new + + ilog("Adding #{child_name} constant to #{parent.name} as a namespace Module", 'core', LEV_1) + # once it's assigned to a constant, then wrapper_module.name will work. + wrapper_module = parent.const_set(child_name, namespace_module) + end + end + + wrapper_module + end end end