Files
metasploit-gs/lib/msf/base/simple/exploit.rb
T
dwelch-r7 5c94910998 Add a cache to handle the ttl of job results
Remove accidental addition of gem

Remove commented out code

Remove commented out code

Remove commented out code

Refactor job tracking code, remove simple framework tests

finish renaming service to job_state_tracker

add missing require and move alias definition

fix private attr declaration

Add rspec tests

Address PR comments

Use let syntax in tests

Finish refactor moving job state tracker
2020-02-25 13:31:28 +00:00

238 lines
6.2 KiB
Ruby

# -*- coding: binary -*-
require 'msf/base'
module Msf
module Simple
###
#
# A simplified exploit wrapper.
#
###
module Exploit
include Module
#
# Wraps the exploitation process in a simple single method. The options
# hash can have the following values passed in it:
#
# Encoder
#
# The encoder module that should be used.
#
# Payload
#
# The payload module name that should be used.
#
# Target
#
# The selected target index.
#
# Nop
#
# The NOP generator that should be used in preference.
#
# OptionStr
#
# A string of comma separated option values that should be imported into
# the datastore.
#
# Options
#
# A hash of values to be imported directly into the datastore.
#
# LocalInput
#
# The local input handle that data can be read in from.
#
# LocalOutput
#
# The local output through which data can be displayed.
#
# RunAsJob
#
# Whether or not the exploit should be run in the context of a background
# job.
#
def self.exploit_simple(oexploit, opts, &block)
exploit = oexploit.replicant
# Trap and print errors here (makes them UI-independent)
begin
# Clone the module to prevent changes to the original instance
Msf::Simple::Framework.simplify_module( exploit, false )
yield(exploit) if block_given?
# Import options from the OptionStr or Option hash.
exploit._import_extra_options(opts)
# Make sure parameters are valid.
if (opts['Payload'] == nil)
raise MissingPayloadError.new, caller
end
# Verify the options
exploit.options.validate(exploit.datastore)
# Start it up
driver = ExploitDriver.new(exploit.framework)
# Keep the handler of driver running if exploit multi targets.
driver.keep_handler = true if opts["multi"]
# Initialize the driver instance
driver.exploit = exploit
driver.payload = exploit.framework.payloads.create(opts['Payload'])
# Set the force wait for session flag if the caller requested force
# blocking. This is so that passive exploits can be blocked on from
# things like the cli.
driver.force_wait_for_session = true if (opts['ForceBlocking'] == true)
# Was the payload valid?
if (driver.payload == nil)
raise MissingPayloadError,
"You specified an invalid payload: #{opts['Payload']}", caller
end
# Use the supplied encoder, if any. If one was not specified, then
# nil will be assigned causing the exploit to default to picking the
# best encoder.
exploit.datastore['ENCODER'] = opts['Encoder'] if opts['Encoder']
# Use the supplied NOP generator, if any. If one was not specified, then
# nil will be assigned causing the exploit to default to picking a
# compatible NOP generator.
exploit.datastore['NOP'] = opts['Nop'] if opts['Nop']
# Force the payload to share the exploit's datastore
driver.payload.share_datastore(driver.exploit.datastore)
# Verify the payload options
driver.payload.options.validate(driver.payload.datastore)
# Set the target and then work some magic to derive index
exploit.datastore['TARGET'] = opts['Target'] if opts['Target']
target_idx = exploit.target_index
if (target_idx == nil or target_idx < 0)
raise MissingTargetError,
"You must select a target.", caller
end
driver.target_idx = target_idx
# Set the payload and exploit's subscriber values
if ! opts['Quiet']
driver.exploit.init_ui(opts['LocalInput'] || exploit.user_input, opts['LocalOutput'] || exploit.user_output)
driver.payload.init_ui(opts['LocalInput'] || exploit.user_input, opts['LocalOutput'] || exploit.user_output)
else
driver.exploit.init_ui(nil, nil)
driver.payload.init_ui(nil, nil)
end
if (opts['RunAsJob'])
driver.use_job = true
end
# Let's rock this party
driver.run
# Save the job identifier this exploit is running as
exploit.job_id = driver.job_id
# Propagate this back to the caller for console mgmt
oexploit.job_id = exploit.job_id
rescue ::Interrupt
exploit.error = $!
raise $!
rescue ::Exception => e
exploit.error = e
exploit.print_error("Exploit failed: #{e}")
elog("Exploit failed (#{exploit.refname}): #{e}", 'core', LEV_0)
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
end
return driver.session if driver
nil
end
#
# Calls the class method.
#
def exploit_simple(opts, &block)
Msf::Simple::Exploit.exploit_simple(self, opts, &block)
end
#
# Initiates a check, setting up the exploit to be used. The following
# options can be specified:
#
# LocalInput
#
# The local input handle that data can be read in from.
#
# LocalOutput
#
# The local output through which data can be displayed.
#
def self.check_simple(mod, opts)
Msf::Simple::Framework.simplify_module(mod, false)
mod._import_extra_options(opts)
if opts['LocalInput']
mod.init_ui(opts['LocalInput'], opts['LocalOutput'])
end
# Validate the option container state so that options will
# be normalized
mod.validate
run_uuid = Rex::Text.rand_text_alphanumeric(24)
mod.framework.job_state_tracker.waiting run_uuid
ctx = [mod, run_uuid]
if opts['RunAsJob']
mod.job_id = mod.framework.jobs.start_bg_job(
"Auxiliary: #{mod.refname} check",
ctx,
Proc.new { |ctx_| self.job_check_proc(ctx_) },
Proc.new { |ctx_| nil }
)
[run_uuid, mod.job_id]
else
self.job_check_proc(ctx)
end
end
#
# Calls the class method.
#
def check_simple(opts)
Msf::Simple::Exploit.check_simple(self, opts)
end
protected
def self.job_check_proc(ctx)
mod = ctx[0]
run_uuid = ctx[1]
begin
mod.setup
mod.framework.job_state_tracker.start run_uuid
result = mod.has_check? ? mod.check : Msf::Exploit::CheckCode::Unsupported
mod.framework.job_state_tracker.completed(run_uuid, result)
rescue => e
mod.framework.job_state_tracker.failed(run_uuid, e)
mod.handle_exception e
end
return result
end
end
end
end