From 184670f62c06e5c2c90646932f3865d64aff809c Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Tue, 17 Jul 2018 17:10:23 -0500 Subject: [PATCH] Land #10329, Add command dispatcher for developer commands --- lib/msf/ui/console/command_dispatcher/core.rb | 1 + .../console/command_dispatcher/developer.rb | 162 ++++++++++++++++++ .../ui/console/command_dispatcher/modules.rb | 142 --------------- lib/msf/ui/console/driver.rb | 3 +- 4 files changed, 165 insertions(+), 143 deletions(-) create mode 100644 lib/msf/ui/console/command_dispatcher/developer.rb diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 8838f1f60c..1d612cae38 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -19,6 +19,7 @@ require 'msf/ui/console/command_dispatcher/post' require 'msf/ui/console/command_dispatcher/jobs' require 'msf/ui/console/command_dispatcher/resource' require 'msf/ui/console/command_dispatcher/modules' +require 'msf/ui/console/command_dispatcher/developer' require 'msf/util/document_generator' module Msf diff --git a/lib/msf/ui/console/command_dispatcher/developer.rb b/lib/msf/ui/console/command_dispatcher/developer.rb new file mode 100644 index 0000000000..d829b3c587 --- /dev/null +++ b/lib/msf/ui/console/command_dispatcher/developer.rb @@ -0,0 +1,162 @@ +# -*- coding: binary -*- + +class Msf::Ui::Console::CommandDispatcher::Developer + + include Msf::Ui::Console::CommandDispatcher + + def initialize(driver) + super + end + + def name + 'Developer' + end + + def commands + { + 'edit' => 'Edit the current module or a file with the preferred editor', + 'reload_lib' => 'Reload one or more library files from specified paths', + 'log' => 'Displays framework.log starting at the bottom if possible' + } + end + + def local_editor + framework.datastore['LocalEditor'] || Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') + end + + def local_pager + framework.datastore['LocalPager'] || Rex::Compat.getenv('PAGER') || Rex::Compat.getenv('MANPAGER') + end + + # XXX: This will try to reload *any* .rb and break on modules + def reload_file(path) + unless File.exist?(path) && path.end_with?('.rb') + print_error("#{path} must exist and be a .rb file") + return + end + + # The file must exist to reach this, so we try our best here + if path =~ %r{^(?:\./)?modules/} + print_error('Reloading Metasploit modules is not supported (try "reload")') + return + end + + print_status("Reloading #{path}") + load path + end + + def cmd_edit_help + print_line 'Usage: edit [file/to/edit]' + print_line + 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 "Otherwise, you can reload the active module with 'reload' or 'rerun'." + print_line + end + + # + # Edit the current module or a file with the preferred editor + # + def cmd_edit(*args) + editing_module = false + + if args.length > 0 + path = File.expand_path(args[0]) + elsif active_module + editing_module = true + path = active_module.file_path + end + + unless path + print_error('Nothing to edit. Try using a module first or specifying a library file to edit.') + return + end + + editor = local_editor + + unless editor + editor = 'vim' + print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.") + end + + # XXX: No vprint_status in this context? + # XXX: VERBOSE is a string instead of Bool?? + print_status("Launching #{editor} #{path}") if framework.datastore['VERBOSE'].to_s == 'true' + + unless system(*editor.split, path) + print_error("Could not execute #{editor} #{path}") + return + end + + return if editing_module + + reload_file(path) + end + + # + # Tab completion for the edit command + # + def cmd_edit_tabs(str, words) + tab_complete_filenames(str, words) + end + + def cmd_reload_lib_help + print_line 'Usage: reload_lib lib/to/reload.rb [...]' + print_line + print_line 'Reload one or more library files from specified paths.' + print_line + end + + # + # Reload one or more library files from specified paths + # + def cmd_reload_lib(*args) + if args.empty? || args.include?('-h') || args.include?('--help') + cmd_reload_lib_help + return + end + + args.each { |path| reload_file(path) } + end + + # + # Tab completion for the reload_lib command + # + def cmd_reload_lib_tabs(str, words) + tab_complete_filenames(str, words) + end + + def cmd_log_help + print_line 'Usage: log' + print_line + print_line 'Displays framework.log starting at the bottom if possible.' + print_line "For full effect, 'setg LogLevel 3' before running modules." + print_line + print_line "Log location: #{File.join(Msf::Config.log_directory, 'framework.log')}" + print_line + end + + # + # Displays framework.log starting at the bottom if possible + # + def cmd_log(*args) + path = File.join(Msf::Config.log_directory, 'framework.log') + + # XXX: +G isn't portable and may hang on large files + pager = local_pager.to_s.include?('less') ? "#{local_pager} +G" : local_pager + + unless pager + pager = 'tail -n 24' + print_warning("LocalPager or $PAGER/$MANPAGER should be set. Falling back on #{pager}.") + end + + # XXX: No vprint_status in this context? + # XXX: VERBOSE is a string instead of Bool?? + print_status("Launching #{pager} #{path}") if framework.datastore['VERBOSE'].to_s == 'true' + + unless system(*pager.split, path) + print_error("Could not execute #{pager} #{path}") + end + end + +end diff --git a/lib/msf/ui/console/command_dispatcher/modules.rb b/lib/msf/ui/console/command_dispatcher/modules.rb index 2b8f06bd2d..f74feb084a 100644 --- a/lib/msf/ui/console/command_dispatcher/modules.rb +++ b/lib/msf/ui/console/command_dispatcher/modules.rb @@ -38,9 +38,6 @@ module Msf "search" => "Searches module names and descriptions", "show" => "Displays modules of a given type, or all modules", "use" => "Selects a module by name", - "edit" => "Edit the current module or a file with the preferred editor", - "reload_lib" => "Reload one or more library files from specified paths", - "log" => "Displays framework.log starting at the bottom if possible", } end @@ -63,145 +60,6 @@ module Msf "Module" end - def local_editor - framework.datastore['LocalEditor'] || Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') - end - - def local_pager - framework.datastore['LocalPager'] || Rex::Compat.getenv('PAGER') || Rex::Compat.getenv('MANPAGER') - end - - # XXX: This will try to reload *any* .rb and break on modules - def reload_file(path) - unless File.exist?(path) && path.end_with?('.rb') - print_error("#{path} must exist and be a .rb file") - return - end - - # The file must exist to reach this, so we try our best here - if path =~ %r{^(?:\./)?modules/} - print_error('Reloading Metasploit modules is not supported (try "reload")') - return - end - - print_status("Reloading #{path}") - load path - end - - def cmd_edit_help - print_line 'Usage: edit [file/to/edit]' - print_line - 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 "Otherwise, you can reload the active module with 'reload' or 'rerun'." - print_line - end - - # - # Edit the current module or a file with the preferred editor - # - def cmd_edit(*args) - editing_module = false - - if args.length > 0 - path = File.expand_path(args[0]) - elsif active_module - editing_module = true - path = active_module.file_path - end - - unless path - print_error('Nothing to edit. Try using a module first or specifying a library file to edit.') - return - end - - editor = local_editor - - unless editor - editor = 'vim' - print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.") - end - - # XXX: No vprint_status in this context? - # XXX: VERBOSE is a string instead of Bool?? - print_status("Launching #{editor} #{path}") if framework.datastore['VERBOSE'].to_s == 'true' - - unless system(*editor.split, path) - print_error("Could not execute #{editor} #{path}") - return - end - - return if editing_module - - reload_file(path) - end - - # - # Tab completion for the edit command - # - def cmd_edit_tabs(str, words) - tab_complete_filenames(str, words) - end - - def cmd_reload_lib_help - print_line 'Usage: reload_lib lib/to/reload.rb [...]' - print_line - print_line 'Reload one or more library files from specified paths.' - print_line - end - - # - # Reload one or more library files from specified paths - # - def cmd_reload_lib(*args) - if args.empty? || args.include?('-h') || args.include?('--help') - cmd_reload_lib_help - return - end - - args.each { |path| reload_file(path) } - end - - # - # Tab completion for the reload_lib command - # - def cmd_reload_lib_tabs(str, words) - tab_complete_filenames(str, words) - end - - def cmd_log_help - print_line 'Usage: log' - print_line - print_line 'Displays framework.log starting at the bottom if possible.' - print_line "For full effect, 'setg LogLevel 3' before running modules." - print_line - print_line "Log location: #{File.join(Msf::Config.log_directory, 'framework.log')}" - print_line - end - - # - # Displays framework.log starting at the bottom if possible - # - def cmd_log(*args) - path = File.join(Msf::Config.log_directory, 'framework.log') - - # XXX: +G isn't portable and may hang on large files - pager = local_pager.to_s.include?('less') ? "#{local_pager} +G" : local_pager - - unless pager - pager = 'tail -n 24' - print_warning("LocalPager or $PAGER/$MANPAGER should be set. Falling back on #{pager}.") - end - - # XXX: No vprint_status in this context? - # XXX: VERBOSE is a string instead of Bool?? - print_status("Launching #{pager} #{path}") if framework.datastore['VERBOSE'].to_s == 'true' - - unless system(*pager.split, path) - print_error("Could not execute #{pager} #{path}") - end - end - def cmd_advanced_help print_line 'Usage: advanced [mod1 mod2 ...]' print_line diff --git a/lib/msf/ui/console/driver.rb b/lib/msf/ui/console/driver.rb index 46c5caad95..32e956717a 100644 --- a/lib/msf/ui/console/driver.rb +++ b/lib/msf/ui/console/driver.rb @@ -32,7 +32,8 @@ class Driver < Msf::Ui::Driver CommandDispatchers = [ CommandDispatcher::Modules, CommandDispatcher::Jobs, - CommandDispatcher::Resource + CommandDispatcher::Resource, + CommandDispatcher::Developer ] #