Path: blob/master/lib/msf/base/simple/auxiliary.rb
19516 views
# -*- coding: binary -*-1module Msf2module Simple34###5#6# A simplified auxiliary wrapper.7#8###9module Auxiliary1011include Module1213#14# Wraps the auxiliary process in a simple single method. The options15# hash can have the following values passed in it:16#17# Action18#19# The selected action name.20#21# OptionStr22#23# A string of comma separated option values that should be imported into24# the datastore.25#26# Options27#28# A hash of values to be imported directly into the datastore.29#30# LocalInput31#32# The local input handle that data can be read in from.33#34# LocalOutput35#36# The local output through which data can be displayed.37#38# RunAsJob39#40# Whether or not the exploit should be run in the context of a background41# job.42#43def self.run_simple(omod, opts = {}, job_listener: Msf::Simple::NoopJobListener.instance, &block)4445# Clone the module to prevent changes to the original instance46mod = omod.replicant47Msf::Simple::Framework.simplify_module(mod)48yield(mod) if block_given?4950# Import options from the OptionStr or Option hash.51mod._import_extra_options(opts)5253mod.datastore['ACTION'] = opts['Action'] if opts['Action']5455# Verify the ACTION56if (mod.actions.length > 0 and not mod.action)57raise MissingActionError, "Please use: #{mod.actions.collect {|e| e.name} * ", "}"58end5960# Validate the option container state so that options will61# be normalized62mod.validate6364# Initialize user interaction65if ! opts['Quiet']66mod.init_ui(opts['LocalInput'] || mod.user_input, opts['LocalOutput'] || mod.user_output)67else68mod.init_ui(nil, nil)69end7071run_uuid = Rex::Text.rand_text_alphanumeric(24)72job_listener.waiting run_uuid73ctx = [mod, run_uuid, job_listener]74run_as_job = opts['RunAsJob'].nil? ? mod.passive? : opts['RunAsJob']75if run_as_job76mod.job_id = mod.framework.jobs.start_bg_job(77"Auxiliary: #{mod.refname}",78ctx,79Proc.new { |ctx_| self.job_run_proc(ctx_, &:run) },80Proc.new { |ctx_| self.job_cleanup_proc(ctx_) }81)82# Propagate this back to the caller for console mgmt83omod.job_id = mod.job_id84return [run_uuid, mod.job_id]85else86result = self.job_run_proc(ctx, &:run)87self.job_cleanup_proc(ctx)8889return result90end91end9293#94# Calls the class method.95#96def run_simple(opts = {}, &block)97Msf::Simple::Auxiliary.run_simple(self, opts, &block)98end99100#101# Initiates a check, setting up the exploit to be used. The following102# options can be specified:103#104# LocalInput105#106# The local input handle that data can be read in from.107#108# LocalOutput109#110# The local output through which data can be displayed.111#112def self.check_simple(mod, opts, job_listener: Msf::Simple::NoopJobListener.instance)113Msf::Simple::Framework.simplify_module(mod)114115mod._import_extra_options(opts)116if opts['LocalInput']117mod.init_ui(opts['LocalInput'], opts['LocalOutput'])118end119120unless mod.has_check?121# Bail out early if the module doesn't have check122raise ::NotImplementedError.new(Msf::Exploit::CheckCode::Unsupported.message)123end124125# Validate the option container state so that options will126# be normalized127mod.validate128129run_uuid = Rex::Text.rand_text_alphanumeric(24)130job_listener.waiting run_uuid131ctx = [mod, run_uuid, job_listener]132133if opts['RunAsJob']134mod.job_id = mod.framework.jobs.start_bg_job(135"Auxiliary: #{mod.refname} check",136ctx,137Proc.new do |ctx_|138self.job_run_proc(ctx_) do |m|139m.check140end141end,142Proc.new { |ctx_| self.job_cleanup_proc(ctx_) }143)144145[run_uuid, mod.job_id]146else147# Run check if it exists148result = self.job_run_proc(ctx) do |m|149m.check150end151self.job_cleanup_proc(ctx)152153result154end155end156157#158# Calls the class method.159#160def check_simple(opts = {})161Msf::Simple::Auxiliary.check_simple(self, opts)162end163164165protected166167#168# Job run proc, sets up the module and kicks it off.169#170def self.job_run_proc(ctx, &block)171mod = ctx[0]172run_uuid = ctx[1]173job_listener = ctx[2]174begin175begin176job_listener.start run_uuid177mod.setup178mod.framework.events.on_module_run(mod)179result = block.call(mod)180job_listener.completed(run_uuid, result, mod)181rescue ::Exception => e182job_listener.failed(run_uuid, e, mod)183raise184end185rescue Msf::Auxiliary::Complete186mod.cleanup187return188rescue Msf::Auxiliary::Failed => e189mod.error = e190mod.print_error("Auxiliary aborted due to failure: #{e.message}")191192# The caller should have already set mod.fail_reason193if mod.fail_reason == Msf::Module::Failure::None194mod.fail_reason = Msf::Module::Failure::Unknown195end196mod.fail_detail ||= e.to_s197198mod.cleanup199return200rescue ::Timeout::Error => e201mod.error = e202mod.fail_reason = Msf::Module::Failure::TimeoutExpired203mod.fail_detail ||= e.to_s204mod.print_error("Auxiliary triggered a timeout exception")205mod.cleanup206return207rescue ::Interrupt => e208mod.error = e209mod.fail_reason = Msf::Module::Failure::UserInterrupt210mod.fail_detail ||= e.to_s211mod.print_error("Stopping running against current target...")212mod.cleanup213mod.print_status("Control-C again to force quit all targets.")214begin215Rex.sleep(0.5)216rescue ::Interrupt217raise $!218end219return220rescue ::Msf::OptionValidateError => e221mod.error = e222mod.fail_reason = Msf::Module::Failure::BadConfig223mod.fail_detail ||= e.to_s224::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e)225rescue ::Exception => e226mod.error = e227mod.fail_reason = Msf::Module::Failure::Unknown228mod.fail_detail ||= e.to_s229mod.print_error("Auxiliary failed: #{e.class} #{e}")230if(e.class.to_s != 'Msf::OptionValidateError')231mod.print_error("Call stack:")232e.backtrace.each do |line|233break if line =~ /lib.msf.base.simple.auxiliary.rb/234mod.print_error(" #{line}")235end236end237238elog('Auxiliary failed', error: e)239mod.cleanup240241end242return result243ensure244# Register an attempt in the database (an `Mdm::ExploitAttempt` (and245# possibly an `Mdm::VulnAttempt`).246#247# Since auxiliary modules don't report clearly when it is a success or a248# failure, we are calling #report_failure keeping the `mod.fail_reason`249# value unchanged. This value is set to `Msf::Module::Failure::None` when250# no error was reported. It should be set to another251# `Msf::Module::Failure::*` value otherwise.252mod.report_failure253end254255#256# Clean up the module after the job completes.257#258def self.job_cleanup_proc(ctx)259mod = ctx[0]260mod.framework.events.on_module_complete(mod)261# Allow the exploit to cleanup after itself, that messy bugger.262mod.cleanup263end264265end266267end268end269270271