Land #10203, Add command for persistent job handler when msf restart
commit
d6bce4410c
|
@ -202,6 +202,13 @@ class Config < Hash
|
|||
self.new.history_file
|
||||
end
|
||||
|
||||
# Returns the full path to the handler file.
|
||||
#
|
||||
# @return [String] path the handler file.
|
||||
def self.persist_file
|
||||
self.new.persist_file
|
||||
end
|
||||
|
||||
# Initializes configuration, creating directories as necessary.
|
||||
#
|
||||
# @return [void]
|
||||
|
@ -278,6 +285,13 @@ class Config < Hash
|
|||
config_directory + FileSep + "history"
|
||||
end
|
||||
|
||||
# Returns the full path to the handler file.
|
||||
#
|
||||
# @return [String] path the handler file.
|
||||
def persist_file
|
||||
config_directory + FileSep + "persist"
|
||||
end
|
||||
|
||||
# Returns the global module directory.
|
||||
#
|
||||
# @return [String] path to global module directory.
|
||||
|
|
|
@ -781,10 +781,10 @@ class ReadableText
|
|||
# @param col [Integer] the column wrap width.
|
||||
# @return [String] the formatted list of running jobs.
|
||||
def self.dump_jobs(framework, verbose = false, indent = DefaultIndent, col = DefaultColumnWrap)
|
||||
columns = [ 'Id', 'Name', "Payload", "Payload opts" ]
|
||||
columns = [ 'Id', 'Name', "Payload", "Payload opts"]
|
||||
|
||||
if (verbose)
|
||||
columns += [ "URIPATH", "Start Time", "Handler opts" ]
|
||||
columns += [ "URIPATH", "Start Time", "Handler opts", "Persist" ]
|
||||
end
|
||||
|
||||
tbl = Rex::Text::Table.new(
|
||||
|
@ -793,6 +793,15 @@ class ReadableText
|
|||
'Columns' => columns
|
||||
)
|
||||
|
||||
# Get the persistent job info.
|
||||
if verbose
|
||||
begin
|
||||
persist_list = JSON.parse(File.read(Msf::Config.persist_file))
|
||||
rescue Errno::ENOENT, JSON::ParserError
|
||||
persist_list = []
|
||||
end
|
||||
end
|
||||
|
||||
# jobs are stored as a hash with the keys being a numeric String job_id.
|
||||
framework.jobs.keys.sort_by(&:to_i).each do |job_id|
|
||||
# Job context is stored as an Array with the 0th element being
|
||||
|
@ -827,11 +836,17 @@ class ReadableText
|
|||
row[4] = uripath
|
||||
row[5] = framework.jobs[job_id].start_time
|
||||
row[6] = ''
|
||||
row[7] = 'false'
|
||||
|
||||
if pinst.respond_to?(:listener_uri)
|
||||
listener_uri = pinst.listener_uri.strip
|
||||
row[6] = listener_uri unless listener_uri == payload_uri
|
||||
end
|
||||
|
||||
persist_list.each do |e|
|
||||
row[7] = 'true' if e['mod_options']['Options'] == framework.jobs[job_id.to_s].ctx[1].datastore
|
||||
end
|
||||
|
||||
end
|
||||
tbl << row
|
||||
end
|
||||
|
|
|
@ -35,7 +35,9 @@ module Msf
|
|||
"-i" => [ true, "Lists detailed information about a running job."],
|
||||
"-l" => [ false, "List all running jobs." ],
|
||||
"-v" => [ false, "Print more detailed info. Use with -i and -l" ],
|
||||
"-S" => [ true, "Row search filter." ],
|
||||
"-p" => [ true, "Add persistence to job by job ID" ],
|
||||
"-P" => [ false, "Persist all running jobs on restart." ],
|
||||
"-S" => [ true, "Row search filter." ]
|
||||
)
|
||||
|
||||
def commands
|
||||
|
@ -117,7 +119,9 @@ module Msf
|
|||
verbose = false
|
||||
dump_list = false
|
||||
dump_info = false
|
||||
kill_job = false
|
||||
job_id = nil
|
||||
job_list = nil
|
||||
|
||||
# Parse the command options
|
||||
@@jobs_opts.parse(args) do |opt, _idx, val|
|
||||
|
@ -129,29 +133,31 @@ module Msf
|
|||
# Terminate the supplied job ID(s)
|
||||
when "-k"
|
||||
job_list = build_range_array(val)
|
||||
if job_list.blank?
|
||||
print_error("Please specify valid job identifier(s)")
|
||||
return false
|
||||
end
|
||||
print_status("Stopping the following job(s): #{job_list.join(', ')}")
|
||||
job_list.map(&:to_s).each do |job|
|
||||
if framework.jobs.key?(job)
|
||||
print_status("Stopping job #{job}")
|
||||
framework.jobs.stop_job(job)
|
||||
else
|
||||
print_error("Invalid job identifier: #{job}")
|
||||
end
|
||||
end
|
||||
kill_job = true
|
||||
when "-K"
|
||||
print_line("Stopping all jobs...")
|
||||
framework.jobs.each_key do |i|
|
||||
framework.jobs.stop_job(i)
|
||||
end
|
||||
File.truncate(Msf::Config.persist_file,0)
|
||||
when "-i"
|
||||
# Defer printing anything until the end of option parsing
|
||||
# so we can check for the verbose flag.
|
||||
dump_info = true
|
||||
job_id = val
|
||||
when "-p"
|
||||
job_list = build_range_array(val)
|
||||
job_list.each do |job_id|
|
||||
add_persist_job(job_id)
|
||||
end
|
||||
when "-P"
|
||||
print_line("Making all jobs persistent ...")
|
||||
job_list = framework.jobs.map do |k,v|
|
||||
v.jid.to_s
|
||||
end
|
||||
job_list.each do |job_id|
|
||||
add_persist_job(job_id)
|
||||
end
|
||||
when "-S", "--search"
|
||||
search_term = val
|
||||
dump_list = true
|
||||
|
@ -159,6 +165,7 @@ module Msf
|
|||
cmd_jobs_help
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if dump_list
|
||||
|
@ -186,6 +193,77 @@ module Msf
|
|||
print_line("Invalid Job ID")
|
||||
end
|
||||
end
|
||||
|
||||
if kill_job
|
||||
if job_list.blank?
|
||||
print_error("Please specify valid job identifier(s)")
|
||||
return false
|
||||
end
|
||||
|
||||
print_status("Stopping the following job(s): #{job_list.join(', ')}")
|
||||
|
||||
# Remove the persistent job when match the option of payload.
|
||||
begin
|
||||
persist_list = JSON.parse(File.read(Msf::Config.persist_file))
|
||||
rescue Errno::ENOENT, JSON::ParserError
|
||||
persist_list = []
|
||||
end
|
||||
|
||||
job_list.map(&:to_s).each do |job|
|
||||
payload_option = framework.jobs[job.to_s].ctx[1].datastore
|
||||
persist_list.delete_if{|pjob|pjob['mod_options']['Options'] == payload_option}
|
||||
end
|
||||
# Write persist job back to config file.
|
||||
File.open(Msf::Config.persist_file,"w") do |file|
|
||||
file.puts(JSON.pretty_generate(persist_list))
|
||||
end
|
||||
|
||||
# Stop the job by job id.
|
||||
job_list.map(&:to_s).each do |job|
|
||||
if framework.jobs.key?(job)
|
||||
print_status("Stopping job #{job}")
|
||||
framework.jobs.stop_job(job)
|
||||
else
|
||||
print_error("Invalid job identifier: #{job}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Add a persistent job by job id.
|
||||
# Persistent job would restore on console restarted.
|
||||
|
||||
def add_persist_job(job_id)
|
||||
if job_id && framework.jobs.has_key?(job_id.to_s)
|
||||
mod = framework.jobs[job_id.to_s].ctx[0].replicant
|
||||
payload = framework.jobs[job_id.to_s].ctx[1].replicant
|
||||
|
||||
payload_opts = {
|
||||
'Payload' => payload.refname,
|
||||
'Options' => payload.datastore,
|
||||
'RunAsJob' => true
|
||||
}
|
||||
|
||||
mod_opts = {
|
||||
'mod_name' => mod.fullname,
|
||||
'mod_options' => payload_opts
|
||||
}
|
||||
|
||||
begin
|
||||
persist_list = JSON.parse(File.read(Msf::Config.persist_file))
|
||||
rescue Errno::ENOENT, JSON::ParserError
|
||||
persist_list = []
|
||||
end
|
||||
persist_list << mod_opts
|
||||
File.open(Msf::Config.persist_file,"w") do |file|
|
||||
file.puts(JSON.pretty_generate(persist_list))
|
||||
end
|
||||
print_line("Added persistence to job #{job_id}.")
|
||||
else
|
||||
print_line("Invalid Job ID")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -354,6 +432,7 @@ module Msf
|
|||
}
|
||||
tab_complete_generic(fmt, str, words)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -179,6 +179,22 @@ class Driver < Msf::Ui::Driver
|
|||
}
|
||||
end
|
||||
|
||||
# Process persistent job handler
|
||||
begin
|
||||
restore_handlers = JSON.parse(File.read(Msf::Config.persist_file))
|
||||
rescue Errno::ENOENT, JSON::ParserError
|
||||
restore_handlers = nil
|
||||
end
|
||||
|
||||
unless restore_handlers.nil?
|
||||
print_status("Starting persistent handler(s)...")
|
||||
|
||||
restore_handlers.each do |handler_opts|
|
||||
handler = framework.modules.create(handler_opts['mod_name'])
|
||||
handler.exploit_simple(handler_opts['mod_options'])
|
||||
end
|
||||
end
|
||||
|
||||
# Process any additional startup commands
|
||||
if opts['XCommands'] and opts['XCommands'].kind_of? Array
|
||||
opts['XCommands'].each { |c|
|
||||
|
|
Loading…
Reference in New Issue