Files
metasploit-gs/lib/msf/core/module.rb
T
Brent Cook 6fb6570f99 delete old feature detection code from exploit base
This deletes some old code that apparently has been broken and somewhat unused for many years.

The 'derived_implementor?' method for modules relies on the debug output from Ruby in order to tell of a class implements a method, but the regex it used didn't work properly with any modern Ruby version until 2.5.x. This caused a random sleep to get inserted into certain payload staging operations, which actively breaks staging in certain scenarios (I'm not trying to address that here).

This also removes some ancient module feature detection code, which also is entirely unused today.
2018-04-07 12:47:42 -05:00

368 lines
10 KiB
Ruby

# -*- coding: binary -*-
require 'msf/core'
module Msf
autoload :OptionContainer, 'msf/core/option_container'
###
#
# 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, description, version,
# authors, etc) and by managing the module's data store.
#
###
class Module
autoload :Arch, 'msf/core/module/arch'
autoload :Auth, 'msf/core/module/auth'
autoload :Author, 'msf/core/module/author'
autoload :AuxiliaryAction, 'msf/core/module/auxiliary_action'
autoload :Compatibility, 'msf/core/module/compatibility'
autoload :DataStore, 'msf/core/module/data_store'
autoload :Deprecated, 'msf/core/module/deprecated'
autoload :Failure, 'msf/core/module/failure'
autoload :FullName, 'msf/core/module/full_name'
autoload :HasActions, 'msf/core/module/has_actions'
autoload :ModuleInfo, 'msf/core/module/module_info'
autoload :ModuleStore, 'msf/core/module/module_store'
autoload :Network, 'msf/core/module/network'
autoload :Options, 'msf/core/module/options'
autoload :Platform, 'msf/core/module/platform'
autoload :PlatformList, 'msf/core/module/platform_list'
autoload :Privileged, 'msf/core/module/privileged'
autoload :Ranking, 'msf/core/module/ranking'
autoload :Reference, 'msf/core/module/reference'
autoload :Search, 'msf/core/module/search'
autoload :SiteReference, 'msf/core/module/reference'
autoload :Target, 'msf/core/module/target'
autoload :Type, 'msf/core/module/type'
autoload :UI, 'msf/core/module/ui'
autoload :UUID, 'msf/core/module/uuid'
include Msf::Module::Arch
include Msf::Module::Auth
include Msf::Module::Author
include Msf::Module::Compatibility
include Msf::Module::DataStore
include Msf::Module::FullName
include Msf::Module::ModuleInfo
include Msf::Module::ModuleStore
include Msf::Module::Network
include Msf::Module::Options
include Msf::Module::Privileged
include Msf::Module::Ranking
include Msf::Module::Search
include Msf::Module::Type
include Msf::Module::UI
include Msf::Module::UUID
# The key where a comma-separated list of Ruby module names will live in the
# datastore, consumed by #replicant to allow clean override of MSF module methods.
REPLICANT_EXTENSION_DS_KEY = 'ReplicantExtensions'
# Make include public so we can runtime extend
public_class_method :include
class << self
include Framework::Offspring
#
# This attribute holds the non-duplicated copy of the module
# implementation. This attribute is used for reloading purposes so that
# it can be re-duplicated.
#
attr_accessor :orig_cls
#
# The path from which the module was loaded.
#
attr_accessor :file_path
end
#
# Returns the class reference to the framework
#
def framework
self.class.framework
end
#
# This method allows modules to tell the framework if they are usable
# on the system that they are being loaded on in a generic fashion.
# By default, all modules are indicated as being usable. An example of
# where this is useful is if the module depends on something external to
# ruby, such as a binary.
#
def self.is_usable
true
end
#
# Creates an instance of an abstract module using the supplied information
# hash.
#
def initialize(info = {})
@module_info_copy = info.dup
self.module_info = info
generate_uuid
set_defaults
# Initialize module compatibility hashes
init_compat
# Fixup module fields as needed
info_fixups
# Transform some of the fields to arrays as necessary
self.author = Msf::Author.transform(module_info['Author'])
self.arch = Rex::Transformer.transform(module_info['Arch'], Array, [ String ], 'Arch')
self.platform = PlatformList.transform(module_info['Platform'])
self.references = Rex::Transformer.transform(module_info['References'], Array, [ SiteReference, Reference ], 'Ref')
# Create and initialize the option container for this module
self.options = Msf::OptionContainer.new
self.options.add_options(info['Options'], self.class)
self.options.add_advanced_options(info['AdvancedOptions'], self.class)
self.options.add_evasion_options(info['EvasionOptions'], self.class)
# Create and initialize the data store for this module
self.datastore = ModuleDataStore.new(self)
# Import default options into the datastore
import_defaults
self.privileged = module_info['Privileged'] || false
self.license = module_info['License'] || MSF_LICENSE
# Allow all modules to track their current workspace
register_advanced_options(
[
OptString.new('WORKSPACE', [ false, "Specify the workspace for this module" ]),
OptBool.new('VERBOSE', [ false, 'Enable detailed status messages', false ])
], Msf::Module)
end
#
# Creates a fresh copy of an instantiated module
#
def replicant
obj = self.class.new
self.instance_variables.each { |k|
v = instance_variable_get(k)
v = v.dup rescue v
obj.instance_variable_set(k, v)
}
obj.datastore = self.datastore.copy
obj.user_input = self.user_input
obj.user_output = self.user_output
obj.module_store = self.module_store.clone
obj.perform_extensions
obj
end
# Extends self with the constant list in the datastore
# @return [void]
def perform_extensions
if datastore[REPLICANT_EXTENSION_DS_KEY].present?
if datastore[REPLICANT_EXTENSION_DS_KEY].respond_to?(:each)
datastore[REPLICANT_EXTENSION_DS_KEY].each do |const|
self.extend(const)
end
else
fail "Invalid settings in datastore at key #{REPLICANT_EXTENSION_DS_KEY}"
end
end
end
# @param[Constant] One or more Ruby constants
# @return [void]
def register_extensions(*rb_modules)
datastore[REPLICANT_EXTENSION_DS_KEY] = [] unless datastore[REPLICANT_EXTENSION_DS_KEY].present?
rb_modules.each do |rb_mod|
datastore[REPLICANT_EXTENSION_DS_KEY] << rb_mod unless datastore[REPLICANT_EXTENSION_DS_KEY].include? rb_mod
end
end
#
# Returns the unduplicated class associated with this module.
#
def orig_cls
self.class.orig_cls
end
#
# The path to the file in which the module can be loaded from.
#
def file_path
self.class.file_path
end
#
# Checks to see if the target is vulnerable, returning unsupported if it's
# not supported.
#
# This method is designed to be overriden by exploit modules.
#
def check
Msf::Exploit::CheckCode::Unsupported
end
#
# Returns the current workspace
#
def workspace
self.datastore['WORKSPACE'] ||
(framework.db and framework.db.active and framework.db.workspace and framework.db.workspace.name)
end
#
# Returns the username that instantiated this module, this tries a handful of methods
# to determine what actual user ran this module.
#
def owner
# Generic method to configure a module owner
username = self.datastore['MODULE_OWNER'].to_s.strip
# Specific method used by the commercial products
if username.empty?
username = self.datastore['PROUSER'].to_s.strip
end
# Fallback when neither prior method is available, common for msfconsole
if username.empty?
username = (ENV['LOGNAME'] || ENV['USERNAME'] || ENV['USER'] || "unknown").to_s.strip
end
username
end
#
# Scans the parent module reference to populate additional information. This
# is used to inherit common settings (owner, workspace, parent uuid, etc).
#
def register_parent(ref)
self.datastore['WORKSPACE'] = (ref.datastore['WORKSPACE'] ? ref.datastore['WORKSPACE'].dup : nil)
self.datastore['PROUSER'] = (ref.datastore['PROUSER'] ? ref.datastore['PROUSER'].dup : nil)
self.datastore['MODULE_OWNER'] = ref.owner.dup
self.datastore['ParentUUID'] = ref.uuid.dup
end
#
# Return a comma separated list of supported platforms, if any.
#
def platform_to_s
platform.all? ? "All" : platform.names.join(", ")
end
#
# Checks to see if this module is compatible with the supplied platform
#
def platform?(what)
(platform & what).empty? == false
end
#
# Returns true if this module is being debugged.
#
def debugging?
datastore['DEBUG']
end
#
# Raises a RuntimeError failure message. This is meant to be used for all non-exploits,
# and allows specific classes to override.
#
# @param reason [String] A reason about the failure.
# @param msg [String] (Optional) A message about the failure.
# @raise [RuntimeError]
# @return [void]
# @note If you are writing an exploit, you don't use this API. Instead, please refer to the
# API documentation from lib/msf/core/exploit.rb.
# @see Msf::Exploit#fail_with
# @example
# fail_with('No Access', 'Unable to login')
#
def fail_with(reason, msg=nil)
raise RuntimeError, "#{reason.to_s}: #{msg}"
end
##
#
# Just some handy quick checks
#
##
#
# Returns false since this is the real module
#
def self.cached?
false
end
#
# The array of zero or more platforms.
#
attr_reader :platform
#
# The reference count for the module.
#
attr_reader :references
#
# The license under which this module is provided.
#
attr_reader :license
#
# The job identifier that this module is running as, if any.
#
attr_accessor :job_id
#
# The last exception to occur using this module
#
attr_accessor :error
# An opaque bag of data to attach to a module. This is useful for attaching
# some piece of identifying info on to a module before calling
# {Msf::Simple::Exploit#exploit_simple} or
# {Msf::Simple::Auxiliary#run_simple} for correlating where modules came
# from.
#
attr_accessor :user_data
protected
#
# Sets the modules unsupplied info fields to their default values.
#
def set_defaults
self.module_info = {
'Name' => 'No module name',
'Description' => 'No module description',
'Version' => '0',
'Author' => nil,
'Arch' => nil, # No architectures by default.
'Platform' => [], # No platforms by default.
'Ref' => nil,
'Privileged' => false,
'License' => MSF_LICENSE,
}.update(self.module_info)
self.module_store = {}
end
attr_writer :platform, :references # :nodoc:
attr_writer :privileged # :nodoc:
attr_writer :license # :nodoc:
end
end