support for generic payloads

git-svn-id: file:///home/svn/framework3/trunk@3843 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Miller 2006-08-26 02:13:25 +00:00
parent 190922400e
commit ea06abe5bb
8 changed files with 406 additions and 10 deletions

View File

@ -11,10 +11,6 @@ module Msf
###
module Exception
include Rex::Exception
def to_s
"A framework exception occurred."
end
end
###
@ -231,6 +227,10 @@ class IncompatiblePayloadError < ArgumentError
attr_reader :pname
end
class NoCompatiblePayloadError < ArgumentError
include Exception
end
##
#
# NOP exceptions

View File

@ -353,7 +353,7 @@ class Exploit < Msf::Module
# This method generates a non-cached payload which is typically useful for
# passive exploits that will have more than one client.
#
def generate_single_payload(pinst = nil)
def generate_single_payload(pinst = nil, platform = nil, arch = nil)
if (target == nil)
raise MissingTargetError, "No target has been specified.",
caller
@ -368,6 +368,28 @@ class Exploit < Msf::Module
caller
end
# If this is a generic payload, then we should specify the platform
# and architecture so that it knows how to pass things on.
if real_payload.kind_of?(Msf::Payload::Generic)
# Convert the architecture specified into an array.
if arch and arch.kind_of?(String)
arch = [ arch ]
end
# Define the explicit platform and architecture information only if
# it's been specified.
if platform
real_payload.explicit_platform = Msf::Module::PlatformList.transform(platform)
end
if arch
real_payload.explicit_arch = arch
end
# Force it to reset so that it will find updated information.
real_payload.reset
end
# Duplicate the exploit payload requirements
reqs = self.payload_info.dup
@ -389,10 +411,11 @@ class Exploit < Msf::Module
#
# Re-generates an encoded payload, typically called after something in the
# datastore has changed.
# datastore has changed. An optional platform and architecture can be
# supplied as well.
#
def regenerate_payload
generate_single_payload
def regenerate_payload(platform = nil, arch = nil)
generate_single_payload(nil, platform, arch)
end
##
@ -489,6 +512,21 @@ class Exploit < Msf::Module
return (target_idx) ? targets[target_idx.to_i] : nil
end
#
# Returns the target's platform, or the one assigned to the module itself.
#
def target_platform
(target and target.platform) ? target.platform : platform
end
#
# Returns the target's architecture, or the one assigned to the module
# itself.
#
def target_arch
(target and target.arch) ? target.arch : (arch == []) ? nil : arch
end
#
# Returns a list of compatible payloads based on platform, architecture,
# and size requirements.

View File

@ -157,6 +157,14 @@ module Handler
#
attr_accessor :exploit_config
#
# This will be non-nil if the handler has a parent payload that it
# was spawned from. Right now, this is only the case with generic
# payloads. The parent payload is used to create a session
# rather than using the instance itself.
#
attr_accessor :parent_payload
protected
#
@ -165,6 +173,9 @@ protected
# associated session.
#
def create_session(conn)
# If there is a parent payload, then use that in preference.
return parent_payload.create_session(conn) if (parent_payload)
# If the payload we merged in with has an associated session factory,
# allocate a new session.
if (self.session)

View File

@ -0,0 +1,253 @@
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,
'Platform' => ''))
register_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
#
# 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
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
if actual_payload.nil?
self.actual_payload = framework.payloads.find_payload(
actual_platform,
actual_arch,
handler_klass,
session,
payload_type)
dlog("Selected payload #{actual_payload.refname} from generic payload #{refname}", 'core', LEV_2)
if actual_payload.nil?
raise NoCompatiblePayloadError, "Could not locate a compatible payload for #{actual_platform}/#{actual_arch}"
else
# 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
end
end
end
end
end

View File

@ -94,7 +94,12 @@ class PayloadSet < ModuleSet
add_single(p, name, op[5])
# Cache the payload's size
sizes[name] = p.new.size
begin
sizes[name] = p.new.size
# Don't cache generic payload sizes.
rescue NoCompatiblePayloadError
end
}
# Recalculate stagers and stages
@ -197,7 +202,7 @@ class PayloadSet < ModuleSet
# also convey other information about the module, such as
# the platforms and architectures it supports
payload_type_modules[instance.payload_type][name] = pinfo
# If the payload happens to be a single, but has no defined
# connection, then it can also be staged. Insert it into
# the staged list.
@ -208,6 +213,36 @@ class PayloadSet < ModuleSet
end
end
#
# Looks for a payload that matches the specified requirements and
# returns an instance of that payload.
#
def find_payload(platform, arch, handler, session, payload_type)
# Pre-filter based on platform and architecture.
each_module(
'Platform' => platform,
'Arch' => arch) { |name, mod|
p = mod.new
# We can't substitute one generic with another one.
next if (p.kind_of?(Msf::Payload::Generic))
# Check to see if the handler classes match.
next if (handler and p.handler_klass != handler)
# Check to see if the session classes match.
next if (session and p.session != session)
# Check for matching payload types
next if (payload_type and p.payload_type != payload_type)
return p
}
return nil
end
#
# This method adds a single payload to the set and adds it to the singles
# hash.

View File

@ -14,6 +14,7 @@ class Exploits::Test::Multi::Aggressive < Msf::Exploit::Remote
'Author' => 'skape',
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Arch' => 'x86',
'Payload' =>
{
'Space' => 1000,

View File

@ -0,0 +1,29 @@
require 'msf/core'
require 'msf/core/payload/generic'
require 'msf/core/handler/bind_tcp'
module Msf
module Payloads
module Singles
module Generic
module ShellBindTcp
include Msf::Payload::Single
include Msf::Payload::Generic
def initialize(info = {})
super(merge_info(info,
'Name' => 'Generic Command Shell, Bind TCP Inline',
'Version' => '$Revision: 3425 $',
'Description' => 'Listen for a connection and spawn a command shell',
'Author' => 'skape',
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::BindTcp,
'Session' => Msf::Sessions::CommandShell
))
end
end
end end end end

View File

@ -0,0 +1,29 @@
require 'msf/core'
require 'msf/core/payload/generic'
require 'msf/core/handler/reverse_tcp'
module Msf
module Payloads
module Singles
module Generic
module ShellReverseTcp
include Msf::Payload::Single
include Msf::Payload::Generic
def initialize(info = {})
super(merge_info(info,
'Name' => 'Generic Command Shell, Reverse TCP Inline',
'Version' => '$Revision: 3425 $',
'Description' => 'Connect back to attacker and spawn a command shell',
'Author' => 'skape',
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::CommandShell
))
end
end
end end end end