Merge Zate Berg's latest patch

git-svn-id: file:///home/svn/framework3/trunk@10938 4d416f70-5f16-0410-b530-b9f4589650da
unstable
HD Moore 2010-11-07 01:57:17 +00:00
parent 416f6966e3
commit 8f4cb4fbf6
2 changed files with 352 additions and 50 deletions

View File

@ -17,7 +17,7 @@ class NessusXMLStreamParser
def reset_state
@host = {'hname' => nil, 'addr' => nil, 'mac' => nil, 'os' => nil, 'ports' => [
'port' => {'port' => nil, 'svc_name' => nil, 'proto' => nil, 'severity' => nil,
'nasl' => nil, 'description' => nil, 'cve' => [], 'bid' => [], 'xref' => [] } ] }
'nasl' => nil, 'description' => nil, 'cve' => [], 'bid' => [], 'xref' => [], 'msf' => nil } ] }
@state = :generic_state
end
@ -66,9 +66,6 @@ class NessusXMLStreamParser
end
end
def text(str)
case @state
when :is_fqdn
@ -88,16 +85,8 @@ class NessusXMLStreamParser
when :is_xref
@xref.push str
when :msf
#this requires that the user has run nessus_exploits to build the index. Not ready for primetime.
#regex = Regexp.new(str, true, 'n')
#File.open("xindex", "r") do |m|
# while line = m.gets
# if (line.match(regex))
# exp = line.split("|").first
# @x['msf'] = exp
# end
# end
#end
#p str
@x['msf'] = str
end
end

View File

