Initial commit of the fzuse plugin

This commit is contained in:
Spencer McIntyre
2024-08-05 10:50:18 -04:00
parent 52fb857b99
commit 32d242c5d2
2 changed files with 229 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
module Msf
###
#
# This class illustrates a fuzzy_use plugin. Plugins can change the behavior of
# the framework by adding new features, new user interface commands, or
# through any other arbitrary means. They are designed to have a very loose
# definition in order to make them as useful as possible.
#
###
class Plugin::FuzzyUse < Msf::Plugin
###
#
# This class implements a fuzzy_use console command dispatcher.
#
###
class ConsoleCommandDispatcher
include Msf::Ui::Console::CommandDispatcher
def initialize(driver)
super
@module_dispatcher = Msf::Ui::Console::CommandDispatcher::Modules.new(driver)
end
#
# The dispatcher's name.
#
def name
'FuzzyUse'
end
#
# Returns the hash of commands supported by this dispatcher.
#
def commands
{
'fzuse' => 'A fuzzy_use command added by the fuzzy_use plugin'
}
end
#
# This method handles the fuzzy_use command.
#
def cmd_fzuse(*args)
unless Msf::Util::Helper.which('fzf')
print_error('This command requires that the `fzf` utility be installed.')
return
end
previewer = File.join(Msf::Config.install_root, 'tools', 'modules', 'print.py')
module_types = framework.modules.module_types
query = args.empty? ? '' : args.first
selection = nil
# alternative preview:
# jq \'to_entries[] | select(.value.fullname == "{1}") | .value\' db/modules_metadata_base.json | bat --language=json --color=always
stdin, stdout, stderr, wait_thr = Open3.popen3('fzf', '--select-1', '--query', query, '--preview', "#{previewer} {1}", '--preview-label', "Module Information") do |stdin, stdout, stderr, wait_thr|
module_types
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
exit_status = wait_thr.value
selection = stdout.read
end
selection.strip!
return if selection.blank?
@module_dispatcher.cmd_use(selection)
end
end
#
# The constructor is called when an instance of the plugin is created. The
# framework instance that the plugin is being associated with is passed in
# the framework parameter. Plugins should call the parent constructor when
# inheriting from Msf::Plugin to ensure that the framework attribute on
# their instance gets set.
#
def initialize(framework, opts)
super
# If this plugin is being loaded in the context of a console application
# that uses the framework's console user interface driver, register
# console dispatcher commands.
add_console_dispatcher(ConsoleCommandDispatcher)
print_status('FuzzyUse plugin loaded.')
end
#
# The cleanup routine for plugins gives them a chance to undo any actions
# they may have done to the framework. For instance, if a console
# dispatcher was added, then it should be removed in the cleanup routine.
#
def cleanup
# If we had previously registered a console dispatcher with the console,
# deregister it now.
remove_console_dispatcher('FuzzyUse')
end
#
# This method returns a short, friendly name for the plugin.
#
def name
'fuzzy_use'
end
#
# This method returns a brief description of the plugin. It should be no
# more than 60 characters, but there are no hard limits.
#
def desc
'Demonstrates using framework plugins'
end
end
end
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env python
import argparse
import json
import pathlib
from rich import box
from rich.console import Console
from rich.panel import Panel
from rich.syntax import Syntax
from rich.table import Table
from rich.tree import Tree
__version__ = '1.0'
RANKS = {
600: 'Excellent',
500: 'Great',
400: 'Good',
300: 'Normal',
200: 'Average',
100: 'Low',
0: 'Manual'
}
framework_root = pathlib.Path(__file__).parent.parent.parent
def get_notes(module_metadata):
tree = Tree('Notes', hide_root=True)
for key, values in module_metadata.get('notes', {}).items():
node = tree.add(key)
for value in values:
node.add(value)
return tree
def get_description(module_metadata):
description = ''
paragraphs = module_metadata['description'].split('\n\n')
for paragraph in paragraphs:
for line in paragraph.split('\n'):
description += line.strip() + '\n'
description += '\n'
return description.strip()
def get_authors(module_metadata):
return get_bulleted_list(module_metadata['author'])
def get_targets(module_metadata):
return get_bulleted_list(module_metadata['targets'])
def get_references(module_metadata):
references = []
for reference in module_metadata.get('references', []):
if reference.startswith('URL-'):
reference = reference[4:]
references.append(reference)
return get_bulleted_list(references)
def get_bulleted_list(items):
formatted = ''
for item in items:
formatted += f"[bold]•[/bold] {item}\n"
return formatted.strip()
def main():
parser = argparse.ArgumentParser(description='fzuse helper', conflict_handler='resolve')
parser.add_argument('module_name', help='module name to display')
parser.add_argument('-v', '--version', action='version', version='%(prog)s Version: ' + __version__)
arguments = parser.parse_args()
with (framework_root / 'db' / 'modules_metadata_base.json').open('r') as file_h:
all_metadata = json.load(file_h)
module_metadata = next((metadata for metadata in all_metadata.values() if metadata['fullname'] == arguments.module_name), None)
if not module_metadata:
return
table = Table(show_header=False, box=box.MINIMAL)
table.add_column(justify='right')
table.add_column()
table.add_row('[bold]Name[/bold]', module_metadata['name'])
table.add_row('[bold]Module[/bold]', module_metadata['fullname'])
table.add_row('[bold]Platform[/bold]', module_metadata['platform'])
table.add_row('[bold]Arch[/bold]', module_metadata['arch'])
table.add_row('[bold]Rank[/bold]', RANKS[module_metadata['rank']])
table.add_row('[bold]Disclosed[/bold]', module_metadata['disclosure_date'])
console = Console()
console.print(table)
panel_title = lambda v: f"[bold]{v}[/bold]"
console.print(Panel(get_authors(module_metadata), title=panel_title('Provided by'), title_align='left'))
console.print(Panel(get_notes(module_metadata), title=panel_title('Notes'), title_align='left'))
if module_metadata.get('targets'):
console.print(Panel(get_targets(module_metadata), title=panel_title('Targets'), title_align='left'))
console.print(Panel(get_description(module_metadata), title=panel_title('Description'), title_align='left'))
if module_metadata.get('references'):
console.print(Panel(get_references(module_metadata), title=panel_title('References'), title_align='left'))
if module_metadata.get('path', ''):
syntax = Syntax.from_path(framework_root / module_metadata['path'][1:], background_color='default', line_numbers=True)
console.print(Panel(syntax, title=panel_title('Source code'), title_align='left'))
if __name__ == '__main__':
main()