lib/msf/ui/console/command_dispatcher/session.rb
# frozen_string_literal: true
module Msf
module Ui
module Console
module CommandDispatcher
module Session
include Rex::Ui::Text::DispatcherShell::CommandDispatcher
@@irb_opts = Rex::Parser::Arguments.new(
%w[-h --help] => [false, 'Help menu.' ],
'-e' => [true, 'Expression to evaluate.']
)
@@sessions_opts = Rex::Parser::Arguments.new(
['-h', '--help'] => [ false, 'Show this message' ],
['-i', '--interact'] => [ true, 'Interact with a provided session ID', '<id>' ]
)
def commands
{
'?' => 'Help menu',
'background' => 'Backgrounds the current session',
'bg' => 'Alias for background',
'exit' => 'Terminate the session',
'help' => 'Help menu',
'irb' => 'Open an interactive Ruby shell on the current session',
'pry' => 'Open the Pry debugger on the current session',
'quit' => 'Terminate the session',
'resource' => 'Run the commands stored in a file',
'uuid' => 'Get the UUID for the current session',
'sessions' => 'Quickly switch to another session'
}
end
def cmd_background_help
print_line('Usage: background')
print_line
print_line('Stop interacting with this session and return to the parent prompt')
print_line
end
def cmd_background(*args)
if args.include?('-h') || args.include?('--help')
cmd_background_help
return
end
print_status("Backgrounding session #{session.name}...")
session.interacting = false
end
alias cmd_bg cmd_background
alias cmd_bg_help cmd_background_help
#
# Terminates the session.
#
def cmd_exit(*args)
print_status("Shutting down session: #{session.sid}")
session.exit
end
alias cmd_quit cmd_exit
def cmd_irb_help
print_line('Usage: irb')
print_line
print_line('Open an interactive Ruby shell on the current session.')
print @@irb_opts.usage
end
def cmd_irb_tabs(str, words)
return [] if words.length > 1
@@irb_opts.option_keys
end
#
# Open an interactive Ruby shell on the current session
#
def cmd_irb(*args)
expressions = []
# Parse the command options
@@irb_opts.parse(args) do |opt, _idx, val|
case opt
when '-e'
expressions << val
when '-h', '--help'
return cmd_irb_help
end
end
framework = session.framework
if expressions.empty?
print_status('Starting IRB shell...')
print_status("You are in the session object\n")
framework.history_manager.with_context(name: :irb) do
Rex::Ui::Text::IrbShell.new(session).run
end
else
# XXX: No vprint_status here
if framework.datastore['VERBOSE'].to_s == 'true'
print_status("You are executing expressions in #{binding.receiver}")
end
expressions.each { |expression| eval(expression, binding) }
end
end
def cmd_pry_help
print_line 'Usage: pry'
print_line
print_line 'Open the Pry debugger on the current session.'
print_line
end
#
# Open the Pry debugger on the current session
#
def cmd_pry(*args)
if args.include?('-h') || args.include?('--help')
cmd_pry_help
return
end
begin
require 'pry'
rescue LoadError
print_error('Failed to load Pry, try "gem install pry"')
return
end
print_status('Starting Pry shell...')
print_status("You are in the session object\n")
Pry.config.history_load = false
session.framework.history_manager.with_context(history_file: Msf::Config.pry_history, name: :pry) do
session.pry
end
end
def cmd_sessions_help
print_line('Usage: sessions [options] or sessions [id]')
print_line
print_line('Interact with a different session ID.')
print(@@sessions_opts.usage)
print_line
end
def cmd_sessions(*args)
if args.empty?
cmd_sessions_help
return false
end
sid = nil
if args.length == 1 && args[0] =~ /-?\d+/
sid = args[0].to_i
else
@@sessions_opts.parse(args) do |opt, _idx, val|
case opt
when '-h', '--help'
cmd_sessions_help
return false
when '-i', '--interact'
sid = val.to_i
else
cmd_sessions_help
return false
end
end
end
if sid == 0 || sid.nil?
cmd_sessions_help
return false
end
if sid.to_s == session.name.to_s
print_status("Session #{session.name} is already interactive.")
else
print_status("Backgrounding session #{session.name}...")
# store the next session id so that it can be referenced as soon
# as this session is no longer interacting
session.next_session = sid
session.interacting = false
end
end
def cmd_resource_help
print_line 'Usage: resource path1 [path2 ...]'
print_line
print_line 'Run the commands stored in the supplied files. (- for stdin, press CTRL+D to end input from stdin)'
print_line 'Resource files may also contain ERB or Ruby code between <ruby></ruby> tags.'
print_line
end
def cmd_resource(*args)
if args.empty? || args.include?('-h') || args.include?('--help')
cmd_resource_help
return false
end
args.each do |res|
good_res = nil
if res == '-'
good_res = res
elsif ::File.exist?(res)
good_res = res
elsif [
::Msf::Config.script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter',
::Msf::Config.user_script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter'
].each do |dir|
res_path = dir + ::File::SEPARATOR + res
if ::File.exist?(res_path)
good_res = res_path
break
end
end
# let's check to see if it's in the scripts/resource dir (like when tab completed)
end
unless good_res
print_error("#{res} is not a valid resource file")
next
end
session.console.load_resource(good_res)
end
end
def cmd_resource_tabs(str, words)
tabs = []
# return tabs if words.length > 1
if (str && str =~ (/^#{Regexp.escape(::File::SEPARATOR)}/))
# then you are probably specifying a full path so let's just use normal file completion
return tab_complete_filenames(str, words)
elsif (!(words[1]) || !words[1].match(%r{^/}))
# then let's start tab completion in the scripts/resource directories
begin
[
::Msf::Config.script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter',
::Msf::Config.user_script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter',
'.'
].each do |dir|
next if !::File.exist? dir
tabs += ::Dir.new(dir).find_all do |e|
path = dir + ::File::SEPARATOR + e
::File.file?(path) and ::File.readable?(path)
end
end
rescue StandardError => e
elog('Problem tab completing resource file names in the scripts/resource directories', error: e)
end
else
tabs += tab_complete_filenames(str, words)
end
return tabs
end
end
end
end
end
end