Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add favorite module feature and show favorites command for msfconsole #14201

Merged
merged 8 commits into from
Mar 8, 2021
14 changes: 14 additions & 0 deletions lib/msf/base/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@ def self.history_file
self.new.history_file
end

# Returns the full path to the fav_modules file.
#
# @return [String] path the fav_modules file.
def self.fav_modules_file
self.new.fav_modules_file
end

# Returns the full path to the handler file.
#
# @return [String] path the handler file.
Expand Down Expand Up @@ -293,6 +300,13 @@ def history_file
config_directory + FileSep + "history"
end

# Returns the full path to the fav_modules file.
#
# @return [String] path the fav_modules file.
def fav_modules_file
config_directory + FileSep + "fav_modules"
end

# Returns the full path to the handler file.
#
# @return [String] path the handler file.
Expand Down
131 changes: 129 additions & 2 deletions lib/msf/ui/console/command_dispatcher/modules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def commands
"search" => "Searches module names and descriptions",
"show" => "Displays modules of a given type, or all modules",
"use" => "Interact with a module by name or search term/index",
"favorite" => "Add current modules to the list of favorite modules",
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
}
end

Expand All @@ -58,6 +59,7 @@ def initialize(driver)
@previous_module = nil
@module_name_stack = []
@module_search_results = []
@module_show_results = []
@@payload_show_results = []
@dangerzone_map = nil
end
Expand Down Expand Up @@ -501,7 +503,7 @@ def cmd_search_tabs(str, words)
end

def cmd_show_help
global_opts = %w{all encoders nops exploits payloads auxiliary post plugins info options}
global_opts = %w{all encoders nops exploits payloads auxiliary post plugins info options favorites}
print_status("Valid parameters for the \"show\" command are: #{global_opts.join(", ")}")

module_opts = %w{ missing advanced evasion targets actions }
Expand Down Expand Up @@ -545,6 +547,8 @@ def cmd_show(*args)
show_auxiliary
when 'post'
show_post
when 'favorites'
show_favorites
when 'info'
cmd_info(*args[1, args.length])
when 'options'
Expand Down Expand Up @@ -611,7 +615,7 @@ def cmd_show(*args)
def cmd_show_tabs(str, words)
return [] if words.length > 1

res = %w{all encoders nops exploits payloads auxiliary post plugins options}
res = %w{all encoders nops exploits payloads auxiliary post plugins options favorites}
if (active_module)
res.concat %w{missing advanced evasion targets actions info}
if (active_module.respond_to? :compatible_sessions)
Expand Down Expand Up @@ -971,6 +975,107 @@ def cmd_back(*args)
driver.destack_dispatcher
end
end

def cmd_favorite_help
print_line 'Usage: favorite [mod1 mod2 ...]'
print_line
print_line 'Add one or multiple modules to the list of favorite modules stored in the fav_modules file'
print_line 'If no module name is specified, the command will add the active module if there is one'
print_line
print_line 'OPTIONS:'
print_line ' -d Delete the provided module(s) or the active module from the fav_modules file'
print_line ' -D Delete the fav_modules file'
end
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved

#
# Helper method for cmd_favorite that writes modules to the fav_modules_file
#
def cmd_favorite_process(mod, del)
favs_file = Msf::Config.fav_modules_file
if File.exists?(favs_file)
unless File.readable?(favs_file)
print_error("Unable to read #{favs_file}")
return false
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
end

contents = File.read(favs_file)
if contents.include?(mod.fullname)
unless del
print_warning("Module #{mod.fullname} has already been favorited and will not be added to #{favs_file}")
return
end

# remove module from contents (deletion happens below)
contents = contents.split("\n")
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
contents.delete(mod.fullname)

else
return if del #do nothing if fav_modules does not contain the module we need to delete
end
else
return if del
end

# finally, start adding/deleting stuff
begin
if del
write_mode = 'w'
contents = contents.join("\n")
message = "Removed #{mod.fullname} from #{favs_file}"
else
write_mode = 'a+'
contents = mod.fullname
message = "Added #{mod.fullname} to #{favs_file}"
end
File.open(favs_file, write_mode) do |file|
file.puts(contents)
end
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
rescue Errno::EACCES => e
print_error("Unable to write to #{favs_file}")
return false
end
print_status("#{message}")
return true
end

#
# Add modules to the fav_modules file
#
def cmd_favorite(*args)
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
favs_file = Msf::Config.fav_modules_file
del = false

if args.include?('-D')
args.delete('-D')
print_status("Removing #{favs_file} if it exists")
File.delete(favs_file) if File.exist?(favs_file)
return
end

if args.include?('-d')
args.delete('-d')
del = true
end

if args.empty?
if (active_module)
cmd_favorite_process(active_module, del)
else
print_error('No module active')
return false
end
end

args.each { |name|
mod = framework.modules.create(name)

if (mod == nil)
print_error("Invalid module: #{name}")
else
cmd_favorite_process(mod, del)
end
}
ErikWynter marked this conversation as resolved.
Show resolved Hide resolved
end

#
# Tab complete module names
Expand Down Expand Up @@ -1106,6 +1211,28 @@ def show_post(regex = nil, minrank = nil, opts = nil) # :nodoc:
show_module_set("Post", framework.post, regex, minrank, opts)
end

def show_favorites(regex = nil, minrank = nil, opts = nil) # :nodoc:
favs_file = Msf::Config.fav_modules_file
unless File.exists?(favs_file) && !File.zero?(favs_file)
print_error("#{favs_file} does not exist or is empty")
return
end

unless File.readable?(favs_file)
print_error("Unable to read from #{favs_file}")
return
end

# create module set using the saved modules
fav_modules = {}
saved_favs = File.readlines(favs_file)
saved_favs.each do |mod|
module_name = mod.strip
fav_modules[module_name] = framework.modules[module_name]
end
show_module_set("Favorites", fav_modules, regex, minrank, opts)
end

def show_missing(mod) # :nodoc:
mod_opt = Serializer::ReadableText.dump_options(mod, ' ', true)
print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0)
Expand Down