module Msf::Module::ModuleInfo # # CONSTANTS # # The list of options that support merging in an information hash. UpdateableOptions = [ "Name", "Description", "Alias", "PayloadCompat" ] # # Instance Methods # # # Returns the module's alias, if it has one. Otherwise, the module's # name is returned. # def alias module_info['Alias'] end # # Return the module's description. # def description module_info['Description'] end # # Returns the disclosure date, if known. # def disclosure_date date_str = Date.parse(module_info['DisclosureDate'].to_s) rescue nil end # # Return the module's name from the module information hash. # def name module_info['Name'] end # # Return the module's notes (including AKA and NOCVE descriptors). # def notes module_info['Notes'] end protected # # Attributes # # @!attribute module_info attr_accessor :module_info # # Instance Methods # # # Register options with a specific owning class. # def info_fixups # Each reference should be an array consisting of two elements refs = module_info['References'] if(refs and not refs.empty?) refs.each_index do |i| if !(refs[i].respond_to?('[]') and refs[i].length == 2) refs[i] = nil end end # Purge invalid references refs.delete(nil) end end # # Checks and merges the supplied key/value pair in the supplied hash. # def merge_check_key(info, name, val) if (self.respond_to?("merge_info_#{name.downcase}", true)) self.send("merge_info_#{name.downcase}", info, val) else # If the info hash already has an entry for this name if (info[name]) # If it's not an array, convert it to an array and merge the # two if (info[name].kind_of?(Hash)) raise TypeError, 'can only merge a hash into a hash' unless val.kind_of?(Hash) val.each_pair do |val_key, val_val| merge_check_key(info[name], val_key, val_val) end return elsif (info[name].kind_of?(Array) == false) curr = info[name] info[name] = [ curr ] end # If the value being merged is an array, add each one if (val.kind_of?(Array) == true) val.each { |v| if (info[name].include?(v) == false) info[name] << v end } # Otherwise just add the value elsif (info[name].include?(val) == false) info[name] << val end # Otherwise, just set the value equal if no current value # exists else info[name] = val end end end # # Merges options in the info hash in a sane fashion, as some options # require special attention. # def merge_info(info, opts) opts.each_pair { |name, val| merge_check_key(info, name, val) } info end # # Merges advanced options. # def merge_info_advanced_options(info, val) merge_info_options(info, val, true, false) end # # Merge aliases with an underscore delimiter. # def merge_info_alias(info, val) merge_info_string(info, 'Alias', val, '_') end # # Merges the module description. # def merge_info_description(info, val) key = 'Description' unless info[key] info[key] = val return end current_value = Msf::Serializer::ReadableText.word_wrap_description(info[key]) new_value = Msf::Serializer::ReadableText.word_wrap_description(val) info[key] = current_value.end_with?('.') ? "#{current_value}\n#{val}" : "#{current_value}.\n\n#{new_value}" end # # Merges advanced options. # def merge_info_evasion_options(info, val) merge_info_options(info, val, false, true) end # # Merges the module name. # def merge_info_name(info, val) merge_info_string(info, 'Name', val, ', ', true) end # # Merges options. # def merge_info_options(info, val, advanced = false, evasion = false) key_name = ((advanced) ? 'Advanced' : (evasion) ? 'Evasion' : '') + 'Options' new_cont = Msf::OptionContainer.new new_cont.add_options(val, advanced, evasion) cur_cont = Msf::OptionContainer.new cur_cont.add_options(info[key_name] || [], advanced, evasion) new_cont.each_option { |name, option| next if (cur_cont.get(name)) info[key_name] = [] if (!info[key_name]) info[key_name] << option } end # # Merges a given key in the info hash with a delimiter. # def merge_info_string(info, key, val, delim = ', ', inverse = false) if (info[key]) if (inverse == true) info[key] = info[key] + delim + val else info[key] = val + delim + info[key] end else info[key] = val end end # # Merge the module version. # def merge_info_version(info, val) merge_info_string(info, 'Version', val) end # # Updates information in the supplied info hash and merges other # information. This method is used to override things like Name, Version, # and Description without losing the ability to merge architectures, # platforms, and options. # def update_info(info, opts) opts.each_pair { |name, val| # If the supplied option name is one of the ones that we should # override by default if (UpdateableOptions.include?(name) == true) # Only if the entry is currently nil do we use our value if (info[name] == nil) info[name] = val end # Otherwise, perform the merge operation like normal else merge_check_key(info, name, val) end } return info end end