Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 101 lines (92 sloc) 3.44 KB
#!/usr/bin/env ruby
#
# List all findings from a Nessus XML output
#
require 'optparse' #option parser
require 'nokogiri' #xml parser
require 'colorize' #color
# Parse command line options
x=nil
options = {}
optparse = OptionParser.new do |opts|
# The banner to display at the top
opts.banner = "Parses a Nessus XML output file and lists findings for each host sorted by CVSS.
\nUsage: nessus_list.rb [options]"
opts.on( '-f', '--file FILENAME', 'Nessus XML output file' ) do |file|
options[:file] = file
end
opts.on( '-i', '--ignore', 'Ignore Info / no-CVSS findings' ) do |ignore|
options[:ignore] = ignore
end
opts.on('-c', '--color', 'Colorize findings by severity' ) do |color|
options[:color] = color
end
opts.on('-g', '--grepable', 'Grepable output format' ) do |grepable|
options[:grepable] = grepable
end
opts.on( '-h', '--help', 'Display this screen' ) do
puts opts
exit
end
x=opts
end.parse!(ARGV)
# If no options are specified, output help screen and exit
if options[:file].nil?
puts x
exit
end
# If grepable, set it
if options[:grepable]
GREPABLE = true
else
GREPABLE = false
end
# Open the file for reading
xml_file = File.read(options[:file])
# Parse as Nokogiri XML element
doc = Nokogiri::XML(xml_file)
hosts = doc.xpath('//NessusClientData_v2/Report/ReportHost') #find hosts
hosts.each do |host| #for each hosts do
findings = []
host.xpath('./ReportItem').each do |item| #for each report item do
if item.at_xpath("cvss_base_score").nil? #if no cvss node present (info finding) create a new node
cvss = Nokogiri::XML::Node.new("cvss_base_score", doc)
cvss.content = "-" #set the initial value to "-"
item << cvss
else
cvss = item.at_xpath("cvss_base_score") #if cvss present, store value
end
proto = item.at_xpath("@protocol") #store proto value
port = item.at_xpath("@port") #store port value
plugin_name = item.at_xpath("plugin_name") #store plugin name value
unless cvss.text == "-" && options[:ignore] #store finding unless ignore is set and cvss value is "-"
findings.push([cvss.text.to_f, proto.text, port.text, plugin_name.text])
end
end
if findings.any? #display output for the IP if findings
puts "\nHost: "+host.at_xpath("@name") unless GREPABLE
puts "CVSS\tProto\tPort\tName" unless GREPABLE
puts "----\t-----\t----\t----" unless GREPABLE
findings.sort_by!{ |a,b,c,d| a } #sort findings by first element in array (cvss)
findings.reverse.each do |finding| #sort_by is low to high, so reverse
if finding[0] >= 9.0 #critical finding
severity = "magenta"
elsif finding[0] >= 7.0 and finding[0] <= 8.9 #high finding
severity = "red"
elsif finding[0] >= 4.0 and finding[0] <= 6.9 #medium finding
severity = "light_yellow"
elsif finding[0] >= 0.1 and finding[0] <= 3.9 #low finding
severity = "light_blue"
else #info finding
severity = "light_green"
end
if options[:color] #if color enabled, display in color, else no color
puts "#{finding[0].to_s} \t #{finding[1]} \t #{finding[2]} \t #{finding[3]}".colorize(:"#{severity}") unless GREPABLE
puts host.at_xpath("@name").to_s + "\t" + "#{finding[0].to_s} \t #{finding[1]} \t #{finding[2]} \t #{finding[3]}".colorize(:"#{severity}") if GREPABLE
else
puts finding[0].to_s + "\t" + finding[1] + "\t" + finding[2] + "\t" + finding[3] unless GREPABLE
puts host.at_xpath("@name").to_s + "\t" + finding[0].to_s + "\t" + finding[1] + "\t" + finding[2] + "\t" + finding[3] if GREPABLE
end
end
end
end
You can’t perform that action at this time.