Skip to content

Commit 32d242c

Browse files
committed
Initial commit of the fzuse plugin
1 parent 52fb857 commit 32d242c

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

plugins/fzuse.rb

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
module Msf
2+
###
3+
#
4+
# This class illustrates a fuzzy_use plugin. Plugins can change the behavior of
5+
# the framework by adding new features, new user interface commands, or
6+
# through any other arbitrary means. They are designed to have a very loose
7+
# definition in order to make them as useful as possible.
8+
#
9+
###
10+
class Plugin::FuzzyUse < Msf::Plugin
11+
12+
###
13+
#
14+
# This class implements a fuzzy_use console command dispatcher.
15+
#
16+
###
17+
class ConsoleCommandDispatcher
18+
include Msf::Ui::Console::CommandDispatcher
19+
20+
def initialize(driver)
21+
super
22+
23+
@module_dispatcher = Msf::Ui::Console::CommandDispatcher::Modules.new(driver)
24+
end
25+
26+
#
27+
# The dispatcher's name.
28+
#
29+
def name
30+
'FuzzyUse'
31+
end
32+
33+
#
34+
# Returns the hash of commands supported by this dispatcher.
35+
#
36+
def commands
37+
{
38+
'fzuse' => 'A fuzzy_use command added by the fuzzy_use plugin'
39+
}
40+
end
41+
42+
#
43+
# This method handles the fuzzy_use command.
44+
#
45+
def cmd_fzuse(*args)
46+
unless Msf::Util::Helper.which('fzf')
47+
print_error('This command requires that the `fzf` utility be installed.')
48+
return
49+
end
50+
51+
previewer = File.join(Msf::Config.install_root, 'tools', 'modules', 'print.py')
52+
53+
module_types = framework.modules.module_types
54+
55+
query = args.empty? ? '' : args.first
56+
57+
selection = nil
58+
# alternative preview:
59+
# jq \'to_entries[] | select(.value.fullname == "{1}") | .value\' db/modules_metadata_base.json | bat --language=json --color=always
60+
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|
61+
module_types
62+
module_types.each do |module_type|
63+
framework.modules.module_names(module_type).each do |module_name|
64+
stdin.puts "#{module_type}/#{module_name}"
65+
end
66+
end
67+
stdin.close
68+
69+
exit_status = wait_thr.value
70+
71+
selection = stdout.read
72+
end
73+
74+
selection.strip!
75+
return if selection.blank?
76+
77+
@module_dispatcher.cmd_use(selection)
78+
end
79+
end
80+
81+
#
82+
# The constructor is called when an instance of the plugin is created. The
83+
# framework instance that the plugin is being associated with is passed in
84+
# the framework parameter. Plugins should call the parent constructor when
85+
# inheriting from Msf::Plugin to ensure that the framework attribute on
86+
# their instance gets set.
87+
#
88+
def initialize(framework, opts)
89+
super
90+
91+
# If this plugin is being loaded in the context of a console application
92+
# that uses the framework's console user interface driver, register
93+
# console dispatcher commands.
94+
add_console_dispatcher(ConsoleCommandDispatcher)
95+
96+
print_status('FuzzyUse plugin loaded.')
97+
end
98+
99+
#
100+
# The cleanup routine for plugins gives them a chance to undo any actions
101+
# they may have done to the framework. For instance, if a console
102+
# dispatcher was added, then it should be removed in the cleanup routine.
103+
#
104+
def cleanup
105+
# If we had previously registered a console dispatcher with the console,
106+
# deregister it now.
107+
remove_console_dispatcher('FuzzyUse')
108+
end
109+
110+
#
111+
# This method returns a short, friendly name for the plugin.
112+
#
113+
def name
114+
'fuzzy_use'
115+
end
116+
117+
#
118+
# This method returns a brief description of the plugin. It should be no
119+
# more than 60 characters, but there are no hard limits.
120+
#
121+
def desc
122+
'Demonstrates using framework plugins'
123+
end
124+
125+
end
126+
end

