2012-06-29 05:18:28 +00:00
|
|
|
# -*- coding: binary -*-
|
2005-07-09 21:18:49 +00:00
|
|
|
require 'msf/core'
|
2010-01-15 00:32:48 +00:00
|
|
|
require 'msf/core/module'
|
2005-05-21 17:57:00 +00:00
|
|
|
|
|
|
|
module Msf
|
|
|
|
|
2005-06-04 18:55:20 +00:00
|
|
|
###
|
|
|
|
#
|
2005-11-02 16:49:45 +00:00
|
|
|
# This module exposes an interface that is used when wanting to receive
|
|
|
|
# notifications about events pertaining to exploitation.
|
2005-06-04 18:55:20 +00:00
|
|
|
#
|
|
|
|
###
|
2005-10-30 22:20:29 +00:00
|
|
|
module ExploitEvent
|
2005-05-21 17:57:00 +00:00
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
# This method is called when an exploit succeeds.
|
|
|
|
#
|
|
|
|
def on_exploit_success(exploit, session)
|
|
|
|
end
|
2005-05-21 17:57:00 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
|
2005-06-04 18:55:20 +00:00
|
|
|
###
|
|
|
|
#
|
|
|
|
# The exploit class acts as the base class for all exploit modules. It
|
|
|
|
# provides a common interface for interacting with exploits at the most basic
|
|
|
|
# level.
|
|
|
|
#
|
|
|
|
###
|
|
|
|
class Exploit < Msf::Module
|
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
require 'msf/core/post'
|
|
|
|
require 'msf/core/exploit/local'
|
|
|
|
|
|
|
|
##
|
|
|
|
# Exceptions
|
|
|
|
##
|
|
|
|
|
|
|
|
# Indicate that the exploit should abort because it has completed
|
|
|
|
class Complete < RuntimeError
|
|
|
|
end
|
|
|
|
|
|
|
|
# Indicate that the exploit should abort because it has failed
|
|
|
|
class Failed < RuntimeError
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Default compatibility settings for exploit modules.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
module CompatDefaults
|
|
|
|
#
|
|
|
|
# Default compatibility specifications for payloads
|
|
|
|
#
|
|
|
|
Payload =
|
|
|
|
{
|
|
|
|
# Support reverse, bind, and noconn connection types
|
|
|
|
# for all exploits unless expressly disabled.
|
|
|
|
'ConnectionType' => 'reverse bind noconn none tunnel',
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# The various check codes that can be returned from the ``check'' routine.
|
2014-01-21 02:10:50 +00:00
|
|
|
# Please read the following wiki to learn how these codes are used:
|
|
|
|
# https://github.com/rapid7/metasploit-framework/wiki/How-to-write-a-check()-method
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
##
|
|
|
|
module CheckCode
|
|
|
|
|
|
|
|
#
|
2014-01-17 19:35:17 +00:00
|
|
|
# Can't tell if the target is exploitable or not. This is recommended if the module fails to
|
|
|
|
# retrieve enough information from the target machine, such as due to a timeout.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
Unknown = [ 'unknown', "Cannot reliably check exploitability."]
|
|
|
|
|
|
|
|
#
|
2014-01-17 19:35:17 +00:00
|
|
|
# The target is safe and is therefore not exploitable. This is recommended after the check
|
|
|
|
# fails to trigger the vulnerability, or even detect the service.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
Safe = [ 'safe', "The target is not exploitable." ]
|
|
|
|
|
|
|
|
#
|
2014-01-17 19:35:17 +00:00
|
|
|
# The target is running the service in question, but the check fails to determine whether
|
|
|
|
# the target is vulnerable or not.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
Detected = [ 'detected', "The target service is running, but could not be validated." ]
|
|
|
|
|
|
|
|
#
|
2014-01-17 19:35:17 +00:00
|
|
|
# The target appears to be vulnerable. This is recommended if the vulnerability is determined
|
2014-01-19 22:01:38 +00:00
|
|
|
# based on passive reconnaissance. For example: version, banner grabbing, or having the resource
|
2014-01-17 19:35:17 +00:00
|
|
|
# that's known to be vulnerable.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
Appears = [ 'appears', "The target appears to be vulnerable." ]
|
|
|
|
|
|
|
|
#
|
2014-01-17 19:50:23 +00:00
|
|
|
# The target is vulnerable. Only used if the check is able to actually take advantage of the
|
|
|
|
# bug, and obtain hard evidence. For example: executing a command on the target machine, and
|
2014-01-17 19:35:17 +00:00
|
|
|
# retrieve the output.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
Vulnerable = [ 'vulnerable', "The target is vulnerable." ]
|
|
|
|
|
|
|
|
#
|
2014-01-26 07:14:11 +00:00
|
|
|
# The module does not support the check method.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
2014-01-26 07:14:11 +00:00
|
|
|
Unsupported = [ 'unsupported', "This module does not support check." ]
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# The various basic types of exploits
|
|
|
|
#
|
|
|
|
module Type
|
|
|
|
|
|
|
|
#
|
|
|
|
# Indicates that the exploit is a remote exploit.
|
|
|
|
#
|
|
|
|
Remote = "remote"
|
|
|
|
|
|
|
|
#
|
|
|
|
# Indicates that the exploit is a local exploit.
|
|
|
|
#
|
|
|
|
Local = "local"
|
|
|
|
|
|
|
|
#
|
|
|
|
# Indicates that the exploit can work anywhere it damn pleases.
|
|
|
|
#
|
|
|
|
Omni = "omnipresent"
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# The types of stances an exploit can take, such as passive or aggressive.
|
|
|
|
# Stances indicate whether or not the exploit triggers the exploit without
|
|
|
|
# waiting for one or more conditions to be met (aggressive) or whether it
|
|
|
|
# must wait for certain conditions to be satisfied before the exploit can
|
|
|
|
# be initiated (passive)
|
|
|
|
#
|
|
|
|
module Stance
|
|
|
|
|
|
|
|
#
|
|
|
|
# Used to indicate that an exploit takes an aggressive stance. This
|
|
|
|
# means that the exploit proactively triggers a vulnerability.
|
|
|
|
#
|
|
|
|
Aggressive = "aggressive"
|
|
|
|
|
|
|
|
#
|
|
|
|
# Used to indicate that an exploit takes a passive stance. This means
|
|
|
|
# that the exploit waits for interaction from a client or other entity
|
|
|
|
# before being able to trigger the vulnerability.
|
|
|
|
#
|
|
|
|
Passive = "passive"
|
|
|
|
end
|
|
|
|
|
|
|
|
###
|
|
|
|
#
|
|
|
|
# The remote exploit class is a specialization of the exploit module class
|
|
|
|
# that is geared toward exploits that are performed against targets other than
|
|
|
|
# the local machine. This typically implies exploiting other machines via a
|
|
|
|
# network connection, though it is not limited to this scope.
|
|
|
|
#
|
|
|
|
###
|
|
|
|
class Remote < Exploit
|
|
|
|
|
|
|
|
#
|
|
|
|
# Initializes the socket array.
|
|
|
|
#
|
|
|
|
def initialize(info)
|
|
|
|
super
|
|
|
|
|
|
|
|
self.sockets = Array.new
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the fact that this exploit is a remote exploit.
|
|
|
|
#
|
|
|
|
def exploit_type
|
|
|
|
Exploit::Type::Remote
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Adds a socket to the list of sockets opened by this exploit.
|
|
|
|
#
|
|
|
|
def add_socket(sock)
|
|
|
|
self.sockets << sock
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Removes a socket from the list of sockets.
|
|
|
|
#
|
|
|
|
def remove_socket(sock)
|
|
|
|
self.sockets.delete(sock)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# This method is called once a new session has been created on behalf of
|
|
|
|
# this exploit instance and all socket connections created by this
|
|
|
|
# exploit should be closed.
|
|
|
|
#
|
|
|
|
def abort_sockets
|
|
|
|
sockets.delete_if { |sock|
|
|
|
|
|
|
|
|
begin
|
|
|
|
sock.close
|
|
|
|
rescue ::Exception
|
|
|
|
end
|
|
|
|
true
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
|
|
|
#
|
|
|
|
# The list of sockets established by this exploit.
|
|
|
|
#
|
|
|
|
attr_accessor :sockets
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Load all of the exploit mixins
|
|
|
|
#
|
|
|
|
require 'msf/core/exploit/mixins'
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns an array of all of the exploit mixins. Lame algorithm right now.
|
|
|
|
# We search the Msf::Exploit namespace for all modules that do not have any
|
|
|
|
# constants in them. In the future we can replace this with a better
|
|
|
|
# algorithm. It's just important that it returns an array of all of the
|
|
|
|
# mixin modules.
|
|
|
|
#
|
|
|
|
# @return [Array]
|
|
|
|
def self.mixins
|
|
|
|
mixins = []
|
|
|
|
wl = [ Msf::Exploit ]
|
|
|
|
visited = {}
|
|
|
|
|
|
|
|
until wl.length == 0
|
|
|
|
wl.delete_if { |mod|
|
|
|
|
mod.constants.each { |const|
|
|
|
|
child = mod.const_get(const)
|
|
|
|
|
|
|
|
next if child.to_s !~ /^Msf::Exploit/
|
|
|
|
|
|
|
|
next if visited[child]
|
|
|
|
|
|
|
|
next if child.kind_of?(::Module) == false
|
|
|
|
|
|
|
|
visited[child] = true
|
|
|
|
|
|
|
|
if child.constants.length > 0
|
|
|
|
wl << child
|
|
|
|
else
|
|
|
|
mixins << child
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
return mixins
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Creates an instance of the exploit module. Mad skillz.
|
|
|
|
#
|
|
|
|
def initialize(info = {})
|
|
|
|
|
|
|
|
# Ghetto compat mirroring for payload compatibilities. This mirrors
|
|
|
|
#
|
|
|
|
# Payload => Compat => xyz
|
|
|
|
#
|
|
|
|
# to
|
|
|
|
#
|
|
|
|
# Compat => Payload => xyz
|
|
|
|
if (info['Payload'] and info['Payload']['Compat'])
|
|
|
|
info['Compat'] = Hash.new if (info['Compat'] == nil)
|
|
|
|
info['Compat']['Payload'] = Hash.new if (info['Compat']['Payload'] == nil)
|
|
|
|
info['Compat']['Payload'].update(info['Payload']['Compat'])
|
|
|
|
end
|
|
|
|
|
|
|
|
# Call the parent constructor after making any necessary modifications
|
|
|
|
# to the information hash.
|
|
|
|
super(info)
|
|
|
|
|
|
|
|
self.targets = Rex::Transformer.transform(info['Targets'], Array,
|
|
|
|
[ Target ], 'Targets')
|
|
|
|
self.default_target = info['DefaultTarget']
|
|
|
|
self.payload_info = info['Payload'] || {}
|
|
|
|
self.successful = false
|
|
|
|
self.session_count = 0
|
|
|
|
self.active_timeout = 120
|
|
|
|
self.fail_reason = Failure::None
|
|
|
|
|
|
|
|
if (info['Payload'] and info['Payload']['ActiveTimeout'])
|
|
|
|
self.active_timeout = info['Payload']['ActiveTimeout'].to_i
|
|
|
|
end
|
|
|
|
|
|
|
|
# All exploits can increase the delay when waiting for a session.
|
|
|
|
# However, this only applies to aggressive exploits.
|
|
|
|
if aggressive?
|
|
|
|
register_advanced_options(
|
|
|
|
[
|
|
|
|
OptInt.new('WfsDelay', [ false, "Additional delay when waiting for a session", 0 ])
|
|
|
|
], Msf::Exploit)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Allow all exploits to leverage context keyed encoding
|
|
|
|
register_advanced_options(
|
|
|
|
[
|
|
|
|
OptBool.new('EnableContextEncoding', [ false, "Use transient context when encoding payloads", false ]),
|
|
|
|
OptPath.new('ContextInformationFile', [ false, "The information file that contains context information", nil ])
|
|
|
|
], Msf::Exploit)
|
|
|
|
|
|
|
|
# Allow all exploits to disable their payload handlers
|
|
|
|
register_advanced_options(
|
|
|
|
[
|
|
|
|
OptBool.new('DisablePayloadHandler', [ false, "Disable the handler code for the selected payload", false ])
|
|
|
|
], Msf::Exploit)
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Core exploit interface
|
|
|
|
#
|
|
|
|
# These are the methods that exploits will override to perform various
|
|
|
|
# tasks, such as checking a target to see if it's vulnerable, automatically
|
|
|
|
# selecting a target, or performing an exploit.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Kicks off the actual exploit. Prior to this call, the framework will
|
|
|
|
# have validated the data store using the options associated with this
|
|
|
|
# exploit module. It will also pre-generate the desired payload, though
|
|
|
|
# exploits can re-generate the payload if necessary.
|
|
|
|
#
|
|
|
|
# This method is designed to be overriden by exploit modules.
|
|
|
|
#
|
|
|
|
def exploit
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Performs last-minute sanity checking of auxiliary parameters. This method
|
|
|
|
# is called during automated exploitation attempts and allows an
|
|
|
|
# auxiliary module to filter bad attempts, obtain more information, and choose
|
|
|
|
# better parameters based on the available data. Returning anything that
|
|
|
|
# evaluates to "false" will cause this specific auxiliary attempt to
|
|
|
|
# be skipped. This method can and will change datastore values and
|
|
|
|
# may interact with the backend database.
|
|
|
|
#
|
|
|
|
def autofilter
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Provides a list of ports that can be used for matching this module
|
|
|
|
# against target systems.
|
|
|
|
#
|
|
|
|
def autofilter_ports
|
|
|
|
@autofilter_ports || []
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Provides a list of services that can be used for matching this module
|
|
|
|
# against target systems.
|
|
|
|
#
|
|
|
|
def autofilter_services
|
|
|
|
@autofilter_services || []
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Adds a port into the list of ports
|
|
|
|
#
|
|
|
|
def register_autofilter_ports(ports=[])
|
|
|
|
@autofilter_ports ||= []
|
|
|
|
@autofilter_ports << ports
|
|
|
|
@autofilter_ports.flatten!
|
|
|
|
@autofilter_ports.uniq!
|
|
|
|
end
|
|
|
|
|
|
|
|
def register_autofilter_services(services=[])
|
|
|
|
@autofilter_services ||= []
|
|
|
|
@autofilter_services << services
|
|
|
|
@autofilter_services.flatten!
|
|
|
|
@autofilter_services.uniq!
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Prepares the module for exploitation, initializes any state, and starts
|
|
|
|
# the payload handler.
|
|
|
|
#
|
|
|
|
def setup
|
|
|
|
# Reset the session counts to zero.
|
|
|
|
reset_session_counts
|
|
|
|
|
|
|
|
return if not payload_instance
|
|
|
|
return if not handler_enabled?
|
|
|
|
|
|
|
|
# Configure the payload handler
|
|
|
|
payload_instance.exploit_config = {
|
|
|
|
'active_timeout' => self.active_timeout
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set up the payload handlers
|
|
|
|
payload_instance.setup_handler
|
|
|
|
|
|
|
|
# Start the payload handler
|
|
|
|
payload_instance.start_handler
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Performs any cleanup that may be necessary, such as disconnecting
|
|
|
|
# connections and any other such fun things. If a payload is active then
|
|
|
|
# its handler cleanup routines are called as well.
|
|
|
|
#
|
|
|
|
def cleanup
|
|
|
|
if (payload_instance and handler_enabled?)
|
|
|
|
payload_instance.cleanup_handler
|
|
|
|
end
|
|
|
|
self.abort_sockets if self.respond_to?(:abort_sockets)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generates the encoded version of the supplied payload using the payload
|
|
|
|
# requirements specific to this exploit. The encoded instance is returned
|
|
|
|
# to the caller. This method is exposed in the manner that it is such
|
|
|
|
# that passive exploits and re-generate an encoded payload on the fly
|
|
|
|
# rather than having to use the pre-generated one.
|
|
|
|
#
|
|
|
|
# The return value is an EncodedPayload instance.
|
|
|
|
#
|
|
|
|
def generate_payload(pinst = nil)
|
|
|
|
# Set the encoded payload to the result of the encoding process
|
|
|
|
self.payload = generate_single_payload(pinst)
|
|
|
|
|
|
|
|
# Save the payload instance
|
|
|
|
self.payload_instance = (pinst) ? pinst : self.payload_instance
|
|
|
|
|
|
|
|
return self.payload
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Allows arbitrary shellcode to be encoded from within an exploit
|
|
|
|
#
|
|
|
|
def encode_shellcode_stub(code, badchars=payload_badchars)
|
|
|
|
platform = self.platform
|
|
|
|
if(self.payload_instance)
|
|
|
|
self.payload_instance.platform
|
|
|
|
end
|
|
|
|
compatible_encoders.each do |name, mod|
|
|
|
|
begin
|
|
|
|
enc = framework.encoders.create(name)
|
|
|
|
raw = enc.encode(code, badchars, nil, platform)
|
|
|
|
return raw if raw
|
|
|
|
rescue ::Exception
|
|
|
|
end
|
|
|
|
end
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Allows the payload handler to spawn a new monitor
|
|
|
|
#
|
|
|
|
def add_handler(opts={})
|
|
|
|
return if not payload_instance
|
|
|
|
return if not handler_enabled?
|
|
|
|
payload_instance.add_handler(opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# 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, platform = nil, arch = nil, explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target == nil)
|
|
|
|
raise MissingTargetError, "No target has been specified.",
|
|
|
|
caller
|
|
|
|
end
|
|
|
|
|
|
|
|
# If a payload instance was supplied, use it, otherwise
|
|
|
|
# use the active payload instance
|
|
|
|
real_payload = (pinst) ? pinst : self.payload_instance
|
|
|
|
|
|
|
|
if (real_payload == nil)
|
|
|
|
raise MissingPayloadError, "No payload has been selected.",
|
|
|
|
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
|
|
|
|
|
|
|
|
# Pass save register requirements to the NOP generator
|
|
|
|
reqs['Space'] = payload_space(explicit_target)
|
|
|
|
reqs['SaveRegisters'] = nop_save_registers(explicit_target)
|
|
|
|
reqs['Prepend'] = payload_prepend(explicit_target)
|
|
|
|
reqs['PrependEncoder'] = payload_prepend_encoder(explicit_target)
|
|
|
|
reqs['BadChars'] = payload_badchars(explicit_target)
|
|
|
|
reqs['Append'] = payload_append(explicit_target)
|
2014-02-04 15:41:10 +00:00
|
|
|
reqs['AppendEncoder'] = payload_append_encoder(explicit_target)
|
2013-08-30 21:28:33 +00:00
|
|
|
reqs['MaxNops'] = payload_max_nops(explicit_target)
|
|
|
|
reqs['MinNops'] = payload_min_nops(explicit_target)
|
|
|
|
reqs['Encoder'] = datastore['ENCODER']
|
|
|
|
reqs['Nop'] = datastore['NOP']
|
|
|
|
reqs['EncoderType'] = payload_encoder_type(explicit_target)
|
|
|
|
reqs['EncoderOptions'] = payload_encoder_options(explicit_target)
|
|
|
|
reqs['ExtendedOptions'] = payload_extended_options(explicit_target)
|
2014-02-21 21:49:39 +00:00
|
|
|
reqs['Exploit'] = self
|
2013-08-30 21:28:33 +00:00
|
|
|
|
|
|
|
# Pass along the encoder don't fall through flag
|
|
|
|
reqs['EncoderDontFallThrough'] = datastore['EncoderDontFallThrough']
|
|
|
|
|
|
|
|
# Incorporate any context encoding requirements that are needed
|
|
|
|
define_context_encoding_reqs(reqs)
|
|
|
|
|
|
|
|
# Call the encode begin routine.
|
|
|
|
encode_begin(real_payload, reqs)
|
|
|
|
|
|
|
|
# Generate the encoded payload.
|
|
|
|
encoded = EncodedPayload.create(real_payload, reqs)
|
|
|
|
|
|
|
|
# Call the encode end routine which is expected to return the actual
|
|
|
|
# encoded payload instance.
|
|
|
|
return encode_end(real_payload, reqs, encoded)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Re-generates an encoded payload, typically called after something in the
|
|
|
|
# datastore has changed. An optional platform and architecture can be
|
|
|
|
# supplied as well.
|
|
|
|
#
|
|
|
|
def regenerate_payload(platform = nil, arch = nil, explicit_target = nil)
|
|
|
|
generate_single_payload(nil, platform, arch, explicit_target)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Called prior to encoding a payload.
|
|
|
|
#
|
|
|
|
def encode_begin(real_payload, reqs)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Called after an encoded payload has been generated. This gives exploits
|
|
|
|
# or mixins a chance to alter the encoded payload.
|
|
|
|
#
|
|
|
|
def encode_end(real_payload, reqs, encoded)
|
|
|
|
encoded
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Feature detection
|
|
|
|
#
|
|
|
|
# These methods check to see if there is a derived implementation of
|
|
|
|
# various methods as a way of inferring whether or not a given exploit
|
|
|
|
# supports the feature.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns true if the exploit module supports the check method.
|
|
|
|
#
|
|
|
|
def supports_check?
|
|
|
|
derived_implementor?(Msf::Exploit, 'check')
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns true if the exploit module supports the exploit method.
|
|
|
|
#
|
|
|
|
def supports_exploit?
|
|
|
|
derived_implementor?(Msf::Exploit, 'exploit')
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns a hash of the capabilities this exploit module has support for,
|
|
|
|
# such as whether or not it supports check and exploit.
|
|
|
|
#
|
|
|
|
def capabilities
|
|
|
|
{
|
|
|
|
'check' => supports_check?,
|
|
|
|
'exploit' => supports_exploit?
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Getters/Setters
|
|
|
|
#
|
|
|
|
# Querying and set interfaces for some of the exploit's attributes.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns MODULE_EXPLOIT to indicate that this is an exploit module.
|
|
|
|
#
|
|
|
|
def self.type
|
2014-10-17 17:43:40 +00:00
|
|
|
Msf::MODULE_EXPLOIT
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns MODULE_EXPLOIT to indicate that this is an exploit module.
|
|
|
|
#
|
|
|
|
def type
|
2014-10-17 17:43:40 +00:00
|
|
|
Msf::MODULE_EXPLOIT
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# If we don't know the exploit type, then I guess it's omnipresent!
|
|
|
|
#
|
|
|
|
def exploit_type
|
|
|
|
Type::Omni
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generally, all exploits take an aggressive stance.
|
|
|
|
#
|
|
|
|
def stance
|
|
|
|
module_info['Stance'] || Stance::Aggressive
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns true if the exploit has an aggressive stance.
|
|
|
|
#
|
|
|
|
def aggressive?
|
2016-09-25 23:57:41 +00:00
|
|
|
(stance == Stance::Aggressive)
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns if the exploit has a passive stance.
|
|
|
|
#
|
|
|
|
def passive?
|
2016-09-25 23:57:41 +00:00
|
|
|
(stance == Stance::Passive)
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the active target for this exploit. If not target has been
|
|
|
|
# defined, nil is returned. If no target was defined but there is a
|
|
|
|
# default target, that one will be automatically used.
|
|
|
|
#
|
|
|
|
def target
|
|
|
|
target_idx = target_index
|
|
|
|
|
|
|
|
return (target_idx) ? targets[target_idx.to_i] : nil
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# The target index that has been selected.
|
|
|
|
#
|
|
|
|
def target_index
|
|
|
|
target_idx = datastore['TARGET']
|
|
|
|
|
|
|
|
# Use the default target if one was not supplied.
|
|
|
|
if (target_idx == nil and default_target and default_target >= 0)
|
|
|
|
target_idx = default_target
|
|
|
|
end
|
|
|
|
return (target_idx) ? 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
|
|
|
|
|
2016-12-20 23:39:09 +00:00
|
|
|
def normalize_platform_arch
|
2016-12-21 06:16:33 +00:00
|
|
|
c_platform = (target && target.platform) ? target.platform : platform
|
|
|
|
c_arch = (target && target.arch) ? target.arch : (arch == []) ? nil : arch
|
2016-12-20 23:39:09 +00:00
|
|
|
c_arch ||= [ ARCH_X86 ]
|
|
|
|
return c_platform, c_arch
|
|
|
|
end
|
2015-05-29 20:09:29 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Returns whether the requested payload is compatible with the module.
|
|
|
|
#
|
|
|
|
# @param [String] payload_name The payload name
|
|
|
|
# @return [TrueClass] Payload is compatible.
|
|
|
|
# @return [FalseClass] Payload is not compatible.
|
|
|
|
#
|
2016-12-20 23:39:09 +00:00
|
|
|
def is_payload_compatible?(name)
|
|
|
|
p = framework.payloads[name]
|
|
|
|
|
|
|
|
# Skip over payloads that are too big
|
|
|
|
return false if payload_space && p.cached_size && p.cached_size > payload_space
|
2015-05-29 20:07:59 +00:00
|
|
|
|
2016-12-20 23:39:09 +00:00
|
|
|
pi = p.new
|
|
|
|
|
|
|
|
# Are we compatible in terms of conventions and connections and
|
|
|
|
# what not?
|
|
|
|
return false if !compatible?(pi)
|
|
|
|
|
|
|
|
# If the payload is privileged but the exploit does not give
|
|
|
|
# privileged access, then fail it.
|
|
|
|
return false if !self.privileged && pi.privileged
|
|
|
|
|
|
|
|
return true
|
2015-05-29 20:07:59 +00:00
|
|
|
end
|
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
# Returns a list of compatible payloads based on platform, architecture,
|
|
|
|
# and size requirements.
|
|
|
|
#
|
|
|
|
def compatible_payloads
|
|
|
|
payloads = []
|
|
|
|
|
2016-12-20 23:39:09 +00:00
|
|
|
c_platform, c_arch = normalize_platform_arch
|
2013-08-30 21:28:33 +00:00
|
|
|
|
|
|
|
framework.payloads.each_module(
|
2016-12-20 23:39:09 +00:00
|
|
|
'Arch' => c_arch, 'Platform' => c_platform) { |name, mod|
|
|
|
|
payloads << [ name, mod ] if is_payload_compatible?(name)
|
2013-08-30 21:28:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return payloads;
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns a list of compatible encoders based on architecture
|
|
|
|
#
|
|
|
|
def compatible_encoders
|
|
|
|
encoders = []
|
|
|
|
|
2016-12-20 23:39:09 +00:00
|
|
|
c_platform, c_arch = normalize_platform_arch
|
2013-08-30 21:28:33 +00:00
|
|
|
|
|
|
|
framework.encoders.each_module_ranked(
|
2014-02-04 20:34:11 +00:00
|
|
|
'Arch' => c_arch, 'Platform' => c_platform) { |name, mod|
|
2013-08-30 21:28:33 +00:00
|
|
|
encoders << [ name, mod ]
|
|
|
|
}
|
|
|
|
|
|
|
|
return encoders;
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# This method returns the number of bytes that should be adjusted to the
|
|
|
|
# stack pointer prior to executing any code. The number of bytes to adjust
|
|
|
|
# is indicated to the routine through the payload 'StackAdjustment'
|
|
|
|
# attribute or through a target's payload 'StackAdjustment' attribute.
|
|
|
|
#
|
|
|
|
def stack_adjustment
|
|
|
|
if (target and target.payload_stack_adjustment)
|
|
|
|
adj = target.payload_stack_adjustment
|
|
|
|
else
|
|
|
|
adj = payload_info['StackAdjustment']
|
|
|
|
end
|
|
|
|
|
|
|
|
# Get the architecture for the current target or use the one specific to
|
|
|
|
# this exploit
|
|
|
|
arch = (target and target.arch) ? target.arch : self.arch
|
|
|
|
|
|
|
|
# Default to x86 if we can't find a list of architectures
|
|
|
|
if (arch and arch.empty? == false)
|
|
|
|
arch = arch.join(", ")
|
|
|
|
else
|
|
|
|
arch = 'x86'
|
|
|
|
end
|
|
|
|
|
|
|
|
(adj != nil) ? Rex::Arch::adjust_stack_pointer(arch, adj) || '' : ''
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Return any text that should be prepended to the payload. The payload
|
|
|
|
# module is passed so that the exploit can take a guess at architecture
|
|
|
|
# and platform if it's a multi exploit. This automatically takes into
|
|
|
|
# account any require stack adjustments.
|
|
|
|
#
|
|
|
|
def payload_prepend(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_prepend)
|
|
|
|
p = explicit_target.payload_prepend
|
|
|
|
else
|
|
|
|
p = payload_info['Prepend'] || ''
|
|
|
|
end
|
|
|
|
|
|
|
|
stack_adjustment + p
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Return any text that should be appended to the payload. The payload
|
|
|
|
# module is passed so that the exploit can take a guess at architecture
|
|
|
|
# and platform if it's a multi exploit.
|
|
|
|
#
|
|
|
|
def payload_append(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_append)
|
|
|
|
explicit_target.payload_append
|
|
|
|
else
|
|
|
|
payload_info['Append'] || ''
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Return any text that should be prepended to the encoder of the payload.
|
|
|
|
# The payload module is passed so that the exploit can take a guess
|
|
|
|
# at architecture and platform if it's a multi exploit.
|
|
|
|
#
|
|
|
|
def payload_prepend_encoder(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_prepend_encoder)
|
|
|
|
p = explicit_target.payload_prepend_encoder
|
|
|
|
else
|
|
|
|
p = payload_info['PrependEncoder'] || ''
|
|
|
|
end
|
|
|
|
|
|
|
|
p
|
|
|
|
end
|
|
|
|
|
2014-02-04 15:41:10 +00:00
|
|
|
#
|
|
|
|
# Return any text that should be appended to the encoder of the payload.
|
|
|
|
# The payload module is passed so that the exploit can take a guess
|
|
|
|
# at architecture and platform if it's a multi exploit.
|
|
|
|
#
|
|
|
|
def payload_append_encoder(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_append_encoder)
|
|
|
|
p = explicit_target.payload_append_encoder
|
|
|
|
else
|
|
|
|
p = payload_info['AppendEncoder'] || ''
|
|
|
|
end
|
|
|
|
|
|
|
|
p
|
|
|
|
end
|
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
# Maximum number of nops to use as a hint to the framework.
|
|
|
|
# Nil signifies that the framework should decide.
|
|
|
|
#
|
|
|
|
def payload_max_nops(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_max_nops)
|
|
|
|
explicit_target.payload_max_nops
|
|
|
|
else
|
|
|
|
payload_info['MaxNops'] || nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Minimum number of nops to use as a hint to the framework.
|
2015-04-13 08:21:41 +00:00
|
|
|
# Nil signifies that the framework should decide.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
def payload_min_nops(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_min_nops)
|
|
|
|
explicit_target.payload_min_nops
|
|
|
|
else
|
|
|
|
payload_info['MinNops'] || nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the maximum amount of room the exploit has for a payload.
|
|
|
|
#
|
|
|
|
def payload_space(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_space)
|
|
|
|
explicit_target.payload_space
|
|
|
|
elsif (payload_info['Space'])
|
|
|
|
payload_info['Space'].to_i
|
|
|
|
else
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the bad characters that cannot be in any payload used by this
|
|
|
|
# exploit.
|
|
|
|
#
|
|
|
|
def payload_badchars(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_badchars)
|
|
|
|
explicit_target.payload_badchars
|
|
|
|
else
|
|
|
|
payload_info['BadChars']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the payload encoder type that is associated with either the
|
|
|
|
# current target of the exploit in general.
|
|
|
|
#
|
|
|
|
def payload_encoder_type(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_encoder_type)
|
|
|
|
explicit_target.payload_encoder_type
|
|
|
|
else
|
|
|
|
payload_info['EncoderType']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the payload encoder option hash that is used to initialize the
|
|
|
|
# datastore of the encoder that is selected when generating an encoded
|
|
|
|
# payload.
|
|
|
|
#
|
|
|
|
def payload_encoder_options(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.payload_encoder_options)
|
|
|
|
explicit_target.payload_encoder_options
|
|
|
|
else
|
|
|
|
payload_info['EncoderOptions']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the payload extended options hash which is used to provide
|
|
|
|
# a location to store extended information that may be useful to
|
|
|
|
# a particular type of payload or mixin.
|
|
|
|
#
|
|
|
|
def payload_extended_options(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if explicit_target and explicit_target.payload_extended_options
|
|
|
|
explicit_target.payload_extended_options
|
|
|
|
else
|
|
|
|
payload_info['ExtendedOptions']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# NOP requirements
|
|
|
|
#
|
|
|
|
# Hints to the nop generator on how it should perform if it's used.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the list of registers that the NOP generator should save,
|
|
|
|
# if any. It will use the current target's save registers in precedence
|
|
|
|
# over those defined globally for the exploit module.
|
|
|
|
#
|
|
|
|
# If there are no save registers, nil is returned.
|
|
|
|
#
|
|
|
|
def nop_save_registers(explicit_target = nil)
|
|
|
|
explicit_target ||= target
|
|
|
|
|
|
|
|
if (explicit_target and explicit_target.save_registers)
|
|
|
|
return explicit_target.save_registers
|
|
|
|
else
|
|
|
|
return module_info['SaveRegisters']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Returns the first compatible NOP generator for this exploit's payload
|
|
|
|
# instance.
|
|
|
|
#
|
|
|
|
def nop_generator
|
|
|
|
return nil if (!payload_instance)
|
|
|
|
|
|
|
|
payload_instance.compatible_nops.each { |nopname, nopmod|
|
|
|
|
return nopmod.new
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2016-06-13 20:25:46 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Generates a NOP sled using the #make_nops method.
|
|
|
|
# The difference between this and #make_nops is this method is much faster, good for exploit
|
|
|
|
# developers that actually want huge chunks of NOPs. The downside of using this is the NOP sled
|
|
|
|
# is less randomized.
|
|
|
|
#
|
|
|
|
# @param count [String] Number of NOPs to return.
|
|
|
|
# @return [String] NOPs
|
|
|
|
#
|
|
|
|
def make_fast_nops(count)
|
|
|
|
max_nop_chunk_size = 100
|
|
|
|
|
|
|
|
if count < max_nop_chunk_size
|
|
|
|
return make_nops(count)
|
|
|
|
end
|
|
|
|
|
|
|
|
nops = make_nops(max_nop_chunk_size)
|
|
|
|
nops += nops while nops.length < count
|
|
|
|
|
|
|
|
nops[0, count]
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
# Generates a nop sled of a supplied length and returns it to the caller.
|
|
|
|
#
|
|
|
|
def make_nops(count)
|
|
|
|
# If we're debugging, then make_nops will return a safe sled. We
|
|
|
|
# currently assume x86.
|
|
|
|
if debugging?
|
|
|
|
return "\x90" * count
|
|
|
|
end
|
|
|
|
|
|
|
|
nop_sled = nil
|
|
|
|
|
|
|
|
# If there is no payload instance then we can't succeed.
|
|
|
|
return nil if (!payload_instance)
|
|
|
|
|
|
|
|
payload_instance.compatible_nops.each { |nopname, nopmod|
|
|
|
|
# Create an instance of the nop module
|
|
|
|
nop = nopmod.new
|
|
|
|
|
|
|
|
# The list of save registers
|
|
|
|
save_regs = nop_save_registers || []
|
|
|
|
|
|
|
|
if (save_regs.empty? == true)
|
|
|
|
save_regs = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
nop.copy_ui(self)
|
|
|
|
|
|
|
|
nop_sled = nop.generate_sled(count,
|
|
|
|
'BadChars' => payload_badchars || '',
|
|
|
|
'SaveRegisters' => save_regs)
|
2015-10-16 19:01:00 +00:00
|
|
|
|
|
|
|
if nop_sled && nop_sled.length == count
|
|
|
|
break
|
|
|
|
else
|
|
|
|
wlog("#{self.refname}: Nop generator #{nop.refname} failed to generate sled for exploit", 'core', LEV_0)
|
|
|
|
end
|
2013-08-30 21:28:33 +00:00
|
|
|
rescue
|
|
|
|
wlog("#{self.refname}: Nop generator #{nop.refname} failed to generate sled for exploit: #{$!}",
|
|
|
|
'core', LEV_0)
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
nop_sled
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Utility methods for generating random text that implicitly uses the
|
|
|
|
# exploit's bad character set.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random text characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random english-like avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_english(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_english(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random high ascii characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_highascii(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_highascii(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random alpha characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_alpha(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_alpha(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random alpha upper characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_alpha_upper(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_alpha_upper(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random alpha lower characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_alpha_lower(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"a" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_alpha_lower(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random alphanumeric characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_alphanumeric(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_alphanumeric(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate random numeric characters avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_text_numeric(length, bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"0" * length
|
|
|
|
else
|
|
|
|
Rex::Text.rand_text_numeric(length, bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate a random character avoiding the exploit's bad
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
def rand_char(bad=payload_badchars)
|
|
|
|
if debugging?
|
|
|
|
"A"
|
|
|
|
else
|
|
|
|
Rex::Text.rand_char(bad)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate a non-repeating static random string
|
|
|
|
#
|
|
|
|
def pattern_create(length, sets = nil)
|
|
|
|
Rex::Text.pattern_create(length, sets)
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# The default "wait for session" delay is zero for all exploits.
|
|
|
|
#
|
|
|
|
def wfs_delay
|
|
|
|
(datastore['WfsDelay'] || 0).to_i
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Allow the user to disable the payload handler
|
|
|
|
#
|
|
|
|
def handler_enabled?
|
|
|
|
not datastore['DisablePayloadHandler']
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Handler interaction
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Passes the connection to the associated payload handler to see if the
|
|
|
|
# exploit succeeded and a connection has been established. The return
|
|
|
|
# value can be one of the Handler::constants.
|
|
|
|
#
|
|
|
|
def handler(*args)
|
2016-04-07 03:03:31 +00:00
|
|
|
if payload_instance && handler_enabled?
|
2016-04-01 19:43:16 +00:00
|
|
|
payload_instance.handler(*args)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def interrupt_handler
|
|
|
|
if payload_instance && handler_enabled? && payload_instance.respond_to?(:interrupt_wait_for_session)
|
|
|
|
payload_instance.interrupt_wait_for_session()
|
|
|
|
end
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Session tracking
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# This is called by the payload when a new session is created
|
|
|
|
#
|
|
|
|
def on_new_session(session)
|
|
|
|
self.session_count += 1
|
|
|
|
self.successful = true
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# A boolean for whether a session has been created yet
|
|
|
|
#
|
|
|
|
def session_created?
|
|
|
|
(self.session_count > 0) ? true : false
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Reset the session counter to zero (which occurs during set up of the
|
|
|
|
# exploit prior to calling exploit).
|
|
|
|
#
|
|
|
|
def reset_session_counts
|
|
|
|
self.session_count = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
# Failure tracking
|
|
|
|
##
|
|
|
|
|
2015-04-17 20:55:22 +00:00
|
|
|
# Raises a Msf::Exploit::Failed exception. It overrides the fail_with method
|
|
|
|
# in lib/msf/core/module.rb
|
|
|
|
#
|
|
|
|
# @param reason [String] A constant from Msf::Module::Failure.
|
|
|
|
# If the reason does not come from there, then it will default to
|
|
|
|
# Msf::Module::Failure::Unknown.
|
2015-04-19 22:06:59 +00:00
|
|
|
# @param msg [String] (Optional) A message about the failure.
|
2015-04-17 20:55:22 +00:00
|
|
|
# @raise [Msf::Exploit::Failed] A custom Msf::Exploit::Failed exception.
|
|
|
|
# @return [void]
|
|
|
|
# @see Msf::Module::Failure
|
|
|
|
# @see Msf::Module#fail_with
|
|
|
|
# @example
|
|
|
|
# fail_with(Msf::Module::Failure::NoAccess, 'Unable to login to upload payload')
|
2013-08-30 21:28:33 +00:00
|
|
|
def fail_with(reason,msg=nil)
|
2015-04-17 20:55:22 +00:00
|
|
|
# The reason being registered here will be used later on, so it's important we don't actually
|
|
|
|
# provide a made-up one.
|
|
|
|
allowed_values = Msf::Module::Failure.constants.collect {|e| Msf::Module::Failure.const_get(e)}
|
|
|
|
if allowed_values.include?(reason)
|
|
|
|
self.fail_reason = reason
|
|
|
|
else
|
|
|
|
self.fail_reason = Msf::Module::Failure::Unknown
|
|
|
|
end
|
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
self.fail_detail = msg
|
2015-04-17 20:55:22 +00:00
|
|
|
raise Msf::Exploit::Failed, (msg || "No failure message given")
|
2013-08-30 21:28:33 +00:00
|
|
|
end
|
|
|
|
|
Fix #6371, being able to report an exception in #job_run_proc
Fix #6371
When a browser fails to bind (probably due to an invalid port or
server IP), the module actually fails to report this exception from
exception, the method calls exploit.handle_exception(e). But since
handle_exception is not a valid method for that object, it is unable
to do so, and as a result the module fails to properly terminate
the module, or show any error on the console. For the user, this will
make it look like the module has started, the payload listener is up,
but there is no exploit job.
Rex::BindFailed actually isn't the only error that could be raised
by #job_run_proc. As far as I can tell registering the same resource
again could, too. With this patch, the user should be able to see this
error too.
Since the exploit object does not have access to the methods in
Msf::Simple::Exploit, plus there is no other code using
handle_exception and setup_fail_detail_from_exception, I decided
to move these to lib/msf/core/exploit.rb so they are actually
callable.
2015-12-22 22:35:29 +00:00
|
|
|
def setup_fail_detail_from_exception e
|
|
|
|
# Build a user-friendly error message
|
|
|
|
msg = "#{e}"
|
|
|
|
unless e.class == Msf::Exploit::Failed
|
|
|
|
msg = "#{e.class} #{e}"
|
|
|
|
end
|
|
|
|
|
|
|
|
self.error = e
|
|
|
|
|
|
|
|
# Record the detailed reason
|
|
|
|
self.fail_detail ||= e.to_s
|
|
|
|
msg
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Handle the exception
|
|
|
|
#
|
|
|
|
def handle_exception e
|
|
|
|
msg = setup_fail_detail_from_exception e
|
|
|
|
|
|
|
|
case e
|
|
|
|
when Msf::Exploit::Complete
|
|
|
|
# Nothing to show in this case
|
|
|
|
return
|
|
|
|
|
|
|
|
when Msf::Exploit::Failed
|
|
|
|
self.print_error("Exploit aborted due to failure: #{self.fail_reason}: #{msg}")
|
|
|
|
|
|
|
|
# The caller should have already set self.fail_reason
|
|
|
|
if self.fail_reason == Msf::Exploit::Failure::None
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::Unknown
|
|
|
|
end
|
|
|
|
|
|
|
|
when Rex::ConnectionError
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::Unreachable
|
|
|
|
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
|
|
|
|
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
|
|
|
|
|
|
|
when Rex::BindFailed
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::BadConfig
|
|
|
|
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
|
|
|
|
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
|
|
|
|
|
|
|
when Timeout::Error
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::TimeoutExpired
|
|
|
|
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
|
|
|
|
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
|
|
|
else
|
|
|
|
|
|
|
|
# Compare as a string since not all error classes may be loaded
|
|
|
|
case msg
|
|
|
|
when /access.denied|Login Failed/i # Covers SMB as well as some generic errors
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::NoAccess
|
|
|
|
when /connection reset/i
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::Disconnected
|
|
|
|
when /connection timed out|SSL_connect|unreachable|connection was refused/i
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::Unreachable
|
|
|
|
when /unable.*target/i
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::NoTarget
|
|
|
|
when /execution expired/i
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::TimeoutExpired
|
|
|
|
when /(doesn.t|not).*vulnerable|may.*patched/i
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::NotVulnerable
|
|
|
|
end
|
|
|
|
|
|
|
|
# The caller should have already set self.fail_reason
|
|
|
|
if self.fail_reason == Msf::Exploit::Failure::None
|
|
|
|
self.fail_reason = Msf::Exploit::Failure::Unknown
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.fail_reason == Msf::Exploit::Failure::Unknown
|
|
|
|
self.print_error("Exploit failed: #{msg}")
|
|
|
|
else
|
|
|
|
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
|
|
|
|
end
|
|
|
|
|
|
|
|
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Record the error to various places
|
|
|
|
self.framework.events.on_module_error(self, msg)
|
|
|
|
|
|
|
|
# Report the failure (and attempt) in the database
|
|
|
|
self.report_failure
|
2016-04-01 19:43:16 +00:00
|
|
|
|
|
|
|
# Interrupt any session waiters in the handler
|
|
|
|
self.interrupt_handler
|
Fix #6371, being able to report an exception in #job_run_proc
Fix #6371
When a browser fails to bind (probably due to an invalid port or
server IP), the module actually fails to report this exception from
exception, the method calls exploit.handle_exception(e). But since
handle_exception is not a valid method for that object, it is unable
to do so, and as a result the module fails to properly terminate
the module, or show any error on the console. For the user, this will
make it look like the module has started, the payload listener is up,
but there is no exploit job.
Rex::BindFailed actually isn't the only error that could be raised
by #job_run_proc. As far as I can tell registering the same resource
again could, too. With this patch, the user should be able to see this
error too.
Since the exploit object does not have access to the methods in
Msf::Simple::Exploit, plus there is no other code using
handle_exception and setup_fail_detail_from_exception, I decided
to move these to lib/msf/core/exploit.rb so they are actually
callable.
2015-12-22 22:35:29 +00:00
|
|
|
end
|
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
def report_failure
|
|
|
|
return unless framework.db and framework.db.active
|
|
|
|
|
|
|
|
info = {
|
|
|
|
:timestamp => Time.now.utc,
|
|
|
|
:workspace => framework.db.find_workspace(self.workspace),
|
|
|
|
:module => self.fullname,
|
|
|
|
:fail_reason => self.fail_reason,
|
|
|
|
:fail_detail => self.fail_detail,
|
|
|
|
:target_name => self.target.name,
|
|
|
|
:username => self.owner,
|
2015-09-15 19:34:44 +00:00
|
|
|
:refs => self.references,
|
|
|
|
:run_id => self.datastore['RUN_ID']
|
2013-08-30 21:28:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.datastore['RHOST'] and self.options['RHOST']
|
|
|
|
info[:host] = self.datastore['RHOST']
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.datastore['RPORT'] and self.options['RPORT']
|
|
|
|
info[:port] = self.datastore['RPORT']
|
|
|
|
if self.class.ancestors.include?(Msf::Exploit::Remote::Tcp)
|
|
|
|
info[:proto] = 'tcp'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
framework.db.report_exploit_failure(info)
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Aliases
|
|
|
|
#
|
|
|
|
# These allow access to methods inside this class, even if exploits use mixins that
|
|
|
|
# override them.
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
# Give exploits the ability to use the original +regenerate_payload+ so
|
|
|
|
# they can avoid needing additional arguments added by overridden versions.
|
|
|
|
# Used specifically by things that include +TcpServer+ (or a descendant)
|
|
|
|
# but which are active exploits.
|
|
|
|
alias :exploit_regenerate_payload :regenerate_payload
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Attributes
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
2015-04-16 19:28:16 +00:00
|
|
|
# The reason why the exploit was not successful (one of Msf::Module::Failure)
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
attr_accessor :fail_reason
|
|
|
|
|
|
|
|
#
|
|
|
|
# Detailed exception string indicating why the exploit was not successful
|
|
|
|
#
|
|
|
|
attr_accessor :fail_detail
|
|
|
|
|
|
|
|
#
|
|
|
|
# The list of targets.
|
|
|
|
#
|
|
|
|
attr_reader :targets
|
|
|
|
#
|
|
|
|
# The default target.
|
|
|
|
#
|
|
|
|
attr_reader :default_target
|
|
|
|
#
|
|
|
|
# The payload requirement hash.
|
|
|
|
#
|
|
|
|
attr_reader :payload_info
|
|
|
|
#
|
|
|
|
# The active payload instance.
|
|
|
|
#
|
|
|
|
attr_accessor :payload_instance
|
|
|
|
#
|
|
|
|
# The encoded payload instance. An instance of an
|
|
|
|
# EncodedPayload object.
|
|
|
|
#
|
|
|
|
attr_accessor :payload
|
|
|
|
|
|
|
|
#
|
|
|
|
# The number of active sessions created by this instance
|
|
|
|
#
|
|
|
|
attr_reader :session_count
|
|
|
|
|
|
|
|
#
|
|
|
|
# The boolean indicating whether the exploit succeeded
|
|
|
|
#
|
|
|
|
attr_reader :successful
|
2012-06-10 08:15:48 +00:00
|
|
|
|
|
|
|
|
2005-07-11 15:34:31 +00:00
|
|
|
protected
|
2005-06-04 22:26:42 +00:00
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
|
|
|
# Writable copy of the list of targets.
|
|
|
|
#
|
|
|
|
attr_writer :targets
|
|
|
|
#
|
|
|
|
# Writable copy of the default target.
|
|
|
|
#
|
|
|
|
attr_writer :default_target
|
|
|
|
#
|
|
|
|
# Writable copy of the payload requirement hash.
|
|
|
|
#
|
|
|
|
attr_writer :payload_info
|
|
|
|
#
|
|
|
|
# Number of sessions created by this exploit instance.
|
|
|
|
#
|
|
|
|
attr_writer :session_count
|
|
|
|
#
|
|
|
|
# Maximum number of seconds for active handlers
|
|
|
|
#
|
|
|
|
attr_accessor :active_timeout
|
|
|
|
|
|
|
|
#
|
|
|
|
# Boolean indicating whether the exploit succeeded
|
|
|
|
#
|
|
|
|
attr_writer :successful
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Overrides the base class method and serves to initialize default
|
|
|
|
# compatibilities for exploits
|
|
|
|
#
|
|
|
|
def init_compat
|
|
|
|
super
|
|
|
|
|
|
|
|
#
|
|
|
|
# Merge in payload compatible defaults
|
|
|
|
#
|
|
|
|
p = module_info['Compat']['Payload']
|
|
|
|
|
|
|
|
CompatDefaults::Payload.each_pair { |k,v|
|
|
|
|
(p[k]) ? p[k] << " #{v}" : p[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# Set the default save registers if none have been explicitly
|
|
|
|
# specified.
|
|
|
|
#
|
|
|
|
if (module_info['SaveRegisters'] == nil)
|
|
|
|
module_info['SaveRegisters'] = [ 'esp', 'ebp' ]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Gets the memory map file and other context information that is
|
|
|
|
# required when wanting to support context keyed encoding
|
|
|
|
#
|
|
|
|
def define_context_encoding_reqs(reqs)
|
2016-03-06 05:10:57 +00:00
|
|
|
return unless datastore['EnableContextEncoding']
|
2013-08-30 21:28:33 +00:00
|
|
|
|
|
|
|
# At present, we don't support any automatic methods of obtaining
|
|
|
|
# context information. In the future, we might support obtaining
|
|
|
|
# temporal information remotely.
|
|
|
|
|
|
|
|
# Pass along the information specified in our exploit datastore as
|
|
|
|
# encoder options
|
|
|
|
reqs['EncoderOptions'] = {} if reqs['EncoderOptions'].nil?
|
|
|
|
reqs['EncoderOptions']['EnableContextEncoding'] = datastore['EnableContextEncoding']
|
|
|
|
reqs['EncoderOptions']['ContextInformationFile'] = datastore['ContextInformationFile']
|
|
|
|
end
|
2007-08-31 04:01:30 +00:00
|
|
|
|
2005-06-04 22:26:42 +00:00
|
|
|
end
|
|
|
|
|
2008-11-09 22:23:29 +00:00
|
|
|
end
|