5e65976089
Allows console users to use the 'run' command for exploits as well as auxiliary and post, in the same way that 'exploit' works for all three. Saves some typing and makes it do the right thing so users don't have to remember what kind of module they're using.
286 lines
7.4 KiB
Ruby
286 lines
7.4 KiB
Ruby
# -*- coding: binary -*-
|
|
module Msf
|
|
module Ui
|
|
module Console
|
|
module CommandDispatcher
|
|
|
|
###
|
|
#
|
|
# Exploit module command dispatcher.
|
|
#
|
|
###
|
|
class Exploit
|
|
|
|
include Msf::Ui::Console::ModuleCommandDispatcher
|
|
|
|
@@exploit_opts = Rex::Parser::Arguments.new(
|
|
"-e" => [ true, "The payload encoder to use. If none is specified, ENCODER is used." ],
|
|
"-f" => [ false, "Force the exploit to run regardless of the value of MinimumRank." ],
|
|
"-h" => [ false, "Help banner." ],
|
|
"-j" => [ false, "Run in the context of a job." ],
|
|
"-n" => [ true, "The NOP generator to use. If none is specified, NOP is used." ],
|
|
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
|
|
"-p" => [ true, "The payload to use. If none is specified, PAYLOAD is used." ],
|
|
"-t" => [ true, "The target index to use. If none is specified, TARGET is used." ],
|
|
"-z" => [ false, "Do not interact with the session after successful exploitation." ])
|
|
|
|
#
|
|
# Returns the hash of exploit module specific commands.
|
|
#
|
|
def commands
|
|
super.update({
|
|
"check" => "Check to see if a target is vulnerable",
|
|
"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",
|
|
"reload" => "Just reloads the module",
|
|
"run" => "Alias for exploit",
|
|
"rerun" => "Alias for rexploit",
|
|
})
|
|
end
|
|
|
|
#
|
|
# Returns the name of the command dispatcher.
|
|
#
|
|
def name
|
|
"Exploit"
|
|
end
|
|
|
|
#
|
|
# Checks to see if a target is vulnerable.
|
|
#
|
|
def cmd_check(*args)
|
|
defanged?
|
|
|
|
begin
|
|
|
|
code = mod.check_simple(
|
|
'LocalInput' => driver.input,
|
|
'LocalOutput' => driver.output)
|
|
|
|
if (code and code.kind_of?(Array) and code.length > 1)
|
|
|
|
if (code == Msf::Exploit::CheckCode::Vulnerable)
|
|
print_good(code[1])
|
|
else
|
|
print_status(code[1])
|
|
end
|
|
|
|
else
|
|
print_error("Check failed: The state could not be determined.")
|
|
end
|
|
|
|
rescue ::Interrupt
|
|
raise $!
|
|
rescue ::Exception => e
|
|
print_error("Exploit check failed: #{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
|
|
end
|
|
|
|
#
|
|
# Launches an exploitation attempt.
|
|
#
|
|
def cmd_exploit(*args)
|
|
defanged?
|
|
|
|
opt_str = nil
|
|
payload = mod.datastore['PAYLOAD']
|
|
encoder = mod.datastore['ENCODER']
|
|
target = mod.datastore['TARGET']
|
|
nop = mod.datastore['NOP']
|
|
bg = false
|
|
jobify = false
|
|
force = false
|
|
|
|
# Always run passive exploits in the background
|
|
if (mod.passive?)
|
|
jobify = true
|
|
end
|
|
|
|
@@exploit_opts.parse(args) { |opt, idx, val|
|
|
case opt
|
|
when '-e'
|
|
encoder = val
|
|
when '-f'
|
|
force = true
|
|
when '-j'
|
|
jobify = true
|
|
when '-n'
|
|
nop = val
|
|
when '-o'
|
|
opt_str = val
|
|
when '-p'
|
|
payload = val
|
|
when '-t'
|
|
target = val.to_i
|
|
when '-z'
|
|
bg = true
|
|
when '-h'
|
|
cmd_exploit_help
|
|
return false
|
|
end
|
|
}
|
|
|
|
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
|
|
|
|
if not payload
|
|
payload = Exploit.choose_payload(mod, target)
|
|
end
|
|
|
|
begin
|
|
session = mod.exploit_simple(
|
|
'Encoder' => encoder,
|
|
'Payload' => payload,
|
|
'Target' => target,
|
|
'Nop' => nop,
|
|
'OptionStr' => opt_str,
|
|
'LocalInput' => driver.input,
|
|
'LocalOutput' => driver.output,
|
|
'RunAsJob' => jobify)
|
|
rescue ::Interrupt
|
|
raise $!
|
|
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
|
|
|
|
# If we were given a session, let's see what we can do with it
|
|
if (session)
|
|
|
|
# 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.
|
|
if (bg == false and session.interactive?)
|
|
print_line
|
|
|
|
driver.run_single("sessions -q -i #{session.sid}")
|
|
# Otherwise, log that we created a session
|
|
else
|
|
print_status("Session #{session.sid} created in the background.")
|
|
end
|
|
# If we ran the exploit as a job, indicate such so the user doesn't
|
|
# wonder what's up.
|
|
elsif (jobify)
|
|
if mod.job_id
|
|
print_status("Exploit running as background job.")
|
|
end
|
|
# Worst case, the exploit ran but we got no session, bummer.
|
|
else
|
|
# 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.datastore["DisablePayloadHandler"])
|
|
print_status("Exploit completed, but no session was created.")
|
|
end
|
|
end
|
|
end
|
|
|
|
alias cmd_run cmd_exploit
|
|
|
|
def cmd_exploit_help
|
|
print_line "Usage: exploit [options]"
|
|
print_line
|
|
print_line "Launches an exploitation attempt."
|
|
print @@exploit_opts.usage
|
|
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)
|
|
reload()
|
|
|
|
cmd_check(*args)
|
|
end
|
|
|
|
#
|
|
# Reloads an exploit module and launches an exploit.
|
|
#
|
|
def cmd_rexploit(*args)
|
|
return cmd_rexploit_help if args.include? "-h"
|
|
|
|
# Stop existing job and reload the module
|
|
if reload(true)
|
|
# Delegate to the exploit command unless the reload failed
|
|
cmd_exploit(*args)
|
|
end
|
|
end
|
|
|
|
alias cmd_rerun cmd_rexploit
|
|
|
|
def cmd_rexploit_help
|
|
print_line "Usage: rexploit [options]"
|
|
print_line
|
|
print_line "Reloads a module, stopping any associated job, and launches an exploitation attempt."
|
|
print @@exploit_opts.usage
|
|
end
|
|
|
|
alias cmd_rerun_help cmd_rexploit_help
|
|
|
|
#
|
|
# Picks a reasonable payload and minimally configures it
|
|
#
|
|
def self.choose_payload(mod, target)
|
|
|
|
# Choose either the real target or an invalid address
|
|
# This is used to determine the LHOST value
|
|
rhost = mod.datastore['RHOST'] || '50.50.50.50'
|
|
|
|
# A list of preferred payloads in the best-first order
|
|
pref = [
|
|
'windows/meterpreter/reverse_tcp',
|
|
'java/meterpreter/reverse_tcp',
|
|
'php/meterpreter/reverse_tcp',
|
|
'php/meterpreter_reverse_tcp',
|
|
'ruby/shell_reverse_tcp',
|
|
'cmd/unix/interact',
|
|
'cmd/unix/reverse',
|
|
'cmd/unix/reverse_perl',
|
|
'cmd/unix/reverse_netcat_gaping',
|
|
'windows/meterpreter/reverse_nonx_tcp',
|
|
'windows/meterpreter/reverse_ord_tcp',
|
|
'windows/shell/reverse_tcp',
|
|
'generic/shell_reverse_tcp'
|
|
]
|
|
pset = mod.compatible_payloads.map{|x| x[0] }
|
|
pref.each do |n|
|
|
if(pset.include?(n))
|
|
mod.datastore['PAYLOAD'] = n
|
|
mod.datastore['LHOST'] = Rex::Socket.source_address(rhost)
|
|
return n
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
end
|
|
|
|
end end end end
|