# -*- coding: binary -*- module Msf module Ui module Console module CommandDispatcher ### # # Exploit module command dispatcher. # ### class Exploit include Msf::Ui::Console::ModuleCommandDispatcher include Msf::Ui::Console::ModuleArgumentParsing include Msf::Ui::Console::ModuleOptionTabCompletion # # Returns the hash of exploit module specific commands. # def commands super.update({ "exploit" => "Launch an exploit attempt", "rcheck" => "Reloads the module and checks if the target is vulnerable", "rexploit" => "Reloads the module and launches an exploit attempt", "run" => "Alias for exploit", "recheck" => "Alias for rcheck", "rerun" => "Alias for rexploit", "reload" => "Just reloads the module" }) end # # Returns the name of the command dispatcher. # def name "Exploit" end # # Launches an exploitation single attempt. # def exploit_single(mod, opts) begin session = mod.exploit_simple(opts) rescue ::Interrupt raise $! rescue ::Msf::OptionValidateError => e ::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e) rescue ::Exception => e print_error("Exploit exception (#{mod.refname}): #{e.class} #{e}") if e.class.to_s != 'Msf::OptionValidateError' print_error("Call stack:") e.backtrace.each do |line| break if line =~ /lib.msf.base.simple/ print_error(" #{line}") end end end return session end # # Tab completion for the run command # def cmd_run_tabs(str, words) fmt = { '-e' => [ framework.encoders.module_refnames ], '-f' => [ nil ], '-h' => [ nil ], '-j' => [ nil ], '-J' => [ nil ], '-n' => [ framework.nops.module_refnames ], '-o' => [ true ], '-p' => [ framework.payloads.module_refnames ], '-r' => [ nil ], '-t' => [ true ], '-z' => [ nil ] } flags = tab_complete_generic(fmt, str, words) options = tab_complete_option(active_module, str, words) flags + options end # # Tab completion for the exploit command # alias cmd_exploit_tabs cmd_run_tabs # # Launches exploitation attempts. # def cmd_exploit(*args, opts: {}) if (args.include?('-r') || args.include?('--reload-libs')) && !opts[:previously_reloaded] driver.run_single('reload_lib -a') end return false unless (args = parse_exploit_opts(args)) any_session = false force = args[:force] || false minrank = RankingName.invert[framework.datastore['MinimumRank']] || 0 if minrank > mod.rank if force print_status("Forcing #{mod.refname} to run despite MinimumRank '#{framework.datastore['MinimumRank']}'") ilog("Forcing #{mod.refname} to run despite MinimumRank '#{framework.datastore['MinimumRank']}'", 'core') else print_error("This exploit is below the minimum rank, '#{framework.datastore['MinimumRank']}'.") print_error("If you really want to run it, do 'exploit -f' or") print_error("setg MinimumRank to something lower ('manual' is") print_error("the lowest and would allow running all exploits).") return end end mod_with_opts = mod.replicant mod_with_opts.datastore.import_options_from_hash(args[:datastore_options]) rhosts = mod_with_opts.datastore['RHOSTS'] has_rhosts_option = mod.options.include?('RHOSTS') || mod.options.include?('RHOST') || mod.options.include?('rhost') || mod.options.include?('rhosts') opts = { 'Encoder' => args[:encoder] || mod_with_opts.datastore['ENCODER'], 'Payload' => args[:payload] || mod_with_opts.datastore['PAYLOAD'], 'Target' => args[:target] || mod_with_opts.datastore['TARGET'], 'Nop' => args[:nop] || mod_with_opts.datastore['NOP'], 'LocalInput' => driver.input, 'LocalOutput' => driver.output, 'RunAsJob' => args[:jobify] || mod_with_opts.passive?, 'Background' => args[:background] || false, 'Force' => force, 'Quiet' => args[:quiet] || false } begin mod_with_opts.validate rescue ::Msf::OptionValidateError => e ::Msf::Ui::Formatter::OptionValidateError.print_error(mod_with_opts, e) return false end driver.run_single('reload_lib -a') if args[:reload_libs] if rhosts && has_rhosts_option rhosts_walker = Msf::RhostsWalker.new(rhosts, mod_with_opts.datastore) rhosts_walker_count = rhosts_walker.count rhosts_walker = rhosts_walker.to_enum end # For multiple targets exploit attempts. if rhosts_walker && rhosts_walker_count > 1 opts[:multi] = true rhosts_walker.with_index do |datastore, index| nmod = mod_with_opts.replicant nmod.datastore.merge!(datastore) # If rhost is the last target, let exploit handler stop. is_last_target = (index + 1) == rhosts_walker_count opts["multi"] = false if is_last_target # Catch the interrupt exception to stop the whole module during exploit begin print_status("Exploiting target #{datastore['RHOSTS']}") session = exploit_single(nmod, opts) rescue ::Interrupt print_status("Stopping exploiting current target #{datastore['RHOSTS']}...") print_status("Control-C again to force quit exploiting all targets.") begin Rex.sleep(1) rescue ::Interrupt raise $! end end # If we were given a session, report it. if session print_status("Session #{session.sid} created in the background.") any_session = true end end # For single target or no rhosts option. else nmod = mod_with_opts.replicant if rhosts_walker && rhosts_walker_count == 1 nmod.datastore.merge!(rhosts_walker.next) end session = exploit_single(nmod, opts) # If we were given a session, let's see what we can do with it if session any_session = true if !opts['Background'] && session.interactive? # If we aren't told to run in the background and the session can be # interacted with, start interacting with it by issuing the session # interaction command. print_line driver.run_single("sessions -q -i #{session.sid}") # Otherwise, log that we created a session else # Otherwise, log that we created a session print_status("Session #{session.sid} created in the background.") end elsif opts['RunAsJob'] && nmod.job_id # Indicate if he exploit as a job, indicate such so the user doesn't # wonder what's up. print_status("Exploit running as background job #{nmod.job_id}.") # Worst case, the exploit ran but we got no session, bummer. end end # If we didn't get any session and exploit ended launch. unless any_session # If we didn't run a payload handler for this exploit it doesn't # make sense to complain to the user that we didn't get a session unless mod_with_opts.datastore["DisablePayloadHandler"] fail_msg = 'Exploit completed, but no session was created.' print_status(fail_msg) begin framework.events.on_session_fail(fail_msg) rescue ::Exception => e wlog("Exception in on_session_open event handler: #{e.class}: #{e}") wlog("Call Stack\n#{e.backtrace.join("\n")}") end end end end alias cmd_run cmd_exploit def cmd_exploit_help print_module_run_or_check_usage(command: :run, options: @@exploit_opts) end alias cmd_run_help cmd_exploit_help # # Reloads an exploit module and checks the target to see if it's # vulnerable. # def cmd_rcheck(*args) opts = {} if args.include?('-r') || args.include?('--reload-libs') driver.run_single('reload_lib -a') opts[:previously_reloaded] = true end reload() cmd_check(*args, opts: opts) end alias cmd_recheck cmd_rcheck # # Reloads an exploit module and launches an exploit. # def cmd_rexploit(*args) opts = {} if args.include?('-r') || args.include?('--reload-libs') driver.run_single('reload_lib -a') opts[:previously_reloaded] = true end return cmd_rexploit_help if args.include?('-h') || args.include?('--help') # Stop existing job and reload the module if reload(true) # Delegate to the exploit command unless the reload failed cmd_exploit(*args, opts: opts) end end alias cmd_rerun cmd_rexploit alias cmd_rerun_tabs cmd_run_tabs alias cmd_rexploit_tabs cmd_exploit_tabs def cmd_rexploit_help print_module_run_or_check_usage( command: :rexploit, description: 'Reloads a module, stopping any associated job, and launches an exploitation attempt.', options: @@exploit_opts ) end alias cmd_rerun_help cmd_rexploit_help # Select a reasonable default payload and minimally configure it # @param [Msf::Module] mod def self.choose_payload(mod) Msf::Payload.choose_payload(mod) end end end end end end