From 3e41db69948dc51aaebd1443045fa49683946ce7 Mon Sep 17 00:00:00 2001 From: Erin Bleiweiss Date: Fri, 27 Jul 2018 16:00:19 -0500 Subject: [PATCH] refactor for more dry, more compartmentalized code --- lib/msf/core/modules/metadata/search.rb | 84 +++++++++---------- lib/msf/core/web_services/module_search.rb | 35 ++------ .../ui/console/command_dispatcher/modules.rb | 39 ++++++++- 3 files changed, 83 insertions(+), 75 deletions(-) diff --git a/lib/msf/core/modules/metadata/search.rb b/lib/msf/core/modules/metadata/search.rb index 26374ec6d1..c0ce350c06 100644 --- a/lib/msf/core/modules/metadata/search.rb +++ b/lib/msf/core/modules/metadata/search.rb @@ -4,67 +4,36 @@ require 'msf/core/modules/metadata' # Provides search operations on the module metadata cache. # module Msf::Modules::Metadata::Search - # - # Searches the module metadata using the passed search string. - # - def find(search_string) - search_results = [] - params = parse_search_string(search_string) + VALID_PARAMS = + %w[app author authors arch cve bid edb date disclosure_date description full_name fullname mod_time name + os platform path port rport rank ref ref_name reference references target targets text type] + + # + # Searches the module metadata using the passed hash of search params + # + def find(params, fields={}) + return [] if params.empty? || VALID_PARAMS.none? { |k| params.key?(k) } + search_results = [] get_metadata.each { |module_metadata| if is_match(params, module_metadata) + unless fields.empty? + module_metadata = get_fields(module_metadata, fields) + end search_results << module_metadata end } - return search_results end - # Helper method for private `is_match` - def matches(params, module_metadata) - is_match(params, module_metadata) - end ####### private ####### - def parse_search_string(search_string) - # Split search terms by space, but allow quoted strings - terms = search_string.split(/\"/).collect{|term| term.strip==term ? term : term.split(' ')}.flatten - terms.delete('') - - # All terms are either included or excluded - res = {} - - terms.each do |term| - keyword, search_term = term.split(":", 2) - unless search_term - search_term = keyword - keyword = 'text' - end - next if search_term.length == 0 - keyword.downcase! - search_term.downcase! - res[keyword] ||=[ [], [] ] - if search_term[0,1] == "-" - next if search_term.length == 1 - res[keyword][1] << search_term[1,search_term.length-1] - else - res[keyword][0] << search_term - end - end - res - end def is_match(params, module_metadata) - valid_params = - %w[app author authors arch cve bid edb date disclosure_date description full_name fullname mod_time name - os platform path port rport rank ref ref_name reference references target targets text type] - - return false if params.empty? || valid_params.none? { |k| params.key?(k) } - param_hash = params [0,1].each do |mode| @@ -174,5 +143,32 @@ module Msf::Modules::Metadata::Search true end + + def get_fields(module_metadata, fields) + selected_fields = {} + + aliases = { + :cve => 'references', + :edb => 'references', + :bid => 'references', + :fullname => 'full_name', + :os => 'platform', + :port => 'rport', + :reference => 'references', + :ref => 'ref_name', + :target => 'targets', + :authors => 'author' + } + + fields.each do | field | + field = aliases[field.to_sym] if aliases[field.to_sym] + if module_metadata.respond_to?(field) + selected_fields[field] = module_metadata.send(field) + end + end + selected_fields + + end + end diff --git a/lib/msf/core/web_services/module_search.rb b/lib/msf/core/web_services/module_search.rb index b3f66b3279..c450a96ba7 100644 --- a/lib/msf/core/web_services/module_search.rb +++ b/lib/msf/core/web_services/module_search.rb @@ -2,15 +2,9 @@ module Msf::WebServices::ModuleSearch def search_modules(opts) raise ::ArgumentError, "At least one search parameter must be provided." if opts.except(:fields).empty? - search_results = [] - metadata = Msf::Modules::Metadata::Cache.instance.get_metadata params = parse_params(opts) - metadata.each do | module_metadata | - if Msf::Modules::Metadata::Cache.instance.matches(params, module_metadata) - search_results << get_fields(opts, module_metadata) - end - end - search_results + fields = parse_fields(opts) + Msf::Modules::Metadata::Cache.instance.find(params, fields) end ####### @@ -39,34 +33,15 @@ module Msf::WebServices::ModuleSearch params end - def get_fields(opts, module_metadata) - selected_fields = {} - - aliases = { - :cve => 'references', - :edb => 'references', - :bid => 'references', - :fullname => 'full_name', - :os => 'platform', - :port => 'rport', - :reference => 'references', - :ref => 'ref_name', - :target => 'targets', - :authors => 'author' - } - + def parse_fields(opts) + fields = [] if opts.key? :fields fields = opts[:fields].split(',') fields.each do | field | field.strip! - field = aliases[field.to_sym] if aliases[field.to_sym] - if module_metadata.respond_to?(field) - selected_fields[field] = module_metadata.send(field) - end end end - selected_fields.empty? ? module_metadata : selected_fields + fields end - end diff --git a/lib/msf/ui/console/command_dispatcher/modules.rb b/lib/msf/ui/console/command_dispatcher/modules.rb index caa838a4da..330c4b8306 100644 --- a/lib/msf/ui/console/command_dispatcher/modules.rb +++ b/lib/msf/ui/console/command_dispatcher/modules.rb @@ -389,7 +389,8 @@ module Msf # Display the table of matches tbl = generate_module_table("Matching Modules", search_term) - Msf::Modules::Metadata::Cache.instance.find(match).each do |m| + search_params = parse_search_string(match) + Msf::Modules::Metadata::Cache.instance.find(search_params).each do |m| tbl << [ m.full_name, m.disclosure_date.nil? ? '' : m.disclosure_date.strftime("%Y-%m-%d"), @@ -409,6 +410,42 @@ module Msf end end + # + # Parses command line search string into a hash + # + # Resulting Hash Example: + # {"platform"=>[["android"], []]} will match modules targeting the android platform + # {"platform"=>[[], ["android"]]} will exclude modules targeting the android platform + # + def parse_search_string(search_string) + # Split search terms by space, but allow quoted strings + terms = search_string.split(/\"/).collect{|term| term.strip==term ? term : term.split(' ')}.flatten + terms.delete('') + + # All terms are either included or excluded + res = {} + + terms.each do |term| + keyword, search_term = term.split(":", 2) + unless search_term + search_term = keyword + keyword = 'text' + end + next if search_term.length == 0 + keyword.downcase! + search_term.downcase! + res[keyword] ||=[ [], [] ] + if search_term[0,1] == "-" + next if search_term.length == 1 + res[keyword][1] << search_term[1,search_term.length-1] + else + res[keyword][0] << search_term + end + end + res + end + + # # Tab completion for the search command #