Land #14021, when searching modules for multiple text terms, the search will now require for all words to be matched
This commit is contained in:
commit
177f720f80
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/modules/metadata'
|
||||
|
||||
#
|
||||
|
@ -16,6 +18,11 @@ module Msf::Modules::Metadata::Search
|
|||
"aux" => Msf::MODULE_AUX
|
||||
}
|
||||
|
||||
module SearchMode
|
||||
INCLUDE = 0
|
||||
EXCLUDE = 1
|
||||
end
|
||||
|
||||
#
|
||||
# Parses command line search string into a hash. A param prefixed with '-' indicates "not", and will omit results
|
||||
# matching that keyword. This hash can be used with the find command.
|
||||
|
@ -52,9 +59,9 @@ module Msf::Modules::Metadata::Search
|
|||
res[keyword] ||=[ [], [] ]
|
||||
if search_term[0,1] == "-"
|
||||
next if search_term.length == 1
|
||||
res[keyword][1] << search_term[1,search_term.length-1]
|
||||
res[keyword][SearchMode::EXCLUDE] << search_term[1,search_term.length-1]
|
||||
else
|
||||
res[keyword][0] << search_term
|
||||
res[keyword][SearchMode::INCLUDE] << search_term
|
||||
end
|
||||
end
|
||||
res
|
||||
|
@ -87,22 +94,41 @@ module Msf::Modules::Metadata::Search
|
|||
|
||||
param_hash = params
|
||||
|
||||
[0,1].each do |mode|
|
||||
[SearchMode::INCLUDE, SearchMode::EXCLUDE].each do |mode|
|
||||
match = false
|
||||
param_hash.keys.each do |keyword|
|
||||
next if param_hash[keyword][mode].length == 0
|
||||
|
||||
# free form text search will honor 'and' semantics, i.e. 'metasploit pro' will only match modules that contain both
|
||||
# words, and will return false when only one word is matched
|
||||
if keyword == 'text'
|
||||
text_segments = [module_metadata.name, module_metadata.fullname, module_metadata.description] + module_metadata.references + module_metadata.author + (module_metadata.notes['AKA'] || [])
|
||||
|
||||
if module_metadata.targets
|
||||
text_segments = text_segments + module_metadata.targets
|
||||
end
|
||||
|
||||
param_hash[keyword][mode].each do |search_term|
|
||||
has_match = text_segments.any? { |text_segment| text_segment =~ as_regex(search_term) }
|
||||
match = [keyword, search_term] if has_match
|
||||
if mode == SearchMode::INCLUDE && !has_match
|
||||
return false
|
||||
end
|
||||
if mode == SearchMode::EXCLUDE && has_match
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
next
|
||||
end
|
||||
|
||||
# The remaining keywords honor 'or' semantics, i.e. the following param_hash will match either osx, or linux
|
||||
# {"platform"=>[["osx", "linux"], []]}
|
||||
param_hash[keyword][mode].each do |search_term|
|
||||
# Reset the match flag for each keyword for inclusive search
|
||||
match = false if mode == 0
|
||||
match = false if mode == SearchMode::INCLUDE
|
||||
|
||||
# Convert into a case-insensitive regex
|
||||
utf8_buf = search_term.dup.force_encoding('UTF-8')
|
||||
if utf8_buf.valid_encoding?
|
||||
regex = Regexp.new(Regexp.escape(utf8_buf), true)
|
||||
else
|
||||
return false
|
||||
end
|
||||
regex = as_regex(search_term)
|
||||
case keyword
|
||||
when 'aka'
|
||||
match = [keyword, search_term] if (module_metadata.notes['AKA'] || []).any? { |aka| aka =~ regex }
|
||||
|
@ -176,13 +202,6 @@ module Msf::Modules::Metadata::Search
|
|||
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
|
||||
|
@ -192,12 +211,12 @@ module Msf::Modules::Metadata::Search
|
|||
break if match
|
||||
end
|
||||
# Filter this module if no matches for a given keyword type
|
||||
if mode == 0 and not match
|
||||
if mode == SearchMode::INCLUDE and not match
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Filter this module if we matched an exclusion keyword (-value)
|
||||
if mode == 1 and match
|
||||
if mode == SearchMode::EXCLUDE and match
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
@ -205,6 +224,17 @@ module Msf::Modules::Metadata::Search
|
|||
true
|
||||
end
|
||||
|
||||
def as_regex(search_term)
|
||||
# Convert into a case-insensitive regex
|
||||
utf8_buf = search_term.dup.force_encoding('UTF-8')
|
||||
if utf8_buf.valid_encoding?
|
||||
Regexp.new(Regexp.escape(utf8_buf), Regexp::IGNORECASE)
|
||||
else
|
||||
# If the encoding is invalid, default to a regex that matches anything
|
||||
//
|
||||
end
|
||||
end
|
||||
|
||||
def get_fields(module_metadata, fields)
|
||||
selected_fields = {}
|
||||
|
||||
|
|
|
@ -669,7 +669,7 @@ module Msf
|
|||
# Avoid trying to use the search result if it exactly matches
|
||||
# the module we were trying to load. The module cannot be
|
||||
# loaded and searching isn't going to change that.
|
||||
mods_found = cmd_search('-I', '-u', mod_name)
|
||||
mods_found = cmd_search('-I', '-u', *args)
|
||||
end
|
||||
|
||||
unless mods_found
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Msf::Modules::Metadata::Search do
|
||||
|
@ -203,6 +205,49 @@ RSpec.describe Msf::Modules::Metadata::Search do
|
|||
it_should_behave_like 'search_filter', :accept => [nil, '', ' '], :test_inverse => false
|
||||
end
|
||||
|
||||
context 'on a module with a #description of "metasploit pro console"' do
|
||||
let(:opts) { ({ 'description' => 'metasploit pro console' }) }
|
||||
it_should_behave_like(
|
||||
'search_filter',
|
||||
:accept => ["metasploit", "metasploit pro", "metasploit pro console", "console pro"],
|
||||
:reject => ["metasploit framework", "pro framework", "pro console php"],
|
||||
:test_inverse => false
|
||||
)
|
||||
end
|
||||
|
||||
context 'when invalid encodings are used, all results are returned' do
|
||||
context 'and the search term is present' do
|
||||
let(:opts) { ({ 'author' => ['István'.force_encoding("UTF-8")] }) }
|
||||
it_should_behave_like(
|
||||
'search_filter',
|
||||
accept: [
|
||||
"author:István",
|
||||
"author:Istv\xE1n ",
|
||||
"author:Istv\u00E1n ",
|
||||
],
|
||||
:reject => [
|
||||
'different_author'
|
||||
],
|
||||
:test_inverse => false
|
||||
)
|
||||
end
|
||||
context 'and the search term is not present' do
|
||||
let(:opts) { ({ 'author' => ['different_author'] }) }
|
||||
it_should_behave_like(
|
||||
'search_filter',
|
||||
accept: [
|
||||
'different_author',
|
||||
"author:Istv\xE1n",
|
||||
],
|
||||
:reject => [
|
||||
"author:István",
|
||||
"author:Istv\u00E1n ",
|
||||
],
|
||||
:test_inverse => false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when filtering by module #type' do
|
||||
all_module_types = Msf::MODULE_TYPES
|
||||
all_module_types.each do |mtype|
|
||||
|
|
Loading…
Reference in New Issue