2011-05-12 20:03:55 +00:00
|
|
|
require 'msf/core'
|
2005-07-13 18:06:12 +00:00
|
|
|
|
|
|
|
module Msf
|
|
|
|
|
|
|
|
###
|
|
|
|
#
|
|
|
|
# This class drives the exploitation process from start to finish for a given
|
|
|
|
# exploit module instance. It's responsible for payload generation, encoding,
|
|
|
|
# and padding as well as initialization handlers and finally launching the
|
|
|
|
# exploit.
|
|
|
|
#
|
|
|
|
###
|
|
|
|
class ExploitDriver
|
|
|
|
|
2005-11-15 15:11:43 +00:00
|
|
|
#
|
|
|
|
# Initializes the exploit driver using the supplied framework instance.
|
|
|
|
#
|
2005-07-13 18:06:12 +00:00
|
|
|
def initialize(framework)
|
2005-10-02 05:48:05 +00:00
|
|
|
self.payload = nil
|
|
|
|
self.exploit = nil
|
|
|
|
self.use_job = false
|
2007-04-04 02:49:08 +00:00
|
|
|
self.job_id = nil
|
2005-10-02 05:48:05 +00:00
|
|
|
self.force_wait_for_session = false
|
2005-07-13 18:06:12 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
2005-11-15 15:11:43 +00:00
|
|
|
# Specification of the exploit target index.
|
2005-07-13 18:06:12 +00:00
|
|
|
#
|
|
|
|
def target_idx=(target_idx)
|
2005-07-15 22:30:04 +00:00
|
|
|
if (target_idx)
|
|
|
|
# Make sure the target index is valid
|
|
|
|
if (target_idx >= exploit.targets.length)
|
|
|
|
raise Rex::ArgumentError, "Invalid target index.", caller
|
|
|
|
end
|
2005-07-13 18:06:12 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Set the active target
|
2005-07-15 22:30:04 +00:00
|
|
|
@target_idx = target_idx
|
2005-07-13 18:06:12 +00:00
|
|
|
end
|
|
|
|
|
2005-11-11 01:49:02 +00:00
|
|
|
#
|
2005-11-15 15:11:43 +00:00
|
|
|
# This method returns the currently selected target index.
|
2005-11-11 01:49:02 +00:00
|
|
|
#
|
|
|
|
def target_idx
|
|
|
|
@target_idx
|
|
|
|
end
|
|
|
|
|
2005-07-13 18:06:12 +00:00
|
|
|
#
|
|
|
|
# Checks to see if the supplied payload is compatible with the
|
2005-07-15 22:30:04 +00:00
|
|
|
# current exploit. Assumes that target_idx is valid.
|
2005-07-13 18:06:12 +00:00
|
|
|
#
|
|
|
|
def compatible_payload?(payload)
|
2005-12-14 00:43:18 +00:00
|
|
|
# Try to use the target's platform in preference of the exploit's
|
|
|
|
exp_platform = exploit.targets[target_idx].platform || exploit.platform
|
|
|
|
|
|
|
|
return ((payload.platform & exp_platform).empty? == false)
|
2005-07-13 18:06:12 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
#
|
|
|
|
# Exploit execution
|
|
|
|
#
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Makes sure everything's in tip-top condition prior to launching the
|
|
|
|
# exploit. For things that aren't good to go, an exception is thrown.
|
|
|
|
#
|
|
|
|
def validate
|
|
|
|
# First, validate that a target has been selected
|
2005-07-15 22:30:04 +00:00
|
|
|
if (target_idx == nil)
|
2009-11-16 15:08:58 +00:00
|
|
|
raise MissingTargetError,
|
2005-07-13 18:06:12 +00:00
|
|
|
"A payload cannot be selected until a target is specified.",
|
|
|
|
caller
|
|
|
|
end
|
|
|
|
|
|
|
|
# Next, validate that a payload has been selected
|
|
|
|
if (payload == nil)
|
2009-11-16 15:08:58 +00:00
|
|
|
raise MissingPayloadError,
|
2005-07-13 18:06:12 +00:00
|
|
|
"A payload has not been selected.", caller
|
|
|
|
end
|
|
|
|
|
2005-07-15 22:30:04 +00:00
|
|
|
# Make sure the payload is compatible after all
|
|
|
|
if (compatible_payload?(payload) == false)
|
2009-11-16 15:08:58 +00:00
|
|
|
raise IncompatiblePayloadError.new(payload.refname),
|
2005-07-15 22:30:04 +00:00
|
|
|
"Incompatible payload", caller
|
|
|
|
end
|
|
|
|
|
2005-11-15 21:25:23 +00:00
|
|
|
# Associate the payload instance with the exploit
|
|
|
|
payload.assoc_exploit = exploit
|
|
|
|
|
2005-07-13 18:06:12 +00:00
|
|
|
# Finally, validate options on the exploit module to ensure that things
|
|
|
|
# are ready to operate as they should.
|
2005-07-15 22:30:04 +00:00
|
|
|
exploit.options.validate(exploit.datastore)
|
2005-07-13 18:06:12 +00:00
|
|
|
|
2005-07-18 02:01:36 +00:00
|
|
|
# Validate the payload's options. The payload's datastore is
|
|
|
|
# most likely shared against the exploit's datastore, but in case it
|
|
|
|
# isn't.
|
|
|
|
payload.options.validate(payload.datastore)
|
|
|
|
|
2005-07-13 18:06:12 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Kicks off an exploitation attempt and performs the following four major
|
|
|
|
# operations:
|
|
|
|
#
|
|
|
|
# - Generates the payload
|
|
|
|
# - Initializes & monitors the handler
|
|
|
|
# - Launches the exploit
|
|
|
|
# - Cleans up the handler
|
|
|
|
#
|
|
|
|
def run
|
2009-11-16 15:08:58 +00:00
|
|
|
|
2005-07-13 18:06:12 +00:00
|
|
|
# First thing's first -- validate the state. Make sure all requirement
|
|
|
|
# parameters are set, including those that are derived from the
|
|
|
|
# datastore.
|
|
|
|
validate()
|
2005-11-11 01:49:02 +00:00
|
|
|
|
2005-07-13 18:06:12 +00:00
|
|
|
# After validation has occurred, it's time to set some values on the
|
|
|
|
# exploit instance and begin preparing the payload
|
2005-11-11 01:49:02 +00:00
|
|
|
exploit.datastore['TARGET'] = target_idx
|
Merged revisions 5366-5377 via svnmerge from
svn+ssh://metasploit.com/home/svn/framework3/branches/framework-3.1
........
r5366 | hdm | 2008-01-26 20:30:53 -0600 (Sat, 26 Jan 2008) | 2 lines
Update version information
........
r5367 | hdm | 2008-01-26 21:10:57 -0600 (Sat, 26 Jan 2008) | 3 lines
Updated for version 3.1
........
r5369 | hdm | 2008-01-26 21:13:31 -0600 (Sat, 26 Jan 2008) | 3 lines
Wipe the private directories from the branch.
........
r5371 | hdm | 2008-01-27 17:24:24 -0600 (Sun, 27 Jan 2008) | 5 lines
Timeout options added for dcerpc connect and read times. Addition of novell netware as a supported target platform. Inclusion of the serverprotect exploit (still works on the latest version). Addition of the first remote netware kernel exploit that leads to a shell, addition of netware stager and shell, and first draft of the release notes for 3.1
........
r5372 | hdm | 2008-01-27 17:30:08 -0600 (Sun, 27 Jan 2008) | 3 lines
Formatting, indentation, fixed the static IP embedded in the request
........
r5373 | hdm | 2008-01-27 20:02:48 -0600 (Sun, 27 Jan 2008) | 3 lines
Correctly trap exploit errors in a way that works with all of the UIs
........
r5374 | hdm | 2008-01-27 20:23:25 -0600 (Sun, 27 Jan 2008) | 3 lines
More last-minute bug fixes
........
r5375 | hdm | 2008-01-27 20:37:43 -0600 (Sun, 27 Jan 2008) | 3 lines
Force multi-bind off in netware, correct label display in gtk gui labels
........
r5376 | hdm | 2008-01-27 20:50:03 -0600 (Sun, 27 Jan 2008) | 3 lines
More exception handling fun
........
git-svn-id: file:///home/svn/framework3/trunk@5378 4d416f70-5f16-0410-b530-b9f4589650da
2008-01-28 03:06:31 +00:00
|
|
|
|
2005-07-16 07:32:11 +00:00
|
|
|
# Default the session to nil
|
2005-09-22 04:53:46 +00:00
|
|
|
self.session = nil
|
|
|
|
|
2010-07-16 21:47:00 +00:00
|
|
|
# Explicitly clear the module's job_id in case it was set in a previous
|
|
|
|
# run
|
|
|
|
exploit.job_id = nil
|
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
# If we are being instructed to run as a job then let's create that job
|
|
|
|
# like a good person.
|
2008-11-17 19:51:09 +00:00
|
|
|
if (use_job or exploit.stance == Msf::Exploit::Stance::Passive)
|
2010-07-01 22:02:46 +00:00
|
|
|
# Since references to the exploit and payload will hang around for
|
|
|
|
# awhile in the job, make sure we copy them so further changes to
|
2010-07-07 16:37:23 +00:00
|
|
|
# the datastore don't alter settings in existing jobs
|
2010-07-06 21:09:53 +00:00
|
|
|
e = exploit.replicant
|
|
|
|
p = payload.replicant
|
2010-07-07 16:37:23 +00:00
|
|
|
|
2011-03-22 03:19:56 +00:00
|
|
|
# Assign the correct exploit instance to the payload
|
|
|
|
p.assoc_exploit = e
|
|
|
|
|
2010-07-07 16:37:23 +00:00
|
|
|
# Generate the encoded version of the supplied payload for the
|
|
|
|
# newly copied exploit module instance
|
|
|
|
e.generate_payload(p)
|
2010-07-06 21:09:53 +00:00
|
|
|
ctx = [ e, p ]
|
2010-07-01 22:02:46 +00:00
|
|
|
|
2010-07-07 16:37:23 +00:00
|
|
|
e.job_id = e.framework.jobs.start_bg_job(
|
|
|
|
"Exploit: #{e.refname}",
|
2008-11-17 19:51:09 +00:00
|
|
|
ctx,
|
2009-10-25 17:18:23 +00:00
|
|
|
Proc.new { |ctx_| job_run_proc(ctx_) },
|
|
|
|
Proc.new { |ctx_| job_cleanup_proc(ctx_) }
|
2009-11-16 15:08:58 +00:00
|
|
|
)
|
2010-07-07 16:37:23 +00:00
|
|
|
self.job_id = e.job_id
|
2005-09-22 04:53:46 +00:00
|
|
|
else
|
2010-07-07 16:37:23 +00:00
|
|
|
# Generate the encoded version of the supplied payload on the
|
|
|
|
# exploit module instance
|
|
|
|
exploit.generate_payload(payload)
|
|
|
|
|
2010-07-01 22:02:46 +00:00
|
|
|
# No need to copy since we aren't creating a job. We wait until
|
|
|
|
# they're finished running to do anything else with them, so
|
|
|
|
# nothing should be able to modify their datastore or other
|
|
|
|
# settings until after they're done.
|
|
|
|
ctx = [ exploit, payload ]
|
2005-09-27 00:35:51 +00:00
|
|
|
job_run_proc(ctx)
|
|
|
|
job_cleanup_proc(ctx)
|
2005-07-15 23:46:05 +00:00
|
|
|
end
|
2005-07-13 18:06:12 +00:00
|
|
|
|
2005-07-16 07:32:11 +00:00
|
|
|
return session
|
2005-07-13 18:06:12 +00:00
|
|
|
end
|
|
|
|
|
2005-10-19 03:20:20 +00:00
|
|
|
attr_accessor :exploit # :nodoc:
|
|
|
|
attr_accessor :payload # :nodoc:
|
|
|
|
attr_accessor :use_job # :nodoc:
|
2007-04-04 02:49:08 +00:00
|
|
|
#
|
|
|
|
# The identifier of the job this exploit is launched as, if it's run as a
|
|
|
|
# job.
|
|
|
|
#
|
2009-11-16 15:08:58 +00:00
|
|
|
attr_accessor :job_id
|
2005-10-19 03:20:20 +00:00
|
|
|
attr_accessor :force_wait_for_session # :nodoc:
|
2010-07-15 21:28:21 +00:00
|
|
|
attr_accessor :session # :nodoc:
|
2005-09-22 04:53:46 +00:00
|
|
|
|
|
|
|
protected
|
|
|
|
|
2010-07-15 21:28:21 +00:00
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Job run proc, sets up the exploit and kicks it off.
|
|
|
|
#
|
|
|
|
def job_run_proc(ctx)
|
2010-07-21 23:25:20 +00:00
|
|
|
# Default session wait time..
|
|
|
|
delay = payload.wfs_delay + exploit.wfs_delay
|
|
|
|
delay = nil if exploit.passive?
|
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
begin
|
|
|
|
exploit, payload = ctx
|
2009-11-16 15:08:58 +00:00
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
# Set the exploit up the bomb
|
|
|
|
exploit.setup
|
2005-11-18 00:26:19 +00:00
|
|
|
|
2010-01-15 00:32:48 +00:00
|
|
|
exploit.framework.events.on_module_run(exploit)
|
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
# Launch the exploit
|
|
|
|
exploit.exploit
|
2005-10-02 05:48:05 +00:00
|
|
|
|
2010-07-16 19:58:41 +00:00
|
|
|
rescue ::Exception => e
|
2012-06-10 08:15:48 +00:00
|
|
|
|
2010-07-21 23:25:20 +00:00
|
|
|
if [::RuntimeError, ::Interrupt].include?(e.class)
|
|
|
|
# Wait for session, but don't wait long.
|
|
|
|
delay = 0.01
|
2010-07-15 21:28:21 +00:00
|
|
|
end
|
2010-07-21 06:03:42 +00:00
|
|
|
|
2010-07-16 19:58:41 +00:00
|
|
|
# Build a user-friendly error message
|
2012-06-20 18:34:31 +00:00
|
|
|
msg = "#{e}"
|
|
|
|
unless e.class == Msf::Exploit::Failed
|
|
|
|
msg = "#{e.class} #{e}"
|
|
|
|
end
|
2012-06-10 08:15:48 +00:00
|
|
|
|
|
|
|
exploit.error = e
|
|
|
|
|
2012-06-19 05:48:39 +00:00
|
|
|
# Record the detailed reason
|
|
|
|
exploit.fail_detail ||= e.to_s
|
|
|
|
|
2012-06-14 15:43:09 +00:00
|
|
|
case e.class
|
|
|
|
when Msf::Exploit::Complete
|
2012-06-10 08:15:48 +00:00
|
|
|
# Nothing to show in this case
|
|
|
|
return
|
|
|
|
|
2012-06-14 15:43:09 +00:00
|
|
|
when Msf::Exploit::Failed
|
2012-06-19 05:48:39 +00:00
|
|
|
exploit.print_error("Exploit aborted due to failure: #{exploit.fail_reason}: #{msg}")
|
2012-06-10 08:15:48 +00:00
|
|
|
|
|
|
|
# The caller should have already set exploit.fail_reason
|
|
|
|
if exploit.fail_reason == Msf::Exploit::Failure::None
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::Unknown
|
|
|
|
end
|
|
|
|
|
2012-06-14 15:43:09 +00:00
|
|
|
when Rex::ConnectionError
|
2012-06-10 08:15:48 +00:00
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::Unreachable
|
2012-06-20 18:34:31 +00:00
|
|
|
exploit.print_error("Exploit failed [#{exploit.fail_reason}]: #{msg}")
|
2012-06-10 08:15:48 +00:00
|
|
|
elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
2012-06-19 05:48:39 +00:00
|
|
|
|
|
|
|
when Timeout::Error
|
2012-06-19 18:31:39 +00:00
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::TimeoutExpired
|
2012-06-20 18:34:31 +00:00
|
|
|
exploit.print_error("Exploit failed [#{exploit.fail_reason}]: #{msg}")
|
2012-06-19 05:48:39 +00:00
|
|
|
elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
2012-06-10 08:15:48 +00:00
|
|
|
else
|
2012-06-19 05:48:39 +00:00
|
|
|
|
|
|
|
# Compare as a string since not all error classes may be loaded
|
|
|
|
case msg
|
2012-06-19 18:31:39 +00:00
|
|
|
when /access.denied|Login Failed/i # Covers SMB as well as some generic errors
|
2012-06-19 05:48:39 +00:00
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::NoAccess
|
2012-06-19 18:31:39 +00:00
|
|
|
when /connection reset/i
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::Disconnected
|
2012-06-25 08:29:30 +00:00
|
|
|
when /connection timed out|SSL_connect|unreachable/i
|
2012-06-19 18:31:39 +00:00
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::Unreachable
|
|
|
|
when /unable.*target/i
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::NoTarget
|
|
|
|
when /execution expired/i
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::TimeoutExpired
|
|
|
|
when /(doesn.t|not).*vulnerable|may.*patched/i
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::NotVulnerable
|
2012-06-19 05:48:39 +00:00
|
|
|
end
|
2012-06-10 08:15:48 +00:00
|
|
|
|
|
|
|
# The caller should have already set exploit.fail_reason
|
|
|
|
if exploit.fail_reason == Msf::Exploit::Failure::None
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::Unknown
|
|
|
|
end
|
|
|
|
|
2012-06-19 05:48:39 +00:00
|
|
|
if exploit.fail_reason == Msf::Exploit::Failure::Unknown
|
2012-06-10 08:15:48 +00:00
|
|
|
exploit.print_error("Exploit failed: #{msg}")
|
|
|
|
else
|
2012-06-20 18:34:31 +00:00
|
|
|
exploit.print_error("Exploit failed [#{exploit.fail_reason}]: #{msg}")
|
2012-06-10 08:15:48 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0)
|
|
|
|
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
|
|
|
|
end
|
2010-07-16 19:58:41 +00:00
|
|
|
|
|
|
|
# Record the error to various places
|
|
|
|
exploit.framework.events.on_module_error(exploit, msg)
|
|
|
|
|
2012-06-10 08:15:48 +00:00
|
|
|
# Report the failure (and attempt) in the database
|
|
|
|
exploit.report_failure
|
2010-07-21 23:25:20 +00:00
|
|
|
end
|
2006-01-07 10:04:30 +00:00
|
|
|
|
2010-07-21 23:25:20 +00:00
|
|
|
# Wait the payload to acquire a session if this isn't a passive-style
|
|
|
|
# exploit.
|
2011-05-17 17:16:47 +00:00
|
|
|
return if not delay
|
2010-12-13 23:34:43 +00:00
|
|
|
|
|
|
|
if (force_wait_for_session == true) or
|
|
|
|
(exploit.passive? == false and exploit.handler_enabled?)
|
2010-07-21 23:25:20 +00:00
|
|
|
begin
|
|
|
|
self.session = payload.wait_for_session(delay)
|
|
|
|
rescue ::Interrupt
|
|
|
|
# Don't let interrupt pass upward
|
|
|
|
end
|
2005-09-22 04:53:46 +00:00
|
|
|
end
|
2012-06-19 05:48:39 +00:00
|
|
|
|
|
|
|
return self.session if self.session
|
|
|
|
|
|
|
|
unless exploit.fail_reason
|
|
|
|
exploit.fail_reason = Msf::Exploit::Failure::PayloadFailed
|
|
|
|
exploit.fail_detail = "No session created"
|
|
|
|
exploit.report_failure
|
|
|
|
end
|
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Clean up the exploit and the handler after the job completes.
|
|
|
|
#
|
|
|
|
def job_cleanup_proc(ctx)
|
|
|
|
exploit, payload = ctx
|
2009-11-16 15:08:58 +00:00
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
# Ensure that, no matter what, clean up of the handler occurs
|
|
|
|
payload.stop_handler
|
2009-11-16 15:08:58 +00:00
|
|
|
|
2010-03-16 19:32:54 +00:00
|
|
|
exploit.framework.events.on_module_complete(exploit)
|
|
|
|
|
2005-09-22 04:53:46 +00:00
|
|
|
# Allow the exploit to cleanup after itself, that messy bugger.
|
|
|
|
exploit.cleanup
|
|
|
|
end
|
2005-07-13 18:06:12 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
|
2008-11-17 19:51:09 +00:00
|
|
|
end
|
2009-11-16 15:08:58 +00:00
|
|
|
|