metasploit-framework/lib/msf/core/payload/generic.rb

283 lines
6.2 KiB
Ruby

require 'msf/core'
module Msf
###
#
# The generic payloads are used to define a generalized payload type that
# is both architecture and platform independent. Under the hood, generic
# payloads seek out the correct payload for the appropriate architecture
# and platform that is being targeted.
#
###
module Payload::Generic
#
# Registers options that are common to all generic payloads, such as
# platform and arch.
#
def initialize(info = {})
super(merge_info(info,
'Arch' => ARCH_ALL - [ARCH_TTY],
'Platform' => ''))
register_advanced_options(
[
OptString.new('PLATFORM',
[
false,
"The platform that is being targeted",
nil
]),
OptString.new('ARCH',
[
false,
"The architecture that is being targeted",
nil
])
], Msf::Payload::Generic)
end
#
# Reset's the generic payload's internal state so that it can find a new
# actual payload.
#
def reset
self.explicit_arch = nil
self.explicit_platform = nil
self.actual_payload = nil
end
#
# Generate is different from other methods -- it will try to re-detect
# the actual payload in case settings have changed. Other methods will
# use the cached version if possible.
#
def generate
reset
redirect_to_actual(:generate)
end
#
# Overrides -- we have to redirect all potential payload methods
# to the actual payload so that they get handled appropriately, cuz
# we're like a proxy and stuff. We can't use method_undefined
# because all of these methods are actually defined.
#
def payload
redirect_to_actual(:payload)
end
def offsets
redirect_to_actual(:offsets)
end
def substitute_vars(*args)
redirect_to_actual(:substitute_vars, *args)
end
def replace_var(*args)
redirect_to_actual(:replace_var, *args)
end
def compatible_encoders
redirect_to_actual(:compatible_encoders)
end
def compatible_nops
redirect_to_actual(:compatible_nops)
end
def handle_connection(*args)
redirect_to_actual(:handle_connection, *args)
end
def on_session(*args)
redirect_to_actual(:on_session, *args)
end
#
# Stager overrides
#
def stage_payload
redirect_to_actual(:stage_payload)
end
def stage_offsets
redirect_to_actual(:stage_offsets)
end
def stager_payload
redirect_to_actual(:stager_payload)
end
def stager_offsets
redirect_to_actual(:stager_offsets)
end
def stage_over_connection?
redirect_to_actual(:stage_over_connection?)
end
def generate_stage
redirect_to_actual(:generate_stage)
end
def handle_connection_stage(*args)
redirect_to_actual(:handle_connection_stage, *args)
end
def handle_intermediate_stage(*args)
redirect_to_actual(:handle_intermediate_stage, *args)
end
def stage_prefix
redirect_to_actual(:stage_prefix)
end
def stage_prefix=(*args)
redirect_to_actual(:stage_prefix=, *args)
end
def user_input=(h)
@user_input = h
redirect_to_actual(:user_input, h) if actual_payload
end
def user_output=(h)
@user_output = h
redirect_to_actual(:user_output, h) if actual_payload
end
#
# First, find the underlying payload and then pass all methods onto it.
#
def redirect_to_actual(name, *args)
find_actual_payload
actual_payload.send(name, *args)
end
#
# Accessor that makes it possible to define an explicit platform. This is
# used for things like payload regeneration.
#
attr_accessor :explicit_platform
#
# Accessor that makes it possible to define an explicit architecture. This
# is used for things like payload regeneration.
#
attr_accessor :explicit_arch
protected
#
# The actual underlying platform/arch-specific payload instance that should
# be used.
#
attr_accessor :actual_payload
#
# Returns the actual platform that should be used for the payload.
#
def actual_platform
platform = nil
if explicit_platform.nil? == false
platform = explicit_platform
elsif datastore['PLATFORM']
platform = datastore['PLATFORM']
elsif assoc_exploit
platform = assoc_exploit.target_platform
end
# If we still have an invalid platform, then we suck.
if platform.nil?
raise NoCompatiblePayloadError, "A platform could not be determined by the generic payload"
elsif platform.kind_of?(String)
platform = Msf::Module::PlatformList.transform(platform)
end
return platform
end
#
# Returns the actual architecture that should be used for the payload.
#
def actual_arch
arch = nil
if explicit_arch.nil? == false
arch = explicit_arch
elsif datastore['ARCH']
arch = datastore['ARCH']
elsif assoc_exploit
arch = assoc_exploit.target_arch || ARCH_X86
end
# If we still have an invalid architecture, then we suck.
if arch.nil?
raise NoCompatiblePayloadError, "An architecture could not be determined by the generic payload"
elsif arch.kind_of?(String)
arch = [ arch ]
end
return arch
end
def find_actual_payload
return if not actual_payload.nil?
# Look for one based on the exploit's compatible set
if(assoc_exploit)
self.actual_payload = framework.payloads.find_payload_from_set(
assoc_exploit.compatible_payloads,
actual_platform,
actual_arch,
handler_klass,
session,
payload_type)
end
# Fall back to the generic match (ignores size, compat flags, etc)
if(actual_payload.nil?)
self.actual_payload = framework.payloads.find_payload(
actual_platform,
actual_arch,
handler_klass,
session,
payload_type)
end
if actual_payload.nil?
raise NoCompatiblePayloadError, "Could not locate a compatible payload for #{actual_platform.names.join("/")}/#{actual_arch}"
else
dlog("Selected payload #{actual_payload.refname} from generic payload #{refname}", 'core', LEV_2)
# Share our datastore with the actual payload so that it has the
# appropriate values to substitute ad so on.
self.actual_payload.share_datastore(self.datastore)
# Set the associated exploit for the payload.
self.actual_payload.assoc_exploit = self.assoc_exploit
# Set the parent payload to this payload so that we can handle
# things like session creation (so that event notifications will
# work properly)
self.actual_payload.parent_payload = self
# Set the cached user_input/user_output
self.actual_payload.user_input = self.user_input
self.actual_payload.user_output = self.user_output
end
end
end
end