Path: blob/master/lib/msf/base/simple/exploit.rb
19778 views
# -*- coding: binary -*-12module Msf3module Simple45###6#7# A simplified exploit wrapper.8#9###10module Exploit1112include Module1314#15# Wraps the exploitation process in a simple single method. The options16# hash can have the following values passed in it:17#18# Encoder19#20# The encoder module that should be used.21#22# Payload23#24# The payload module name that should be used.25#26# Target27#28# The selected target index.29#30# Nop31#32# The NOP generator that should be used in preference.33#34# OptionStr35#36# A string of comma separated option values that should be imported into37# the datastore.38#39# Options40#41# A hash of values to be imported directly into the datastore.42#43# LocalInput44#45# The local input handle that data can be read in from.46#47# LocalOutput48#49# The local output through which data can be displayed.50#51# RunAsJob52#53# Whether or not the exploit should be run in the context of a background54# job.55#56def self.exploit_simple(oexploit, opts, &block)57exploit = oexploit.replicant58# Trap and print errors here (makes them UI-independent)59begin60# Clone the module to prevent changes to the original instance6162Msf::Simple::Framework.simplify_module(exploit)63yield(exploit) if block_given?6465# Import options from the OptionStr or Option hash.66exploit._import_extra_options(opts)67exploit.datastore['ACTION'] = opts['Action'] if opts['Action']68opts['Payload'] ||= exploit.datastore['Payload']6970unless opts['Quiet']71exploit.init_ui(opts['LocalInput'] || exploit.user_input, opts['LocalOutput'] || exploit.user_output)72else73exploit.init_ui(nil, nil)74end7576# Make sure parameters are valid.77if (opts['Payload'] == nil)78raise MissingPayloadError, 'A payload has not been selected.', caller79end8081# Verify the options82exploit.validate8384# Start it up85driver = Msf::ExploitDriver.new(exploit.framework)8687# Keep the handler of driver running if exploiting multiple targets.88driver.keep_handler = true if opts['multi']8990# Initialize the driver instance91driver.exploit = exploit92driver.payload = exploit.framework.payloads.create(opts['Payload'])9394# Set the force wait for session flag if the caller requested force95# blocking. This is so that passive exploits can be blocked on from96# things like the cli.97driver.force_wait_for_session = true if (opts['ForceBlocking'] == true)9899# Was the payload valid?100if (driver.payload == nil)101raise MissingPayloadError,102"You specified an invalid payload: #{opts['Payload']}", caller103end104105# Use the supplied encoder, if any. If one was not specified, then106# nil will be assigned causing the exploit to default to picking the107# best encoder.108exploit.datastore['ENCODER'] = opts['Encoder'] if opts['Encoder']109110# Use the supplied NOP generator, if any. If one was not specified, then111# nil will be assigned causing the exploit to default to picking a112# compatible NOP generator.113exploit.datastore['NOP'] = opts['Nop'] if opts['Nop']114115# Force the payload to share the exploit's datastore116driver.payload.share_datastore(driver.exploit.datastore)117118# Verify the payload options119driver.payload.options.validate(driver.payload.datastore)120121# Set the target and then work some magic to derive index122exploit.datastore['TARGET'] = opts['Target'] if opts['Target']123target_idx = exploit.target_index124125if (target_idx == nil or target_idx < 0)126raise MissingTargetError,127"You must select a target.", caller128end129130driver.target_idx = target_idx131132# Set the payload and exploit's subscriber values133unless opts['Quiet']134driver.payload.init_ui(opts['LocalInput'] || exploit.user_input, opts['LocalOutput'] || exploit.user_output)135else136driver.payload.init_ui(nil, nil)137end138139if (opts['RunAsJob'])140driver.use_job = true141end142143# Let's rock this party144driver.run145146# Save the job identifier this exploit is running as147exploit.job_id = driver.job_id148149# Propagate this back to the caller for console mgmt150oexploit.job_id = exploit.job_id151rescue ::Interrupt152exploit.error = $!153raise $!154rescue ::Msf::OptionValidateError => e155exploit.error = e156::Msf::Ui::Formatter::OptionValidateError.print_error(exploit, e)157return false158rescue ::Exception => e159exploit.error = e160exploit.print_error("Exploit failed: #{e}")161elog("Exploit failed (#{exploit.refname})", error: e)162end163164return driver.session if driver165nil166end167168#169# Calls the class method.170#171def exploit_simple(opts, &block)172Msf::Simple::Exploit.exploit_simple(self, opts, &block)173end174175alias run_simple exploit_simple176#177# Initiates a check, setting up the exploit to be used. The following178# options can be specified:179#180# LocalInput181#182# The local input handle that data can be read in from.183#184# LocalOutput185#186# The local output through which data can be displayed.187#188def self.check_simple(mod, opts, job_listener: Msf::Simple::NoopJobListener.instance)189Msf::Simple::Framework.simplify_module(mod)190mod._import_extra_options(opts)191192if opts['LocalInput']193mod.init_ui(opts['LocalInput'], opts['LocalOutput'])194end195196unless mod.has_check?197# Bail out early if the module doesn't have check198raise ::NotImplementedError.new(Msf::Exploit::CheckCode::Unsupported.message)199end200201# Validate the option container state so that options will202# be normalized203mod.validate204205run_uuid = Rex::Text.rand_text_alphanumeric(24)206job_listener.waiting run_uuid207ctx = [mod, run_uuid, job_listener]208209if opts['RunAsJob']210mod.job_id = mod.framework.jobs.start_bg_job(211"Exploit: #{mod.refname} check",212ctx,213Proc.new { |ctx_| self.job_check_proc(ctx_) },214Proc.new { |ctx_| nil }215)216[run_uuid, mod.job_id]217else218self.job_check_proc(ctx)219end220end221222#223# Calls the class method.224#225def check_simple(opts = {})226Msf::Simple::Exploit.check_simple(self, opts)227end228229protected230231def self.job_check_proc(ctx)232mod = ctx[0]233run_uuid = ctx[1]234job_listener = ctx[2]235begin236job_listener.start run_uuid237mod.setup238result = mod.check239job_listener.completed(run_uuid, result, mod)240rescue => e241job_listener.failed(run_uuid, e, mod)242mod.handle_exception e243ensure244mod.cleanup245end246247return result248end249end250251end252end253254255