Add keyword searching to msfconsole
git-svn-id: file:///home/svn/framework3/trunk@12752 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
96e6e22795
commit
52f7863890
|
@ -573,6 +573,86 @@ class Module
|
|||
(datastore['DEBUG'] || '') =~ /^(1|t|y)/i
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This provides a standard set of search filters for every module.
|
||||
# The search terms are in the form of:
|
||||
# {
|
||||
# "text" => [ [ "include_term1", "include_term2", ...], [ "exclude_term1", "exclude_term2"], ... ],
|
||||
# "cve" => [ [ "include_term1", "include_term2", ...], [ "exclude_term1", "exclude_term2"], ... ]
|
||||
# }
|
||||
#
|
||||
# Returns true on no match, false on match
|
||||
#
|
||||
def search_filter(k)
|
||||
|
||||
refs = self.references.map{|x| [x.ctx_id, x.ctx_val].join("-") }
|
||||
is_exploit = (self.type == "exploit")
|
||||
is_auxiliary = (self.type == "auxiliary")
|
||||
is_post = (self.type == "post")
|
||||
is_server = (self.respond_to?(:stance) and self.stance == "aggressive")
|
||||
is_client = (self.respond_to?(:stance) and self.stance == "passive")
|
||||
|
||||
[0,1].each do |mode|
|
||||
match = false
|
||||
k.keys.each do |t|
|
||||
next if k[t][mode].length == 0
|
||||
|
||||
k[t][mode].each do |w|
|
||||
# Reset the match flag for each keyword for inclusive search
|
||||
match = false if mode == 0
|
||||
|
||||
# Convert into a case-insensitive regex
|
||||
r = Regexp.new(Regexp.escape(w), true)
|
||||
|
||||
case t
|
||||
when 'text'
|
||||
terms = [self.name, self.fullname, self.description] + refs + self.author.map{|x| x.to_s}
|
||||
if self.respond_to?(:targets) and self.targets
|
||||
terms = terms + self.targets.map{|x| x.name}
|
||||
end
|
||||
match = [t,w] if terms.any? { |x| x =~ r }
|
||||
when 'name'
|
||||
match = [t,w] if self.name =~ r
|
||||
when 'path'
|
||||
match = [t,w] if self.fullname =~ r
|
||||
when 'author'
|
||||
match = [t,w] if self.author.map{|x| x.to_s}.any? { |a| a =~ r }
|
||||
when 'os', 'platform'
|
||||
match = [t,w] if self.platform_to_s =~ r or self.arch_to_s =~ r
|
||||
if not match and self.respond_to?(:targets) and self.targets
|
||||
match = [t,w] if self.targets.map{|x| x.name}.any? { |t| t =~ r }
|
||||
end
|
||||
when 'type'
|
||||
match = [t,w] if (w == "exploit" and is_exploit)
|
||||
match = [t,w] if (w == "auxiliary" and is_auxiliary)
|
||||
match = [t,w] if (w == "post" and is_post)
|
||||
when 'app'
|
||||
match = [t,w] if (w == "server" and is_server_exploit)
|
||||
match = [t,w] if (w == "client" and is_client_exploit)
|
||||
when 'cve'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^cve\-/i and ref =~ r }
|
||||
when 'bid'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^bid\-/i and ref =~ r }
|
||||
when 'osvdb'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^osvdb\-/i and ref =~ r }
|
||||
end
|
||||
break if match
|
||||
end
|
||||
# Filter this module if no matches for a given keyword type
|
||||
if mode == 0 and not match
|
||||
return true
|
||||
end
|
||||
end
|
||||
# Filter this module if we matched an exlusion keyword (-value)
|
||||
if mode == 1 and match
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Just some handy quick checks
|
||||
|
|
|
@ -64,9 +64,6 @@ class Core
|
|||
"-z" => [ false, "Just try to connect, then return." ])
|
||||
|
||||
@@search_opts = Rex::Parser::Arguments.new(
|
||||
"-t" => [ true, "Type of module to search for (all|auxiliary|encoder|exploit|nop|payload)" ],
|
||||
"-r" => [ true, "Minimum rank to return (#{RankingName.sort.map{|r|r[1]}.join("|")})" ],
|
||||
"-o" => [ true, "Options or default values to search for (e.g. URIPATH,RPORT=80)" ],
|
||||
"-h" => [ false, "Help banner." ])
|
||||
|
||||
|
||||
|
@ -1124,73 +1121,57 @@ class Core
|
|||
end
|
||||
|
||||
#
|
||||
# Searches modules (name and description) for specified regex
|
||||
# Searches modules for specific keywords
|
||||
#
|
||||
def cmd_search(*args)
|
||||
section = 'all'
|
||||
rank = 'manual'
|
||||
match = nil
|
||||
opts = {}
|
||||
match = ''
|
||||
|
||||
@@search_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-h"
|
||||
cmd_search_help
|
||||
return
|
||||
when "-t"
|
||||
section = val
|
||||
when "-r"
|
||||
rank = val
|
||||
when "-o"
|
||||
val.split(',').each do |optstring|
|
||||
opt, val = optstring.split('=',2)
|
||||
opts[opt] = val
|
||||
end
|
||||
else
|
||||
match = val
|
||||
match += val + " "
|
||||
end
|
||||
}
|
||||
match = '.*' if match.nil?
|
||||
|
||||
|
||||
begin
|
||||
regex = Regexp.new(match, true, 'n')
|
||||
rescue RegexpError => e
|
||||
print_error("Invalid regular expression: #{match} (hint: try .*)")
|
||||
return
|
||||
end
|
||||
match += " "
|
||||
# Split search terms by space, but allow quoted strings
|
||||
terms = match.split(/\"/).collect{|t| t.strip==t ? t : t.split(' ')}.flatten
|
||||
terms.delete('')
|
||||
|
||||
print_status("Searching loaded modules for pattern '#{match}'...")
|
||||
# All terms are either included or excluded
|
||||
res = {}
|
||||
|
||||
if rank.to_i != 0
|
||||
rank = rank.to_i
|
||||
elsif RankingName.has_value? rank
|
||||
rank = RankingName.invert[rank]
|
||||
else
|
||||
print_error("Invalid rank, should be one of: " + RankingName.sort.map{|r| r[1]}.join(", "))
|
||||
return
|
||||
end
|
||||
case section
|
||||
when 'all'
|
||||
show_auxiliary(regex, rank, opts)
|
||||
show_encoders(regex, rank, opts)
|
||||
show_exploits(regex, rank, opts)
|
||||
show_nops(regex, rank, opts)
|
||||
show_payloads(regex, rank, opts)
|
||||
show_post(regex, rank, opts)
|
||||
when 'auxiliary'
|
||||
show_auxiliary(regex, rank, opts)
|
||||
when 'encoder'
|
||||
show_encoders(regex, rank, opts)
|
||||
when 'exploit'
|
||||
show_exploits(regex, rank, opts)
|
||||
when 'nop'
|
||||
show_nops(regex, rank, opts)
|
||||
when 'payload'
|
||||
show_payloads(regex, rank, opts)
|
||||
when 'post'
|
||||
show_post(regex, rank, opts)
|
||||
else
|
||||
print_error("Unknown type '#{section}'")
|
||||
terms.each do |t|
|
||||
f,v = t.split(":", 2)
|
||||
if not v
|
||||
v = f
|
||||
f = 'text'
|
||||
end
|
||||
next if v.length == 0
|
||||
f.downcase!
|
||||
v.downcase!
|
||||
res[f] ||=[ [], [] ]
|
||||
if v[0,1] == "-"
|
||||
next if v.length == 1
|
||||
res[f][1] << v[1,v.length-1]
|
||||
else
|
||||
res[f][0] << v
|
||||
end
|
||||
end
|
||||
|
||||
tbl = generate_module_table("Matching Modules")
|
||||
framework.modules.each do |m|
|
||||
o = framework.modules.create(m[0])
|
||||
if not o.search_filter(res)
|
||||
tbl << [ o.fullname, o.disclosure_date.to_s, o.rank_to_s, o.name ]
|
||||
end
|
||||
end
|
||||
print_line(tbl.to_s)
|
||||
|
||||
end
|
||||
|
||||
def cmd_search_tabs(str, words)
|
||||
|
@ -1209,7 +1190,7 @@ class Core
|
|||
end
|
||||
|
||||
def cmd_search_help
|
||||
print_line "Usage: search [options] [regex]"
|
||||
print_line "Usage: search [keywords]"
|
||||
print_line
|
||||
print @@search_opts.usage
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue