diff --git a/docs/metasploit-framework.wiki/How-To-Use-Plugins.md b/docs/metasploit-framework.wiki/How-To-Use-Plugins.md index 72b16c1b66c8..7b3e6baa201d 100644 --- a/docs/metasploit-framework.wiki/How-To-Use-Plugins.md +++ b/docs/metasploit-framework.wiki/How-To-Use-Plugins.md @@ -18,7 +18,7 @@ plugin_name_command --option The current available plugins for Metasploit can be found by running the `load -l` command, or viewing Metasploit's [plugins](https://github.com/rapid7/metasploit-framework/tree/master/plugins) directory: -| name | Description | +| Name | Description | |------------------|-----------------------------------------------------------------------------------------------------| | aggregator | Interacts with the external Session Aggregator | | alias | Adds the ability to alias console commands | @@ -30,6 +30,7 @@ The current available plugins for Metasploit can be found by running the `load - | db_tracker | Monitors socket calls and updates the database backend | | event_tester | Internal test tool used to verify the internal framework event subscriber logic works | | ffautoregen | This plugin reloads and re-executes a file-format exploit module once it has changed | +| fzuse | A plugin offering a fuzzy use command | | ips_filter | Scans all outgoing data to see if it matches a known IPS signature | | lab | Adds the ability to manage VMs | | libnotify | Send desktop notification with libnotify on sessions and db events | @@ -42,12 +43,12 @@ The current available plugins for Metasploit can be found by running the `load - | request | Make requests from within Metasploit using various protocols. | | rssfeed | Create an RSS feed of events | | sample | Demonstrates using framework plugins | -| session_notifier | This plugin notifies you of a new session via SMS | +| session_notifier | This plugin notifies you of a new session via SMS | | session_tagger | Automatically interacts with new sessions to create a new remote TaggedByUser file | | socket_logger | Log socket operations to a directory as individual files | | sounds | Automatically plays a sound when various framework events occur | | sqlmap | sqlmap plugin for Metasploit | -| thread | Internal test tool for testing thread usage in Metasploit | +| thread | Internal test tool for testing thread usage in Metasploit | | token_adduser | Attempt to add an account using all connected Meterpreter session tokens | | token_hunter | Search all active Meterpreter sessions for specific tokens | | wiki | Outputs stored database values from the current workspace into DokuWiki or MediaWiki format | diff --git a/plugins/fzuse.rb b/plugins/fzuse.rb new file mode 100644 index 000000000000..b56b62b488cb --- /dev/null +++ b/plugins/fzuse.rb @@ -0,0 +1,150 @@ +require 'socket' + +# this is the main routine that's executed in the grandchild process (msfconsole -> fzf -> this) +if $PROGRAM_NAME == __FILE__ + exit 64 unless ARGV.length == 2 + + UNIXSocket.open(ARGV[0]) do |sock| + sock.write ARGV[1] + "\n" + sock.flush + + puts sock.read + end + exit 0 +end + +module Msf + class Plugin::FuzzyUse < Msf::Plugin + class ConsoleCommandDispatcher + include Msf::Ui::Console::CommandDispatcher + + FZF_THEME = { + 'fg' => '-1', + 'fg+' => 'white:regular:bold', + 'bg' => '-1', + 'bg+' => '-1', + 'hl' => '-1', + 'hl+' => 'red:regular:bold', + 'info' => '-1', + 'marker' => '-1', + 'prompt' => '-1', + 'spinner' => '-1', + 'pointer' => 'blue:bold', + 'header' => '-1', + 'border' => '-1', + 'label' => '-1', + 'query' => '-1' + }.freeze + + def initialize(driver) + super + + @module_dispatcher = Msf::Ui::Console::CommandDispatcher::Modules.new(driver) + end + + def name + 'FuzzyUse' + end + + # + # Returns the hash of commands supported by this dispatcher. + # + def commands + { + 'fzuse' => 'A fuzzy use command added by the FuzzyUse plugin' + } + end + + def pipe_server(socket_path) + server = UNIXServer.new(socket_path) + File.chmod(0600, socket_path) + loop do + client = server.accept + begin + unless (input_string = client.gets&.chomp).blank? + if (mod = framework.modules.create(input_string)) + client.puts(Serializer::ReadableText.dump_module(mod)) + end + end + rescue StandardError + end + client.close + end + rescue EOFError + ensure + server.close if server + File.delete(socket_path) if File.exist?(socket_path) + end + + # + # This method handles the fzuse command. + # + def cmd_fzuse(*args) + selection = nil + + Dir.mktmpdir('msf-fzuse-') do |dir| + socket_path = File.join(dir, "msf-fzuse.sock") + server_thread = Thread.new { pipe_server(socket_path) } + + query = args.empty? ? '' : args.first + ruby = RbConfig::CONFIG['bindir'] + '/' + RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT'] + + color = "--color=#{FZF_THEME.map { |key, value| "#{key}:#{value}" }.join(',')}" + Open3.popen3('fzf', '--select-1', '--query', query, '--pointer=->', color, '--preview', "'#{ruby}' '#{__FILE__}' '#{socket_path}' '{1}'", '--preview-label', "Module Information") do |stdin, stdout, stderr, wait_thr| + framework.modules.module_types.each do |module_type| + framework.modules.module_names(module_type).each do |module_name| + stdin.puts "#{module_type}/#{module_name}" + end + end + stdin.close + selection = stdout.read + end + + server_thread.kill + server_thread.join + end + + return if selection.blank? + + selection.strip! + @module_dispatcher.cmd_use(selection) + end + end + + def initialize(framework, opts) + super + + unless defined?(UNIXSocket) + # This isn't a requirement that can be fixed by installing something + print_error("The FuzzyUse plugin has loaded but the Ruby environment does not support UNIX sockets.") + return + end + + missing_requirements = [] + missing_requirements << 'fzf' unless Msf::Util::Helper.which('fzf') + + unless missing_requirements.empty? + print_error("The FuzzyUse plugin has loaded but the following requirements are missing: #{missing_requirements.join(', ')}") + print_error("Please install the missing requirements, then reload the plugin by running: `unload fzuse` and `load fzuse`.") + return + end + + add_console_dispatcher(ConsoleCommandDispatcher) + + print_status('FuzzyUse plugin loaded.') + end + + def cleanup + remove_console_dispatcher('FuzzyUse') + end + + def name + 'fuzzy_use' + end + + def desc + 'A plugin offering a fuzzy use command' + end + + end +end