lib/msf/core/module/module_info.rb
module Msf::Module::ModuleInfo
#
# CONSTANTS
#
# The list of options that don't support merging in an information hash.
UpdateableOptions = [ "Name", "Description", "Alias", "PayloadCompat" , "Stance"]
#
# 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 do |name, val|
# If the supplied option name is one of the ones that we should
# override by default
if UpdateableOptions.include?(name)
# 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
end
info
end
end