178 lines
6.9 KiB
Ruby
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
|
|
|