Land #10705, reload_lib -a/--all options

4.x
William Vu 2018-09-27 22:15:01 -05:00 committed by Metasploit
parent f56194516e
commit b94958234a
No known key found for this signature in database
GPG Key ID: CDFB5FA52007B954
2 changed files with 96 additions and 47 deletions

View File

@ -5,8 +5,9 @@ class Msf::Ui::Console::CommandDispatcher::Developer
include Msf::Ui::Console::CommandDispatcher include Msf::Ui::Console::CommandDispatcher
@@irb_opts = Rex::Parser::Arguments.new( @@irb_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ], '-h' => [false, 'Help menu.' ],
"-e" => [ true, "Expression to evaluate." ]) '-e' => [true, 'Expression to evaluate.']
)
def initialize(driver) def initialize(driver)
super super
@ -18,11 +19,11 @@ class Msf::Ui::Console::CommandDispatcher::Developer
def commands def commands
{ {
'irb' => 'Drop into irb scripting mode', 'irb' => 'Open an interactive Ruby shell in the current context',
'pry' => 'Open a Pry session on the current module or Framework', 'pry' => 'Open the Pry debugger on the current module or Framework',
'edit' => 'Edit the current module or a file with the preferred editor', 'edit' => 'Edit the current module or a file with the preferred editor',
'reload_lib' => 'Reload one or more library files from specified paths', 'reload_lib' => 'Reload Ruby library files from specified paths',
'log' => 'Displays framework.log starting at the bottom if possible' 'log' => 'Display framework.log paged to the end if possible'
} }
end end
@ -35,31 +36,52 @@ class Msf::Ui::Console::CommandDispatcher::Developer
end end
# XXX: This will try to reload *any* .rb and break on modules # XXX: This will try to reload *any* .rb and break on modules
def reload_file(path) def reload_file(path, print_errors: true)
unless File.exist?(path) && path.end_with?('.rb') full_path = File.expand_path(path)
print_error("#{path} must exist and be a .rb file")
unless File.exist?(full_path) && full_path.end_with?('.rb')
print_error("#{full_path} must exist and be a .rb file") if print_errors
return return
end end
# The file must exist to reach this, so we try our best here # The file must exist to reach this, so we try our best here
if path =~ %r{^(?:\./)?modules/} if full_path.start_with?(Msf::Config.module_directory, Msf::Config.user_module_directory)
print_error("Reloading Metasploit modules is not supported (try 'reload')") print_error('Reloading Metasploit modules is not supported (try "reload")') if print_errors
return return
end end
print_status("Reloading #{path}") print_status("Reloading #{full_path}")
load path load full_path
end
def reload_changed_files
# Using an array avoids shelling out, so we avoid escaping/quoting
changed_files = %w[git diff --name-only]
output, status = Open3.capture2e(*changed_files, chdir: Msf::Config.install_root)
unless status.success?
print_error("Git is not available: #{output.chomp}")
return
end
files = output.split("\n")
files.each do |file|
f = File.join(Msf::Config.install_root, file)
reload_file(file, print_errors: false)
end
end end
def cmd_irb_help def cmd_irb_help
print_line "Usage: irb" print_line 'Usage: irb'
print_line print_line
print_line "Execute commands in a Ruby environment" print_line 'Open an interactive Ruby shell in the current context.'
print @@irb_opts.usage print @@irb_opts.usage
end end
# #
# Goes into IRB scripting mode # Open an interactive Ruby shell in the current context
# #
def cmd_irb(*args) def cmd_irb(*args)
expressions = [] expressions = []
@ -76,10 +98,16 @@ class Msf::Ui::Console::CommandDispatcher::Developer
end end
if expressions.empty? if expressions.empty?
print_status("Starting IRB shell...\n") print_status('Starting IRB shell...')
begin begin
Rex::Ui::Text::IrbShell.new(binding).run if active_module
print_status("You are in #{active_module.fullname}\n")
Rex::Ui::Text::IrbShell.new(active_module).run
else
print_status("You are in the \"framework\" object\n")
Rex::Ui::Text::IrbShell.new(framework).run
end
rescue rescue
print_error("Error during IRB: #{$!}\n\n#{$@.join("\n")}") print_error("Error during IRB: #{$!}\n\n#{$@.join("\n")}")
end end
@ -89,6 +117,11 @@ class Msf::Ui::Console::CommandDispatcher::Developer
driver.input.reset_tab_completion driver.input.reset_tab_completion
end end
else else
# XXX: No vprint_status here either
if framework.datastore['VERBOSE'].to_s == 'true'
print_status("You are executing expressions in #{binding.receiver}")
end
expressions.each { |expression| eval(expression, binding) } expressions.each { |expression| eval(expression, binding) }
end end
end end
@ -104,12 +137,12 @@ class Msf::Ui::Console::CommandDispatcher::Developer
def cmd_pry_help def cmd_pry_help
print_line 'Usage: pry' print_line 'Usage: pry'
print_line print_line
print_line 'Open a Pry session on the current module or Framework.' print_line 'Open the Pry debugger on the current module or Framework.'
print_line print_line
end end
# #
# Open a Pry session on the current module or Framework # Open the Pry debugger on the current module or Framework
# #
def cmd_pry(*args) def cmd_pry(*args)
if args.include?('-h') if args.include?('-h')
@ -141,7 +174,7 @@ class Msf::Ui::Console::CommandDispatcher::Developer
print_line print_line
print_line "Edit the currently active module or a local file with #{local_editor}." print_line "Edit the currently active module or a local file with #{local_editor}."
print_line 'If a library file is specified, it will automatically be reloaded after editing.' print_line 'If a library file is specified, it will automatically be reloaded after editing.'
print_line "Otherwise, you can reload the active module with 'reload' or 'rerun'." print_line 'Otherwise, you can reload the active module with "reload" or "rerun".'
print_line print_line
end end
@ -192,22 +225,32 @@ class Msf::Ui::Console::CommandDispatcher::Developer
end end
def cmd_reload_lib_help def cmd_reload_lib_help
print_line 'Usage: reload_lib lib/to/reload.rb [...]' cmd_reload_lib('-h')
print_line
print_line 'Reload one or more library files from specified paths.'
print_line
end end
# #
# Reload one or more library files from specified paths # Reload Ruby library files from specified paths
# #
def cmd_reload_lib(*args) def cmd_reload_lib(*args)
if args.empty? || args.include?('-h') || args.include?('--help') options = OptionParser.new do |opts|
cmd_reload_lib_help opts.banner = 'Usage: reload_lib lib/to/reload.rb [...]'
return opts.separator ''
opts.separator 'Reload Ruby library files from specified paths.'
opts.separator ''
opts.on '-h', '--help', 'Help banner.' do
return print(opts.help)
end
opts.on '-a', '--all', 'Reload all* changed files in your current Git working tree.
*Excludes modules and non-Ruby files.' do
reload_changed_files
return
end
end end
args.each { |path| reload_file(path) } files = options.order(args)
files.each { |file| reload_file(file) }
end end
# #
@ -220,15 +263,15 @@ class Msf::Ui::Console::CommandDispatcher::Developer
def cmd_log_help def cmd_log_help
print_line 'Usage: log' print_line 'Usage: log'
print_line print_line
print_line 'Displays framework.log starting at the bottom if possible.' print_line 'Display framework.log paged to the end if possible.'
print_line "For full effect, 'setg LogLevel 3' before running modules." print_line 'For full effect, "setg LogLevel 3" before running modules.'
print_line print_line
print_line "Log location: #{File.join(Msf::Config.log_directory, 'framework.log')}" print_line "Log location: #{File.join(Msf::Config.log_directory, 'framework.log')}"
print_line print_line
end end
# #
# Displays framework.log starting at the bottom if possible # Display framework.log paged to the end if possible
# #
def cmd_log(*args) def cmd_log(*args)
path = File.join(Msf::Config.log_directory, 'framework.log') path = File.join(Msf::Config.log_directory, 'framework.log')

