151 lines
4.1 KiB
Ruby
151 lines
4.1 KiB
Ruby
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
|