@ -1,10 +1,83 @@
require 'nessus/nessus-xmlrpc'
require 'rex/parser/nessus_xml'
module Msf
#constants
NBVer = "1.0" # Nessus Plugin Version. Increments each time we commit to msf
Xindex = "#{Msf::Config.get_config_root}/nessus_index" # location of the exploit index file used to speed up searching for valid exploits.
class Plugin::Nessus < Msf::Plugin
#creates the index of exploit details to make searching for exploits much faster.
def create_xindex
start = Time.now
print_status("Creating Exploit Search Index - (#{Xindex}) - this wont take long.")
print("%grn[*]")
count = 0
# use Msf::Config.get_config_root as the location.
File.open("#{Xindex}", "w+") do |f|
#need to add version line.
f.puts(Msf::Framework::RepoRevision)
framework.exploits.sort.each { |refname, mod|
case count
when 0
print("\b\b\b[|]")
count += 1
when 1
print("\b\b\b[/]")
count += 1
when 2
print("\b\b\b[-]")
count += 1
when 3
print("\b\b\b[\\]")
count =0
end
stuff = ""
o = nil
begin
o = mod.new
rescue ::Exception
end
stuff << "#{refname}|#{o.name}|#{o.platform_to_s}|#{o.arch_to_s}"
next if not o
o.references.map do |x|
if !(x.ctx_id == "URL")
if (x.ctx_id == "MSB")
stuff << "|#{x.ctx_val}"
else
stuff << "|#{x.ctx_id}-#{x.ctx_val}"
end
end
end
stuff << "\n"
f.puts(stuff)
}
end
total = Time.now - start
print("\b\b\b[*]%clr")
print("\n")
print_status("It has taken : #{total} seconds to build the exploits search index")
end
def nessus_index
if File.exist?("#{Xindex}")
#check if it's version line matches current version.
File.open("#{Xindex}") {|f|
line = f.readline
line.chomp!
if line.to_i == Msf::Framework::RepoRevision
print_good("Exploit Index - (#{Xindex}) - is valid.")
else
create_xindex
end
}
else
create_xindex
end
end
###
#
# This class implements a sample console command dispatcher.
@ -52,46 +125,286 @@ module Msf
"nessus_plugin_prefs" => "Display Plugin Prefs",
"nessus_policy_list" => "List all polciies",
"nessus_policy_del" => "Delete a policy",
"nessus_exploits" => "Generates a search index for exploits.",
"nessus_template_list" => "List all the templates on the server"
"nessus_index" => "Manually generates a search index for exploits.",
"nessus_template_list" => "List all the templates on the server",
"nessus_db_scan" => "Create a scan of all ips in db_hosts",
"nessus_report_exploits" => "Shows a summary of all the vulns in a scan that have a msf exploit."
}
end
def cmd_nessus_exploits
#need to expand this to index all modules. What kind of info is needed?
#find a better place to keep the indexes and a way to name them
#put in version checking:
#check if exists and is a valid readable file (read first line)
#If the version line at start of current index doesnt match rev number of msf, rebuild index
start = Time.now
File.open("xindex", "w+") do |f|
framework.exploits.sort.each { |refname, mod|
stuff = ""
o = nil
begin
o = mod.new
rescue ::Exception
def cmd_nessus_index
Msf::Plugin::Nessus.nessus_index
end
stuff << "#{refname}|#{o.name}|#{o.platform_to_s}|#{o.arch_to_s}"
next if not o
o.references.map do |x|
if !(x.ctx_id == "URL")
if (x.ctx_id == "MSB")
stuff << "|#{x.ctx_val}"
def cmd_nessus_report_exploits(*args)
if args[0] == "-h"
print_status("Usage: ")
print_status(" nessus_report_summary <report id>")
print_status(" Example:> nessus_report_summary 33ebfd80-5e6f-348d-8f15-04628b5f5ca789bb25241af01698")
print_status()
print_status("Parses your report and just shows you exploitable vulns.")
print_status("%redThis plugin is experimental%clr")
return
end
if ! nessus_verify_db
print_error("You need a database configured for this command.")
print_error("Connect to a db with \"db_connect\"")
print_error("Then import scan with nessus_report_get")
return
end
if ! nessus_verify_token
return
end
rid = nil
case args.length
when 1
rid = args[0]
else
stuff << "|#{x.ctx_id}-#{x.ctx_val}"
print_status("Usage: ")
print_status(" nessus_report_summary <report id>")
print_status("Parses your report and just shows you exploitable vulns.")
return
end
if check_scan(rid)
print_error("That scan is still running.")
return
end
#streaming parser ftw.
content = nil
content=@n.report_file_download(rid)
if content.nil?
print_error("Failed, please reauthenticate")
return
end
print_status("Examining " + rid)
print_error("Experimental, trust but verify")
print("\n")
parser = Rex::Parser::NessusXMLStreamParser.new
parser.on_found_host = Proc.new { |host|
addr = host['addr'] || host['hname']
addr.gsub!(/[\n\r]/," or ") if addr
os = host['os']
os.gsub!(/[\n\r]/," or ") if os
hname = host['hname']
hname.gsub!(/[\n\r]/," or ") if hname
mac = host['mac']
mac.gsub!(/[\n\r]/," or ") if mac
host['ports'].each do |item|
next if item['port'] == 0
exp = []
msf = nil
nasl = item['nasl'].to_s
port = item['port'].to_s
proto = item['proto'] || "tcp"
name = item['svc_name']
severity = item['severity']
description = item['description']
cve = item['cve']
bid = item['bid']
xref = item['xref']
msf = item['msf']
# find exploits based on the msf plugin name from the report output.
if msf
regex = Regexp.new(msf, true, 'n')
File.open("#{Xindex}", "r") do |m|
while line = m.gets
exp.push line.split("|").first if (line.match(regex))
end
end
end
stuff << "\n"
f.puts(stuff)
# find exploits based on CVE
if cve
cve.each do |c|
regex = Regexp.new(c, true, 'n')
File.open("#{Xindex}", "r") do |m|
while line = m.gets
exp.push line.split("|").first if (line.match(regex))
end
end
end
end
#find exploits based on BID
if bid
bid.each do |c|
r = "BID-"
r << c
regex = Regexp.new(r, true, 'n')
File.open("#{Xindex}", "r") do |m|
while line = m.gets
exp.push line.split("|").first if (line.match(regex))
end
end
end
end
#find exploits based on OSVDB entry
#find exploits based on MSB
if xref
xref.each do |c|
if c =~ /OSVDB/
c.gsub!(/:/, "-")
regex = Regexp.new(c, true, 'n')
File.open("#{Xindex}", "r") do |m|
while line = m.gets
exp.push line.split("|").first if (line.match(regex))
end
end
end
end
end
#make sure we only report a exploit once in exp. We should evaluate the accuracy of the exploit suggested too, weed out some obvious non starters.
#refs = []
#
#cve.each do |r|
# r.to_s.gsub!(/C(VE|AN)\-/, '')
# refs.push('CVE-' + r.to_s)
#end if cve
#
#bid.each do |r|
# refs.push('BID-' + r.to_s)
#end if bid
#
#xref.each do |r|
# ref_id, ref_val = r.to_s.split(':')
# ref_val ? refs.push(ref_id + '-' + ref_val) : refs.push(ref_id)
#end if xref
#msfref = "MSF-" << exp if exp
#refs.push msfref if msfref
nss = 'NSS-' + nasl
next if exp.empty?
print("#{addr} | #{os} | #{port} | #{nss} | Sev #{severity} | %bld%red#{exp.uniq}%clr\n")
end
}
REXML::Document.parse_stream(content, parser)
end
total = Time.now - start
print_status("It has taken : #{total} seconds to build the exploits search index")
def cmd_nessus_db_scan(*args)
if args[0] == "-h"
print_status("Usage: ")
print_status(" nessus_db_scan <policy id> <scan name>")
print_status(" Example:> nessus_db_scan 1 \"My Scan\"")
print_status()
print_status("Creates a scan based on all the hosts listed in db_hosts.")
print_status("use nessus_policy_list to list all available policies")
return
end
if ! nessus_verify_token
return
end
case args.length
when 2
pid = args[0].to_i
name = args[1]
else
print_status("Usage: ")
print_status(" nessus_db_scan <policy id> <scan name>")
print_status(" use nessus_policy_list to list all available policies")
return
end
if check_policy(pid)
print_error("That policy does not exist.")
return
end
tgts = ""
framework.db.hosts(framework.db.workspace).each do |host|
tgts << host.address
tgts << ","
end
tgts.chop!
print_status("Creating scan from policy number #{pid}, called \"#{name}\" and scanning all hosts in workspace")
scan = @n.scan_new(pid, name, tgts)
if scan
print_status("Scan started. uid is #{scan}")
end
end
#def cmd_nessus_exploits
# #need to expand this to index all modules. What kind of info is needed?
# #find a better place to keep the indexes and a way to name them
# #put in version checking:
# #check if exists and is a valid readable file (read first line)
# #If the version line at start of current index doesnt match rev number of msf, rebuild index
#
# start = Time.now
# @count = 0
# print_status("Building the exploits search index")
# print("%bld%grn[")
# File.open("xindex", "w+") do |f|
# framework.exploits.sort.each { |refname, mod|
# stuff = ""
# o = nil
# begin
# o = mod.new
# rescue ::Exception
# end
# stuff << "#{refname}|#{o.name}|#{o.platform_to_s}|#{o.arch_to_s}"
# next if not o
# o.references.map do |x|
# if !(x.ctx_id == "URL")
# if (x.ctx_id == "MSB")
# stuff << "|#{x.ctx_val}"
# else
# stuff << "|#{x.ctx_id}-#{x.ctx_val}"
# end
# end
# end
# stuff << "\n"
# f.puts(stuff)
#
# case @count
# when 0
# print("%bld%grn|]\b\b")
# @count += 1
# when 1
# print("%bld%grn/]\b\b")
# @count += 1
# when 2
# print("%bld%grn-]\b\b")
# @count += 1
# when 3
# print("%bld%grn/]\b\b")
# @count = 0
# end
# $stdout.flush
# }
# end
# total = Time.now - start
# print("%bld%grn*] Done!\n")
# print_status("It has taken : #{total} seconds to build the exploits search index")
#end
def cmd_nessus_logout
@token = nil
print_status("Logged out")
@ -1536,9 +1849,9 @@ module Msf
# that uses the framework's console user interface driver, register
# console dispatcher commands.
add_console_dispatcher(ConsoleCommandDispatcher)
print_status("Nessus Bridge for Nessus 4.2.x")
print_status("Nessus Bridge for Metasploit #{NBVer}")
print_good("Type %bldnessus_help%clr for a command listing")
nessus_index
end
#
@ -1556,7 +1869,7 @@ module Msf
# This method returns a short, friendly name for the plugin.
#
def name
"nessus"
"nessus bridge"
end
#
@ -1564,7 +1877,7 @@ module Msf
# more than 60 characters, but there are no hard limits.
#
def desc
"HTTP Bridge to control a Nessus 4.2 scanner."
"Nessus Bridge for Metasploit #{NBVer}"
end
protected
end