View File

@ -34,12 +34,14 @@ class Console::CommandDispatcher::Core
end end
@@irb_opts = Rex::Parser::Arguments.new( @@irb_opts = Rex::Parser::Arguments.new(
'-h' => [false, 'Help banner.'], '-h' => [false, 'Help menu.' ],
'-e' => [true, 'Expression to evaluate.']) '-e' => [true, 'Expression to evaluate.']
)
@@load_opts = Rex::Parser::Arguments.new( @@load_opts = Rex::Parser::Arguments.new(
'-l' => [false, 'List all available extensions'], '-h' => [false, 'Help menu.' ],
'-h' => [false, 'Help menu.']) '-l' => [false, 'List all available extensions.']
)
# #
# List of supported commands. # List of supported commands.
@ -52,8 +54,8 @@ class Console::CommandDispatcher::Core
'channel' => 'Displays information or control active channels', 'channel' => 'Displays information or control active channels',
'exit' => 'Terminate the meterpreter session', 'exit' => 'Terminate the meterpreter session',
'help' => 'Help menu', 'help' => 'Help menu',
'irb' => 'Drop into irb scripting mode', 'irb' => 'Open an interactive Ruby shell on the current session',
'pry' => 'Open a Pry session on the current session', 'pry' => 'Open the Pry debugger on the current session',
'use' => 'Deprecated alias for "load"', 'use' => 'Deprecated alias for "load"',
'load' => 'Load one or more meterpreter extensions', 'load' => 'Load one or more meterpreter extensions',
'machine_id' => 'Get the MSF ID of the machine attached to the session', 'machine_id' => 'Get the MSF ID of the machine attached to the session',
@ -532,7 +534,7 @@ class Console::CommandDispatcher::Core
def cmd_irb_help def cmd_irb_help
print_line('Usage: irb') print_line('Usage: irb')
print_line print_line
print_line('Execute commands in a Ruby environment') print_line('Open an interactive Ruby shell on the current session.')
print @@irb_opts.usage print @@irb_opts.usage
end end
@ -542,7 +544,7 @@ class Console::CommandDispatcher::Core
end end
# #
# Runs the IRB scripting shell # Open an interactive Ruby shell on the current session
# #
def cmd_irb(*args) def cmd_irb(*args)
expressions = [] expressions = []
@ -561,12 +563,16 @@ class Console::CommandDispatcher::Core
framework = client.framework framework = client.framework
if expressions.empty? if expressions.empty?
print_status('Starting IRB shell') print_status('Starting IRB shell...')
print_status('The "client" variable holds the meterpreter client') print_status("You are in the \"client\" (session) object\n")
print_line
Rex::Ui::Text::IrbShell.new(binding).run Rex::Ui::Text::IrbShell.new(client).run
else 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) } expressions.each { |expression| eval(expression, binding) }
end end
end end
@ -574,12 +580,12 @@ class Console::CommandDispatcher::Core
def cmd_pry_help def cmd_pry_help
print_line 'Usage: pry' print_line 'Usage: pry'
print_line print_line
print_line 'Open a Pry session on the current session.' print_line 'Open the Pry debugger on the current session.'
print_line print_line
end end
# #
# Open a Pry session on the current session # Open the Pry debugger on the current session
# #
def cmd_pry(*args) def cmd_pry(*args)
if args.include?('-h') if args.include?('-h')