tools/modules/print.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env python
2+
import argparse
3+
import json
4+
import pathlib
5+
6+
from rich import box
7+
from rich.console import Console
8+
from rich.panel import Panel
9+
from rich.syntax import Syntax
10+
from rich.table import Table
11+
from rich.tree import Tree
12+
13+
__version__ = '1.0'
14+
15+
RANKS = {
16+
600: 'Excellent',
17+
500: 'Great',
18+
400: 'Good',
19+
300: 'Normal',
20+
200: 'Average',
21+
100: 'Low',
22+
0: 'Manual'
23+
}
24+
25+
framework_root = pathlib.Path(__file__).parent.parent.parent
26+
27+
def get_notes(module_metadata):
28+
tree = Tree('Notes', hide_root=True)
29+
for key, values in module_metadata.get('notes', {}).items():
30+
node = tree.add(key)
31+
for value in values:
32+
node.add(value)
33+
return tree
34+
35+
def get_description(module_metadata):
36+
description = ''
37+
paragraphs = module_metadata['description'].split('\n\n')
38+
for paragraph in paragraphs:
39+
for line in paragraph.split('\n'):
40+
description += line.strip() + '\n'
41+
description += '\n'
42+
return description.strip()
43+
44+
def get_authors(module_metadata):
45+
return get_bulleted_list(module_metadata['author'])
46+
47+
def get_targets(module_metadata):
48+
return get_bulleted_list(module_metadata['targets'])
49+
50+
def get_references(module_metadata):
51+
references = []
52+
for reference in module_metadata.get('references', []):
53+
if reference.startswith('URL-'):
54+
reference = reference[4:]
55+
references.append(reference)
56+
return get_bulleted_list(references)
57+
58+
def get_bulleted_list(items):
59+
formatted = ''
60+
for item in items:
61+
formatted += f"[bold]•[/bold] {item}\n"
62+
return formatted.strip()
63+
64+
def main():
65+
parser = argparse.ArgumentParser(description='fzuse helper', conflict_handler='resolve')
66+
parser.add_argument('module_name', help='module name to display')
67+
parser.add_argument('-v', '--version', action='version', version='%(prog)s Version: ' + __version__)
68+
arguments = parser.parse_args()
69+
70+
with (framework_root / 'db' / 'modules_metadata_base.json').open('r') as file_h:
71+
all_metadata = json.load(file_h)
72+
module_metadata = next((metadata for metadata in all_metadata.values() if metadata['fullname'] == arguments.module_name), None)
73+
if not module_metadata:
74+
return
75+
76+
table = Table(show_header=False, box=box.MINIMAL)
77+
table.add_column(justify='right')
78+
table.add_column()
79+
80+
table.add_row('[bold]Name[/bold]', module_metadata['name'])
81+
table.add_row('[bold]Module[/bold]', module_metadata['fullname'])
82+
table.add_row('[bold]Platform[/bold]', module_metadata['platform'])
83+
table.add_row('[bold]Arch[/bold]', module_metadata['arch'])
84+
table.add_row('[bold]Rank[/bold]', RANKS[module_metadata['rank']])
85+
table.add_row('[bold]Disclosed[/bold]', module_metadata['disclosure_date'])
86+
87+
console = Console()
88+
console.print(table)
89+
90+
panel_title = lambda v: f"[bold]{v}[/bold]"
91+
console.print(Panel(get_authors(module_metadata), title=panel_title('Provided by'), title_align='left'))
92+
console.print(Panel(get_notes(module_metadata), title=panel_title('Notes'), title_align='left'))
93+
if module_metadata.get('targets'):
94+
console.print(Panel(get_targets(module_metadata), title=panel_title('Targets'), title_align='left'))
95+
console.print(Panel(get_description(module_metadata), title=panel_title('Description'), title_align='left'))
96+
if module_metadata.get('references'):
97+
console.print(Panel(get_references(module_metadata), title=panel_title('References'), title_align='left'))
98+
if module_metadata.get('path', ''):
99+
syntax = Syntax.from_path(framework_root / module_metadata['path'][1:], background_color='default', line_numbers=True)
100+
console.print(Panel(syntax, title=panel_title('Source code'), title_align='left'))
101+
102+
if __name__ == '__main__':
103+
main()

0 commit comments

Comments
 (0)