diff --git a/lib/msf/ui/console/command_dispatcher.rb b/lib/msf/ui/console/command_dispatcher.rb index 2544d0574b..caaac247b9 100644 --- a/lib/msf/ui/console/command_dispatcher.rb +++ b/lib/msf/ui/console/command_dispatcher.rb @@ -94,6 +94,10 @@ module ModuleCommandDispatcher include Msf::Ui::Console::CommandDispatcher + def commands + { "reload" => "Reload the current module from disk" } + end + # # The active driver module, if any. # @@ -108,6 +112,49 @@ module ModuleCommandDispatcher self.driver.active_module = m end + # + # Reloads the active module + # + def cmd_reload(*args) + begin + reload + rescue + log_error("Failed to reload: #{$!}") + end + end + + def cmd_reload_help + print_line "Usage: reload [-k]" + print_line + print_line "Reloads the current module." + print @@reload_opts.usage + end + + # + # Reload the current module, optionally stopping existing job + # + def reload(should_stop_job=false) + if should_stop_job and mod.job_id + print_status('Stopping existing job...') + + framework.jobs.stop_job(mod.job_id) + mod.job_id = nil + end + + print_status('Reloading module...') + + omod = self.mod + self.mod = framework.modules.reload_module(mod) + + if(not self.mod) + print_status("Failed to reload module: #{framework.modules.failed[omod.file_path]}") + self.mod = omod + return + end + + self.mod.init_ui(driver.input, driver.output) + end + end end end end diff --git a/lib/msf/ui/console/command_dispatcher/auxiliary.rb b/lib/msf/ui/console/command_dispatcher/auxiliary.rb index 186059f2a5..8eab29602d 100644 --- a/lib/msf/ui/console/command_dispatcher/auxiliary.rb +++ b/lib/msf/ui/console/command_dispatcher/auxiliary.rb @@ -25,13 +25,13 @@ class Auxiliary # Returns the hash of commands specific to auxiliary modules. # def commands - { + super.update({ "run" => "Launches the auxiliary module", "rerun" => "Reloads and launches the auxiliary module", "exploit" => "This is an alias for the run command", "rexploit" => "This is an alias for the rerun command", "reload" => "Reloads the auxiliary module" - }.merge( (mod ? mod.auxiliary_commands : {}) ) + }).merge( (mod ? mod.auxiliary_commands : {}) ) end # @@ -56,58 +56,16 @@ class Auxiliary "Auxiliary" end - # - # This is an alias for 'rerun' - # - def cmd_rexploit(*args) - cmd_rerun(*args) - end - - # - # Reloads an auxiliary module - # - def cmd_reload(*args) - begin - omod = self.mod - self.mod = framework.modules.reload_module(mod) - if(not self.mod) - print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}") - self.mod = omod - end - rescue - log_error("Failed to reload: #{$!}") - end - end - # # Reloads an auxiliary module and executes it # def cmd_rerun(*args) - if mod.job_id - print_status("Stopping existing job...") - - framework.jobs.stop_job(mod.job_id) - mod.job_id = nil - end - - omod = self.mod - self.mod = framework.modules.reload_module(mod) - - if(not self.mod) - print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}") - self.mod = omod - return - end + reload(true) cmd_run(*args) end - # - # This is an alias for 'run' - # - def cmd_exploit(*args) - cmd_run(*args) - end + alias cmd_rexploit cmd_rerun # # Executes an auxiliary module @@ -131,10 +89,7 @@ class Auxiliary when '-q' quiet = true when '-h' - print( - "Usage: run [options]\n\n" + - "Launches an auxiliary module.\n" + - @@auxiliary_opts.usage) + cmd_run_help return false end } @@ -177,6 +132,17 @@ class Auxiliary end end + alias cmd_exploit cmd_run + + def cmd_run_help + print_line "Usage: run [options]" + print_line + print_line "Launches an auxiliary module." + print @@auxiliary_opts.usage + end + + alias cmd_exploit_help cmd_run_help + end end end end end diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 7db37b0316..b090e67ba2 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -284,9 +284,7 @@ class Core # def cmd_connect(*args) if args.length < 2 or args.include?("-h") - print( "Usage: connect [options] \n\n" + - "Communicate with a host, similar to interacting via netcat.\n" + - @@connect_opts.usage) + cmd_connect_help return false end @@ -460,6 +458,14 @@ class Core true end + def cmd_connect_help + print_line "Usage: connect [options] " + print_line + print_line "Communicate with a host, similar to interacting via netcat, taking advantage of" + print_line "any configured session pivoting." + print @@connect_opts.usage + end + # # Instructs the driver to stop executing. # @@ -485,44 +491,6 @@ class Core Rex::ThreadSafe.sleep(args[0].to_f) end - # - # Displays the command help banner or an individual command's help banner - # if we can figure out how to invoke it. - # - def cmd_help(*args) - if args and args.length > 0 and commands.include?(args[0]) - if self.respond_to? "cmd_"+ args[0] + "_help" - self.send("cmd_"+ args[0] + "_help") - else - # - # This part is done in a hackish way because not all of the - # usage info is available from self.commands() or @@*_opts, so - # we check @@_opts for "-h". It's non-optimal because - # several commands have usage info, but don't use -h to invoke - # it. - begin - opts = eval("@@" + args[0] + "_opts") - rescue - end - if opts and opts.include?("-h") - self.send("cmd_" + args[0], "-h") - else - print_line("No help available for #{args[0]}") - end - end - else - print(driver.help_to_s) - end - end - def cmd_help_tabs(str, words) - return [] if words.length > 1 - - return commands.keys - end - - - alias cmd_? cmd_help - # # Displays information about one or more module. # @@ -620,10 +588,7 @@ class Core dump_info = true job_id = val when "-h" - print( - "Usage: jobs [options]\n\n" + - "Active job manipulation and interaction.\n" + - @@jobs_opts.usage()) + cmd_jobs_help return false end } @@ -670,6 +635,13 @@ class Core [] end + def cmd_jobs_help + print_line "Usage: jobs [options]" + print_line + print_line "Active job manipulation and interaction." + print @@jobs_opts.usage() + end + def cmd_kill(*args) cmd_jobs("-k", *args) end @@ -679,6 +651,13 @@ class Core framework.jobs.keys end + def cmd_kill_help + print_line "Usage: kill [job2 ...]" + print_line + print_line "Equivalent to 'jobs -k job1 -k job2 ...'" + print @@jobs_opts.usage() + end + # # Displays and manages running background threads # @@ -725,10 +704,7 @@ class Core dump_info = true thread_id = val.to_i when "-h" - print( - "Usage: threads [options]\n\n" + - "Background thread management.\n" + - @@threads_opts.usage()) + cmd_threads_help return false end } @@ -800,6 +776,13 @@ class Core [] end + def cmd_threads_help + print( + "Usage: threads [options]\n\n" + + "Background thread management.\n" + + @@threads_opts.usage()) + end + # Loads a plugin from the supplied path. If no absolute path is supplied, # the framework root plugin directory is used. # @@ -1132,8 +1115,8 @@ class Core def cmd_loadpath(*args) defanged? - if (args.length == 0) - print_error("No search paths were provided.") + if (args.length == 0 or args.include? "-h") + cmd_loadpath_help return true end @@ -1205,6 +1188,13 @@ class Core return paths end + def cmd_loadpath_help + print_line "Usage: loadpath /path/to/modules" + print_line + print_line "Loads modules from the given directory which should contain subdirectories for" + print_line "module types, e.g. /path/to/modules/exploits" + end + # # Searches modules (name and description) for specified regex # @@ -1216,8 +1206,7 @@ class Core @@search_opts.parse(args) { |opt, idx, val| case opt when "-h" - print_line("Usage: search [options] [regex]") - print(@@search_opts.usage) + cmd_search_help return when "-t" section = val @@ -1284,12 +1273,18 @@ class Core when "-r" return RankingName.sort.map{|r| r[1]} when "-t" - return %w{auxiliary encoder exploit nop payload} + return %w{auxiliary encoder exploit nop payload post} end [] end + def cmd_search_help + print_line "Usage: search [options] [regex]" + print_line + print @@search_opts.usage + end + # # Provides an interface to the sessions currently active in the framework. # @@ -1359,10 +1354,7 @@ class Core # Display help banner when "-h" - print( - "Usage: sessions [options]\n\n" + - "Active session manipulation and interaction.\n" + - @@sessions_opts.usage()) + cmd_sessions_help return false else extra << val @@ -1568,6 +1560,13 @@ class Core [] end + def cmd_sessions_help + print_line "Usage: sessions [options]" + print_line + print_line "Active session manipulation and interaction." + print(@@sessions_opts.usage()) + end + # # Sets a name to a value in a context aware environment. # @@ -1736,21 +1735,7 @@ class Core args.each { |type| case type when '-h' - global_opts = %w{all encoders nops exploits payloads auxiliary plugins options} - opts = '' - global_opts.each { |el| - opts << ', ' if opts.length > 0 - opts << el - } - print_status("Valid parameters for the \"show\" command are: #{opts}") - module_opts = %w{ advanced evasion targets actions } - opts = '' - module_opts.each { |el| - opts << ', ' if opts.length > 0 - opts << el - } - print_status("Additional module-specific parameters are: #{opts}") - + cmd_show_help when 'all' show_encoders show_nops @@ -1835,6 +1820,14 @@ class Core return res end + def cmd_show_help + global_opts = %w{all encoders nops exploits payloads auxiliary plugins options} + print_status("Valid parameters for the \"show\" command are: #{global_opts.join(", ")}") + + module_opts = %w{ advanced evasion targets actions } + print_status("Additional module-specific parameters are: #{module_opts.join(", ")}") + end + # # Unloads a plugin by its name. # @@ -1891,11 +1884,7 @@ class Core # No arguments? No cookie. if (args.length == 0) - print( - "Usage: unset var1 var2 var3 ...\n\n" + - "The unset command is used to unset one or more variables.\n" + - "To flush all entires, specify 'all' as the variable name\n") - + cmd_unset_help return false end @@ -1934,6 +1923,14 @@ class Core datastore.keys end + def cmd_unset_help + print_line "Usage: unset [-g] var1 var2 var3 ..." + print_line + print_line "The unset command is used to unset one or more variables." + print_line "To flush all entires, specify 'all' as the variable name." + print_line "With -g, operates on global datastore variables." + end + # # Unsets variables in the global data store. # @@ -1950,6 +1947,8 @@ class Core self.framework.datastore.keys end + alias cmd_unsetg_help cmd_unset_help + # # Uses a module. # diff --git a/lib/msf/ui/console/command_dispatcher/exploit.rb b/lib/msf/ui/console/command_dispatcher/exploit.rb index 251eb790fe..7b51c092d6 100644 --- a/lib/msf/ui/console/command_dispatcher/exploit.rb +++ b/lib/msf/ui/console/command_dispatcher/exploit.rb @@ -31,13 +31,13 @@ class Exploit # 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" - } + }) end # @@ -124,10 +124,7 @@ class Exploit when '-z' bg = true when '-h' - print( - "Usage: exploit [options]\n\n" + - "Launches an exploitation attempt.\n" + - @@exploit_opts.usage) + cmd_exploit_help return false end } @@ -203,6 +200,13 @@ class Exploit end end + def cmd_exploit_help + print_line "Usage: exploit [options]" + print_line + print_line "Launches an exploitation attempt." + print @@exploit_opts.usage + end + # # Reloads an exploit module and checks the target to see if it's # vulnerable. @@ -210,68 +214,28 @@ class Exploit def cmd_rcheck(*args) reload() - self.mod.init_ui(driver.input, driver.output) cmd_check(*args) end - # - # Reload an exploit module, optionally stopping existing job - # - def reload(should_stop_job=false) - - if should_stop_job and mod.job_id - print_status('Stopping existing job...') - - framework.jobs.stop_job(mod.job_id) - mod.job_id = nil - end - - - print_status('Reloading module...') - - omod = self.mod - self.mod = framework.modules.reload_module(mod) - - if(not self.mod) - print_status("Failed to reload module: #{framework.modules.failed[omod.file_path]}") - self.mod = omod - return - end - - self.mod.init_ui(driver.input, driver.output) - end - - # - # Handles the command to reload an exploit module. - # - def cmd_reload(*args) - # By default, do not stop the existing job - stop_existing = false - - @@reload_opts.parse(args) { |opt, idx, val| - case opt - when '-k' - stop_existing = true - when '-h' - print_line "Usage: reload [-k]\n\nReloads the current module." - print_line @@reload_opts.usage - return - end - } - - reload(stop_existing) - 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 reload(true) # Delegate to the exploit command cmd_exploit(*args) end + 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 + # # Picks a reasonable payload and minimally configures it # diff --git a/lib/msf/ui/console/command_dispatcher/nop.rb b/lib/msf/ui/console/command_dispatcher/nop.rb index f5d583a129..aa54d1ae7e 100644 --- a/lib/msf/ui/console/command_dispatcher/nop.rb +++ b/lib/msf/ui/console/command_dispatcher/nop.rb @@ -24,9 +24,9 @@ class Nop # Returns the hash of supported commands. # def commands - { + super.update({ "generate" => "Generates a NOP sled", - } + }) end # @@ -91,4 +91,4 @@ class Nop end -end end end end \ No newline at end of file +end end end end diff --git a/lib/msf/ui/console/command_dispatcher/payload.rb b/lib/msf/ui/console/command_dispatcher/payload.rb index 3ad3ec0f90..2c519ff6ea 100644 --- a/lib/msf/ui/console/command_dispatcher/payload.rb +++ b/lib/msf/ui/console/command_dispatcher/payload.rb @@ -39,9 +39,9 @@ class Payload # Returns the hash of commands specific to payload modules. # def commands - { + super.update({ "generate" => "Generates a payload", - } + }) end # diff --git a/lib/msf/ui/console/command_dispatcher/post.rb b/lib/msf/ui/console/command_dispatcher/post.rb index 7f4dc70045..74b7dae113 100644 --- a/lib/msf/ui/console/command_dispatcher/post.rb +++ b/lib/msf/ui/console/command_dispatcher/post.rb @@ -24,20 +24,18 @@ class Post # Returns the hash of commands specific to post modules. # def commands - { + super.update({ "run" => "Launches the post exploitation module", "rerun" => "Reloads and launches the module", "exploit" => "This is an alias for the run command", "rexploit" => "This is an alias for the rerun command", - "reload" => "Reloads the post exploitation module" - }.merge( (mod ? mod.post_commands : {}) ) + }).merge( (mod ? mod.post_commands : {}) ) end # # Allow modules to define their own commands # def method_missing(meth, *args) - $stdout.puts("Post#method_missing") if (mod and mod.respond_to?(meth.to_s)) # Initialize user interaction @@ -63,22 +61,6 @@ class Post cmd_rerun(*args) end - # - # Reloads an auxiliary module - # - def cmd_reload(*args) - begin - omod = self.mod - self.mod = framework.modules.reload_module(mod) - if(not self.mod) - print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}") - self.mod = omod - end - rescue - log_error("Failed to reload: #{$!}") - end - end - # # Reloads an auxiliary module and executes it # @@ -102,12 +84,7 @@ class Post cmd_run(*args) end - # - # This is an alias for 'run' - # - def cmd_exploit(*args) - cmd_run(*args) - end + alias cmd_rexploit cmd_rerun # # Executes an auxiliary module @@ -175,6 +152,15 @@ class Post end end + def cmd_run_help + print_line "Usage: run [options]" + print_line + print_line "Launches a post module." + print @@auxiliary_opts.usage + end + + alias cmd_exploit_help cmd_run_help + end end end end end diff --git a/lib/rex/ui/text/dispatcher_shell.rb b/lib/rex/ui/text/dispatcher_shell.rb index 3bf0b6ec36..36e13264c7 100644 --- a/lib/rex/ui/text/dispatcher_shell.rb +++ b/lib/rex/ui/text/dispatcher_shell.rb @@ -1,4 +1,5 @@ require 'rex/ui' +require 'pp' module Rex module Ui @@ -79,6 +80,54 @@ module DispatcherShell shell.update_prompt(prompt) end + # + # Displays the help banner. With no arguments, this is just a list of + # all commands grouped by dispatcher. Otherwise, tries to use a method + # named cmd_#{+cmd+}_help for the first dispatcher that has a command + # named +cmd+. + # + def cmd_help(cmd=nil, *ignored) + if cmd + help_found = false + cmd_found = false + shell.dispatcher_stack.each do |dispatcher| + next unless dispatcher.respond_to?(:commands) + next if (dispatcher.commands.nil?) + next if (dispatcher.commands.length == 0) + + if dispatcher.respond_to?("cmd_#{cmd}") + cmd_found = true + break unless dispatcher.respond_to? "cmd_#{cmd}_help" + dispatcher.send("cmd_#{cmd}_help") + help_found = true + break + end + end + print_error("No help for #{cmd}, try -h") if cmd_found and not help_found + print_error("No such command") if not cmd_found + else + print(driver.help_to_s) + end + end + + # + # Tab completion for the help command + # + # By default just returns a list of all commands in all dispatchers. + # + def cmd_help_tabs(str, words) + return [] if words.length > 1 + + tabs = [] + shell.dispatcher_stack.each { |dispatcher| + tabs += dispatcher.commands.keys + } + return tabs + end + + alias cmd_? cmd_help + + # # No tab completion items by default #