2005-07-09 21:18:49 +00:00
|
|
|
require 'msf/core'
|
2005-05-21 17:57:00 +00:00
|
|
|
|
|
|
|
module Msf
|
|
|
|
|
|
|
|
###
|
|
|
|
#
|
|
|
|
# Module
|
|
|
|
# ------
|
|
|
|
#
|
|
|
|
# The module base class is responsible for providing the common interface
|
|
|
|
# that is used to interact with modules at the most basic levels, such as
|
|
|
|
# by inspecting a given module's attributes (name, dsecription, version,
|
|
|
|
# authors, etc) and by managing the module's data store.
|
|
|
|
#
|
|
|
|
###
|
|
|
|
class Module
|
|
|
|
|
2005-07-11 05:15:30 +00:00
|
|
|
UpdateableOptions = [ "Name", "Description", "Alias" ]
|
|
|
|
|
2005-07-10 19:21:40 +00:00
|
|
|
class <<self
|
2005-07-11 20:48:13 +00:00
|
|
|
# Make include public so we can runtime extend
|
|
|
|
public :include
|
|
|
|
|
2005-07-10 19:21:40 +00:00
|
|
|
#
|
|
|
|
# The module's name that is assigned it it by the framework
|
|
|
|
# or derived from the path that the module is loaded from.
|
|
|
|
#
|
|
|
|
attr_accessor :refname
|
|
|
|
end
|
|
|
|
|
2005-07-09 21:18:49 +00:00
|
|
|
require 'msf/core/module/author'
|
|
|
|
require 'msf/core/module/platform_list'
|
|
|
|
require 'msf/core/module/reference'
|
|
|
|
require 'msf/core/module/target'
|
2005-06-05 00:03:23 +00:00
|
|
|
|
2005-06-04 22:26:42 +00:00
|
|
|
def initialize(info = {})
|
|
|
|
self.module_info = info
|
2005-05-21 17:57:00 +00:00
|
|
|
|
|
|
|
set_defaults
|
|
|
|
|
|
|
|
# Transform some of the fields to arrays as necessary
|
2005-06-05 00:03:23 +00:00
|
|
|
self.author = Author.transform(module_info['Author'])
|
2005-06-04 08:23:16 +00:00
|
|
|
self.arch = Rex::Transformer.transform(module_info['Arch'], Array,
|
2005-05-21 17:57:00 +00:00
|
|
|
[ String ], 'Arch')
|
2005-06-05 00:33:38 +00:00
|
|
|
self.platform = PlatformList.transform(module_info['Platform'])
|
2005-07-11 16:46:47 +00:00
|
|
|
self.references = Rex::Transformer.transform(module_info['References'], Array,
|
2005-05-21 17:57:00 +00:00
|
|
|
[ SiteReference, Reference ], 'Ref')
|
|
|
|
|
2005-05-21 18:27:24 +00:00
|
|
|
# Create and initialize the option container for this module
|
|
|
|
self.options = OptionContainer.new
|
2005-06-05 23:45:58 +00:00
|
|
|
self.options.add_options(info['Options'], self.class)
|
|
|
|
self.options.add_advanced_options(info['AdvancedOptions'], self.class)
|
2005-05-21 18:27:24 +00:00
|
|
|
|
|
|
|
# Create and initialize the data store for this module
|
2005-05-21 17:57:00 +00:00
|
|
|
self.datastore = DataStore.new
|
2005-05-21 18:27:24 +00:00
|
|
|
self.datastore.import_options(self.options)
|
2005-06-05 05:42:14 +00:00
|
|
|
|
2005-07-11 15:34:31 +00:00
|
|
|
# If there are default options, import their values into the datastore
|
|
|
|
if (module_info['DefaultOptions'])
|
|
|
|
self.datastore.import_options_from_hash(module_info['DefaultOptions'])
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
self.privileged = module_info['Privileged'] || false
|
2005-05-21 17:57:00 +00:00
|
|
|
end
|
2005-07-10 19:21:40 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Return's the module's framework reference name. This is the
|
|
|
|
# short name that end-users work with. Ex:
|
|
|
|
#
|
|
|
|
# win32/shell/reverse_tcp
|
|
|
|
#
|
|
|
|
def refname
|
|
|
|
return self.class.refname
|
|
|
|
end
|
2005-05-21 17:57:00 +00:00
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return the module's name
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def name
|
|
|
|
return module_info['Name']
|
|
|
|
end
|
|
|
|
|
2005-07-07 23:11:03 +00:00
|
|
|
#
|
|
|
|
# Returns the module's alias, if it has one. Otherwise, the module's
|
|
|
|
# name is returned.
|
|
|
|
#
|
|
|
|
def alias
|
2005-07-11 15:34:31 +00:00
|
|
|
return module_info['Alias']
|
2005-07-07 23:11:03 +00:00
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return the module's description
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def description
|
|
|
|
return module_info['Description']
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return the module's version information
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def version
|
|
|
|
return module_info['Version']
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return the module's abstract type
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def type
|
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return a comma separated list of author for this module
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def author_to_s
|
|
|
|
return author.collect { |author| author.to_s }.join(", ")
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Enumerate each author
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def each_author(&block)
|
|
|
|
author.each(&block)
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return a comma separated list of supported architectures, if any
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def arch_to_s
|
|
|
|
return arch.join(", ")
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Enumerate each architecture
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def each_arch(&block)
|
|
|
|
arch.each(&block)
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return whether or not the module supports the supplied architecture
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def arch?(what)
|
2005-05-22 07:14:16 +00:00
|
|
|
return true if (what == ARCH_ANY)
|
|
|
|
|
2005-05-21 17:57:00 +00:00
|
|
|
return arch.index(what) != nil
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
# Return a comma separated list of supported platforms, if any
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
2005-05-21 17:57:00 +00:00
|
|
|
def platform_to_s
|
2005-07-10 23:41:35 +00:00
|
|
|
return (platform.all?) ? [ "All" ] : platform.names
|
2005-05-21 17:57:00 +00:00
|
|
|
end
|
2005-06-05 05:42:14 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Returns whether or not the module requires or grants high privileges
|
|
|
|
#
|
|
|
|
def privileged?
|
|
|
|
return (privileged == true)
|
|
|
|
end
|
2005-07-09 19:35:29 +00:00
|
|
|
|
2005-07-11 02:03:48 +00:00
|
|
|
#
|
|
|
|
# The default communication subsystem for this module. We may need to move
|
|
|
|
# this somewhere else.
|
|
|
|
#
|
|
|
|
def comm
|
|
|
|
return Rex::Socket::Comm::Local
|
|
|
|
end
|
|
|
|
|
2005-07-11 16:46:47 +00:00
|
|
|
attr_reader :author, :arch, :platform, :references, :datastore, :options
|
2005-06-05 05:42:14 +00:00
|
|
|
attr_reader :privileged
|
2005-05-21 17:57:00 +00:00
|
|
|
|
|
|
|
protected
|
|
|
|
|
|
|
|
# Sets the modules unsupplied info fields to their default values
|
|
|
|
def set_defaults
|
2005-05-22 07:46:41 +00:00
|
|
|
self.module_info = {
|
2005-05-21 17:57:00 +00:00
|
|
|
'Name' => 'No module name',
|
|
|
|
'Description' => 'No module description',
|
|
|
|
'Version' => '0',
|
2005-07-10 23:41:35 +00:00
|
|
|
'Author' => '',
|
|
|
|
'Arch' => '',
|
|
|
|
'Platform' => '',
|
2005-06-05 05:42:14 +00:00
|
|
|
'Ref' => nil,
|
|
|
|
'Privileged' => false,
|
2005-05-22 07:46:41 +00:00
|
|
|
}.update(self.module_info)
|
2005-05-21 17:57:00 +00:00
|
|
|
end
|
|
|
|
|
2005-06-05 23:45:58 +00:00
|
|
|
#
|
|
|
|
# Register options with a specific owning class
|
|
|
|
#
|
|
|
|
def register_options(options, owner = self.class)
|
|
|
|
self.options.add_options(options, owner)
|
2005-07-11 02:03:48 +00:00
|
|
|
self.datastore.import_options(self.options)
|
2005-06-05 23:45:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Register advanced options with a specific owning class
|
|
|
|
#
|
|
|
|
def register_advanced_options(options, owner = self.class)
|
|
|
|
self.options.add_advanced_options(options, owner)
|
2005-07-11 02:03:48 +00:00
|
|
|
self.datastore.import_options(self.options)
|
2005-06-05 23:45:58 +00:00
|
|
|
end
|
|
|
|
|
2005-07-11 05:21:19 +00:00
|
|
|
#
|
|
|
|
# Removes the supplied options from the module's option container
|
|
|
|
# and data store
|
|
|
|
#
|
|
|
|
def deregister_options(*names)
|
|
|
|
names.each { |name|
|
|
|
|
self.options.remove_option(name)
|
|
|
|
self.datastore.delete(name)
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2005-06-04 22:26:42 +00:00
|
|
|
#
|
|
|
|
# Checks to see if a derived instance of a given module implements a method
|
|
|
|
# beyond the one that is provided by a base class. This is a pretty lame
|
|
|
|
# way of doing it, but I couldn't find a better one, so meh.
|
|
|
|
#
|
|
|
|
def derived_implementor?(parent, method_name)
|
|
|
|
(self.method(method_name).to_s.match(/#{parent.to_s}[^:]/)) ? false : true
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
|
|
|
# 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|
|
2005-07-11 05:15:30 +00:00
|
|
|
merge_check_key(info, name, val)
|
|
|
|
}
|
|
|
|
|
|
|
|
return info
|
|
|
|
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)
|
2005-07-09 00:24:02 +00:00
|
|
|
info[name] = val
|
|
|
|
end
|
2005-07-11 05:15:30 +00:00
|
|
|
# Otherwise, perform the merge operation like normal
|
|
|
|
else
|
|
|
|
merge_check_key(info, name, val)
|
2005-06-05 05:42:14 +00:00
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
return info
|
|
|
|
end
|
|
|
|
|
2005-07-11 05:15:30 +00:00
|
|
|
#
|
|
|
|
# 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}"))
|
|
|
|
eval("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?(Array) == false)
|
|
|
|
curr = info[name]
|
|
|
|
info[name] = [ curr, val ] if (val != curr)
|
|
|
|
# Otherwise, just append this item to the array entry
|
|
|
|
else
|
|
|
|
if (info[name].include?(val) == false)
|
|
|
|
info[name] << val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
# Otherwise, just set the value equal if no current value
|
|
|
|
# exists
|
|
|
|
else
|
|
|
|
info[name] = val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-07-09 00:24:02 +00:00
|
|
|
#
|
|
|
|
# Merge aliases with an underscore delimiter
|
|
|
|
#
|
|
|
|
def merge_info_alias(info, val)
|
|
|
|
merge_info_string(info, 'Alias', val, '_')
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Merges the module name
|
|
|
|
#
|
|
|
|
def merge_info_name(info, val)
|
|
|
|
merge_info_string(info, 'Name', val)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Merges the module description
|
|
|
|
#
|
|
|
|
def merge_info_description(info, val)
|
|
|
|
merge_info_string(info, 'Description', val)
|
|
|
|
end
|
|
|
|
|
2005-07-10 00:16:48 +00:00
|
|
|
#
|
|
|
|
# Merge the module version
|
|
|
|
#
|
|
|
|
def merge_info_version(info, val)
|
|
|
|
merge_info_string(info, 'Version', val)
|
|
|
|
end
|
|
|
|
|
2005-07-09 00:24:02 +00:00
|
|
|
#
|
|
|
|
# Merges a given key in the info hash with a delimiter
|
|
|
|
#
|
|
|
|
def merge_info_string(info, key, val, delim = ', ')
|
|
|
|
if (info[key])
|
|
|
|
info[key] = val + delim + info[key]
|
|
|
|
else
|
|
|
|
info[key] = val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-06-05 05:42:14 +00:00
|
|
|
#
|
|
|
|
# Merges options
|
|
|
|
#
|
|
|
|
def merge_info_options(info, val, advanced = false)
|
|
|
|
key_name = ((advanced) ? 'Advanced' : '') + 'Options'
|
|
|
|
|
|
|
|
new_cont = OptionContainer.new
|
|
|
|
new_cont.add_options(val, advanced)
|
|
|
|
cur_cont = OptionContainer.new
|
|
|
|
cur_cont.add_options(info[key_name] || [], advanced)
|
|
|
|
|
|
|
|
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 advanced options
|
|
|
|
#
|
|
|
|
def merge_info_advancedoptions(info, val)
|
|
|
|
merge_info_options(info, val, true)
|
|
|
|
end
|
|
|
|
|
2005-05-21 17:57:00 +00:00
|
|
|
attr_accessor :module_info
|
2005-07-11 16:46:47 +00:00
|
|
|
attr_writer :author, :arch, :platform, :references, :datastore, :options
|
2005-06-05 05:42:14 +00:00
|
|
|
attr_writer :privileged
|
2005-05-21 17:57:00 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
|
2005-06-05 00:03:23 +00:00
|
|
|
#
|
|
|
|
# Alias the data types so people can reference them just by Msf:: and not
|
|
|
|
# Msf::Module::
|
|
|
|
#
|
|
|
|
Author = Msf::Module::Author
|
|
|
|
Reference = Msf::Module::Reference
|
|
|
|
SiteReference = Msf::Module::SiteReference
|
|
|
|
Platform = Msf::Module::Platform
|
|
|
|
Target = Msf::Module::Target
|
|
|
|
|
2005-05-21 17:57:00 +00:00
|
|
|
end
|