5c94910998
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
238 lines
6.2 KiB
Ruby
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
|
|
|