Files
metasploit-gs/lib/msf/core/modules/metadata/search.rb
T
2019-06-03 13:19:29 -05:00

178 lines
6.9 KiB
Ruby

require 'msf/core/modules/metadata'
#
# Provides search operations on the module metadata cache.
#
module Msf::Modules::Metadata::Search
VALID_PARAMS =
%w[aka author authors arch cve bid edb check date disclosure_date description fullname 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={})
raise ArgumentError 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
#######
private
#######
def is_match(params, module_metadata)
param_hash = params
[0,1].each do |mode|
match = false
param_hash.keys.each do |keyword|
next if param_hash[keyword][mode].length == 0
param_hash[keyword][mode].each do |search_term|
# Reset the match flag for each keyword for inclusive search
match = false if mode == 0
# Convert into a case-insensitive regex
regex = Regexp.new(Regexp.escape(search_term), true)
case keyword
when 'aka'
match = [keyword, search_term] if (module_metadata.notes['AKA'] || []).any? { |aka| aka =~ regex }
when 'author', 'authors'
match = [keyword, search_term] if module_metadata.author.any? { |author| author =~ regex }
when 'arch'
match = [keyword, search_term] if module_metadata.arch =~ regex
when 'cve'
match = [keyword, search_term] if module_metadata.references.any? { |ref| ref =~ /^cve\-/i and ref =~ regex }
when 'bid'
match = [keyword, search_term] if module_metadata.references.any? { |ref| ref =~ /^bid\-/i and ref =~ regex }
when 'edb'
match = [keyword, search_term] if module_metadata.references.any? { |ref| ref =~ /^edb\-/i and ref =~ regex }
when 'check'
if module_metadata.check
matches_check = %w(true yes).any? { |val| val =~ regex}
else
matches_check = %w(false no).any? { |val| val =~ regex}
end
match = [keyword, search_term] if matches_check
when 'date', 'disclosure_date'
match = [keyword, search_term] if module_metadata.disclosure_date.to_s =~ regex
when 'description'
match = [keyword, search_term] if module_metadata.description =~ regex
when 'fullname'
match = [keyword, search_term] if module_metadata.fullname =~ regex
when 'mod_time'
match = [keyword, search_term] if module_metadata.mod_time.to_s =~ regex
when 'name'
match = [keyword, search_term] if module_metadata.name =~ regex
when 'os', 'platform'
match = [keyword, search_term] if module_metadata.platform =~ regex or module_metadata.arch =~ regex
if module_metadata.targets
match = [keyword, search_term] if module_metadata.targets.any? { |target| target =~ regex }
end
when 'path'
match = [keyword, search_term] if module_metadata.fullname =~ regex
when 'port', 'rport'
match = [keyword, search_term] if module_metadata.rport.to_s =~ regex
when 'rank'
# Determine if param was prepended with gt, lt, gte, lte, or eq
# Ex: "lte300" should match all ranks <= 300
query_rank = search_term.dup
operator = query_rank[0,3].tr('0-9', '')
valid_operators = %w[eq gt lt gte lte]
matches_rank = module_metadata.rank == search_term.to_i
if valid_operators.include? operator
query_rank.slice! operator
query_rank = query_rank.to_i
case operator
when 'gt'
matches_rank = module_metadata.rank.to_i > query_rank
when 'lt'
matches_rank = module_metadata.rank.to_i < query_rank
when 'gte'
matches_rank = module_metadata.rank.to_i >= query_rank
when 'lte'
matches_rank = module_metadata.rank.to_i <= query_rank
when 'eq'
matches_rank = module_metadata.rank.to_i == query_rank
end
elsif query_rank =~ /^\d+$/
matches_rank = module_metadata.rank.to_i == query_rank.to_i
else
matches_rank = module_metadata.rank.to_i == Msf::RankingName.key(query_rank)
end
match = [keyword, search_term] if matches_rank
when 'ref', 'ref_name'
match = [keyword, search_term] if module_metadata.ref_name =~ regex
when 'reference', 'references'
match = [keyword, search_term] if module_metadata.references.any? { |ref| ref =~ regex }
when 'target', 'targets'
match = [keyword, search_term] if module_metadata.targets.any? { |target| target =~ regex }
when 'text'
terms = [module_metadata.name, module_metadata.fullname, module_metadata.description] + module_metadata.references + module_metadata.author + (module_metadata.notes['AKA'] || [])
if module_metadata.targets
terms = terms + module_metadata.targets
end
match = [keyword, search_term] if terms.any? { |term| term =~ regex }
when 'type'
match = [keyword, search_term] if Msf::MODULE_TYPES.any? { |module_type| search_term == module_type and module_metadata.type == module_type }
else
# Ignore extraneous/invalid keywords
match = [keyword, search_term]
end
break if match
end
# Filter this module if no matches for a given keyword type
if mode == 0 and not match
return false
end
end
# Filter this module if we matched an exclusion keyword (-value)
if mode == 1 and match
return false
end
end
true
end
def get_fields(module_metadata, fields)
selected_fields = {}
aliases = {
:cve => 'references',
:edb => 'references',
:bid => 'references',
: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