nessus parsing ding
This commit is contained in:
parent
d06583e340
commit
3a88e1a752
1 changed files with 352 additions and 0 deletions
352
nessus-group/nessus-group.rb
Executable file
352
nessus-group/nessus-group.rb
Executable file
|
|
@ -0,0 +1,352 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
# $Id$
|
||||||
|
# $URL$
|
||||||
|
|
||||||
|
# parse nbe files and group IPs of matching vulnerabilities
|
||||||
|
|
||||||
|
require 'getoptlong'
|
||||||
|
require 'rexml/streamlistener'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
@vulns = Hash.new
|
||||||
|
|
||||||
|
Vuln = Struct.new(:ip, :fullip, :descr, :weight)
|
||||||
|
Weight= { 'Security Note' => 0,
|
||||||
|
'Security Warning' => 1,
|
||||||
|
'Security Hole' => 2,
|
||||||
|
'NOTE' => 0,
|
||||||
|
'INFO' => 1,
|
||||||
|
'REPORT' => 2
|
||||||
|
}
|
||||||
|
|
||||||
|
module Color
|
||||||
|
AnsiAttributes =
|
||||||
|
{
|
||||||
|
'clear' => 0,
|
||||||
|
'reset' => 0,
|
||||||
|
'bold' => 1,
|
||||||
|
'dark' => 2,
|
||||||
|
'underline' => 4,
|
||||||
|
'underscore' => 4,
|
||||||
|
'blink' => 5,
|
||||||
|
'reverse' => 7,
|
||||||
|
'concealed' => 8,
|
||||||
|
'black' => 30, 'on_black' => 40,
|
||||||
|
'red' => 31, 'on_red' => 41,
|
||||||
|
'green' => 32, 'on_green' => 42,
|
||||||
|
'yellow' => 33, 'on_yellow' => 43,
|
||||||
|
'blue' => 34, 'on_blue' => 44,
|
||||||
|
'magenta' => 35, 'on_magenta' => 45,
|
||||||
|
'cyan' => 36, 'on_cyan' => 46,
|
||||||
|
'white' => 37, 'on_white' => 47
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return a string with ANSI codes substituted. Derived from code
|
||||||
|
# written by The FaerieMUD Consortium.
|
||||||
|
#
|
||||||
|
def self.ansi(*attrs)
|
||||||
|
attr = attrs.collect {|a| AnsiAttributes[a] ? AnsiAttributes[a] : nil}.compact.join(';')
|
||||||
|
attr = "\e[%sm" % attr if ! attr.empty?
|
||||||
|
return attr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class XMLListener
|
||||||
|
Vuln = Struct.new(:ip, :fullip, :descr, :weight)
|
||||||
|
|
||||||
|
def initialize()
|
||||||
|
@curpath = Array.new
|
||||||
|
@curpathstr = ""
|
||||||
|
@curhost = ""
|
||||||
|
@vulns = Hash.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def clearhost
|
||||||
|
@curhost = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def clearreport
|
||||||
|
@curport = ""
|
||||||
|
@curseverity = ""
|
||||||
|
@curpluginID = ""
|
||||||
|
@curpluginName = ""
|
||||||
|
@curdata = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def gethash
|
||||||
|
return @vulns
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_start(name, attrs)
|
||||||
|
@curpath.push name
|
||||||
|
@curpathstr = @curpath.join('/')
|
||||||
|
# puts @curpathstr
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost'
|
||||||
|
clearhost
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_end(name)
|
||||||
|
@curpath.pop
|
||||||
|
@curpathstr = @curpath.join('/')
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost'
|
||||||
|
# nu is een report volledig, dus toevoegen aan standaard meuk ofzo
|
||||||
|
# nog even uitzoeken /hoe/
|
||||||
|
if ! @curseverity.nil? and @curseverity.to_i > 0
|
||||||
|
if ! @vulns[@curpluginID].nil?
|
||||||
|
@vulns[@curpluginID].push Vuln.new(@curhost, "#{@curhost} : #{@curport}",
|
||||||
|
@curdata.gsub(/\\n/, "\n").gsub(/\\r/, "\r").gsub(/\\\\/, "\\"), @curseverity.to_i - 1)
|
||||||
|
else
|
||||||
|
@vulns[@curpluginID] = [ Vuln.new(@curhost, "#{@curhost} : #{@curport}",
|
||||||
|
@curdata.gsub(/\\n/, "\n").gsub(/\\r/, "\r").gsub(/\\\\/, "\\"), @curseverity.to_i - 1) ]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
clearreport
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def text(text)
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost/HostName'
|
||||||
|
@curhost = text
|
||||||
|
end
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost/ReportItem/port'
|
||||||
|
@curport = text
|
||||||
|
end
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost/ReportItem/severity'
|
||||||
|
@curseverity = text
|
||||||
|
# is hier precies 1 hoger dan ik zelf bedacht had
|
||||||
|
# severity 0 = boeie
|
||||||
|
# severity 1 = note
|
||||||
|
# severity 2 = warning
|
||||||
|
# severity 3 = hole
|
||||||
|
end
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost/ReportItem/pluginID'
|
||||||
|
@curpluginID = text
|
||||||
|
end
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost/ReportItem/pluginName'
|
||||||
|
@curpluginName = text
|
||||||
|
end
|
||||||
|
if @curpathstr == 'NessusClientData/Report/ReportHost/ReportItem/data'
|
||||||
|
@curdata = text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def usage
|
||||||
|
puts <<EOT
|
||||||
|
nessus-group.rb [-a] <NBE-file>
|
||||||
|
|
||||||
|
-i <ids> ids is a comma seperated list of NessusIDs to be displayed
|
||||||
|
(default: all)
|
||||||
|
-f display full list of descriptions (default: only the first)
|
||||||
|
-C do not display colors
|
||||||
|
-s give a summary of the IDs found
|
||||||
|
-t use NessusId 21643 to generate a table of SSL-weaknesses (tab delimited)
|
||||||
|
EOT
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_options
|
||||||
|
@options = {}
|
||||||
|
begin
|
||||||
|
opts = GetoptLong.new(
|
||||||
|
[ "-i", GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ "-f", GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ "-h", "--help", GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ "-C", GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ "-s", GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ "-t", GetoptLong::NO_ARGUMENT ]
|
||||||
|
)
|
||||||
|
opts.quiet=true
|
||||||
|
opts.each do |opt, arg|
|
||||||
|
@options[opt] = arg
|
||||||
|
end
|
||||||
|
if @options["-h"]
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
rescue GetoptLong::InvalidOption
|
||||||
|
print "#{$!}\n"
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
# default values
|
||||||
|
if @options["-f"].nil?
|
||||||
|
@options["-f"] = false
|
||||||
|
end
|
||||||
|
if @options["-C"].nil?
|
||||||
|
@options["-C"] = false
|
||||||
|
end
|
||||||
|
if @options["-s"].nil?
|
||||||
|
@options["-s"] = false
|
||||||
|
end
|
||||||
|
return @options
|
||||||
|
end
|
||||||
|
|
||||||
|
def colorize(string, color)
|
||||||
|
if @options["-C"]
|
||||||
|
string
|
||||||
|
else
|
||||||
|
"#{Color.ansi(color)}#{string}#{Color.ansi("clear")}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def display(nessusid)
|
||||||
|
next if nessusid.nil?
|
||||||
|
puts "=========================================="
|
||||||
|
if @vulns[nessusid].nil?
|
||||||
|
puts "NessusID: #{nessusid} not found"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
puts "NessusID: #{nessusid} IPs: #{@vulns[nessusid].collect{|i| i[:ip]}.join(" ")}"
|
||||||
|
if ! @options["-f"]
|
||||||
|
case @vulns[nessusid][0][:weight]
|
||||||
|
when 2 then puts colorize("Severity: Security Hole", "on_red")
|
||||||
|
when 1 then puts colorize("Severity: Security Warning", "on_yellow")
|
||||||
|
when 0 then puts colorize("Severity: Security Note", "on_cyan")
|
||||||
|
end
|
||||||
|
puts "Full IPs:\n#{@vulns[nessusid].collect{|i| i[:fullip]}.join("\n")}"
|
||||||
|
puts "First description (these can differ per IP!):"
|
||||||
|
puts "#{@vulns[nessusid][0][:descr]}"
|
||||||
|
else
|
||||||
|
@vulns[nessusid].collect{|vuln|
|
||||||
|
case vuln[:weight]
|
||||||
|
when 2 then puts colorize("Severity: Security Hole #{vuln[:fullip]}", "on_red")
|
||||||
|
when 1 then puts colorize("Severity: Security Warning #{vuln[:fullip]}", "on_yellow")
|
||||||
|
when 0 then puts colorize("Severity: Security Note #{vuln[:fullip]}", "on_cyan")
|
||||||
|
end
|
||||||
|
puts "Description:"
|
||||||
|
puts "#{vuln[:descr]}"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def summary(weight)
|
||||||
|
case weight
|
||||||
|
when 2 then puts colorize("Severity: Security Hole", "on_red")
|
||||||
|
when 1 then puts colorize("Severity: Security Warning", "on_yellow")
|
||||||
|
when 0 then puts colorize("Severity: Security Note", "on_cyan")
|
||||||
|
end
|
||||||
|
@vulns.keys.sort.each{|nessusid|
|
||||||
|
if @vulns[nessusid][0][:weight] == weight
|
||||||
|
puts "NessusID: #{nessusid} IPs: #{@vulns[nessusid].collect{|i| i[:ip]}.join(" ")}"
|
||||||
|
end
|
||||||
|
}
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssltable
|
||||||
|
sslID="21643"
|
||||||
|
if @vulns[sslID].nil?
|
||||||
|
puts "No SSL-ports found"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
puts "IP port EXP LOW MD5 SSLv2"
|
||||||
|
@vulns[sslID].collect{|vuln|
|
||||||
|
port = vuln[:fullip].sub(/.*\(/, "").sub(/\/.*/, "")
|
||||||
|
exp = vuln[:descr].match(/Enc=[^\(]*\(40\)/)
|
||||||
|
low = vuln[:descr].match(/Enc=[^\(]*\(56\)/)
|
||||||
|
md5 = vuln[:descr].match(/Mac=MD5/)
|
||||||
|
sslv2 = vuln[:descr].match(/SSLv2/)
|
||||||
|
puts "#{vuln[:ip]} #{port} #{exp ? "X" : "-"} #{low ? "X" : "-"} #{md5 ? "X" : "-"} #{sslv2 ? "X" : "-"}"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def highestweight(nessusid)
|
||||||
|
highest = 0
|
||||||
|
@vulns[nessusid].each{|i|
|
||||||
|
highest = i[:weight] if i[:weight] > highest
|
||||||
|
}
|
||||||
|
highest
|
||||||
|
end
|
||||||
|
|
||||||
|
def readnbe(inputfile)
|
||||||
|
File.open(inputfile).each_line{|line|
|
||||||
|
sl = Array.new
|
||||||
|
sl = line.split('|', 7)
|
||||||
|
if sl[0] == "results"
|
||||||
|
next if sl[4].nil?
|
||||||
|
if ! @vulns[sl[4]].nil?
|
||||||
|
@vulns[sl[4]].push Vuln.new(sl[2], "#{sl[2]} : #{sl[3]}",
|
||||||
|
sl[6].gsub(/\\n/, "\n").gsub(/\\r/, "\r").gsub(/\\\\/, "\\"), Weight[sl[5]])
|
||||||
|
else
|
||||||
|
@vulns[sl[4]] = [ Vuln.new(sl[2], "#{sl[2]} : #{sl[3]}",
|
||||||
|
sl[6].gsub(/\\n/, "\n").gsub(/\\r/, "\r").gsub(/\\\\/, "\\"), Weight[sl[5]]) ]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def readnsr(inputfile)
|
||||||
|
File.open(inputfile).each_line{|line|
|
||||||
|
sl = Array.new
|
||||||
|
sl = line.split('|')
|
||||||
|
next if sl[3].nil?
|
||||||
|
if ! @vulns[sl[2]].nil?
|
||||||
|
@vulns[sl[2]].push Vuln.new(sl[0], "#{sl[0]} : #{sl[1]}",
|
||||||
|
sl[4].gsub(/;;/, "\n"), Weight[sl[3]])
|
||||||
|
else
|
||||||
|
@vulns[sl[2]] = [ Vuln.new(sl[0], "#{sl[0]} : #{sl[1]}",
|
||||||
|
sl[4].gsub(/;/, "\n"), Weight[sl[3]]) ]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def readnessus(inputfile)
|
||||||
|
list = XMLListener.new
|
||||||
|
source = File.new(inputfile)
|
||||||
|
REXML::Document.parse_stream(source, list)
|
||||||
|
@vulns = list.gethash
|
||||||
|
end
|
||||||
|
|
||||||
|
parse_options
|
||||||
|
|
||||||
|
if ARGV[0].nil? or ARGV[0].empty? or ! FileTest.exists?(ARGV[0])
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
|
||||||
|
# de regels in .nbe bestanden beginnen met 'timestamps|' of 'results|'
|
||||||
|
# de regels in .nsr bestanden beginnen met een IP-adres
|
||||||
|
# de regels in .nessus bestanden beginnen met een '<' (de eerste regel is: <NessusClientData>)
|
||||||
|
|
||||||
|
line = File.open(ARGV[0]).readline
|
||||||
|
|
||||||
|
if line.match(/^(timestamps|results)\|/)
|
||||||
|
readnbe(ARGV[0])
|
||||||
|
elsif line.match(/^\d+\.\d+\.\d+\.\d+/)
|
||||||
|
readnsr(ARGV[0])
|
||||||
|
elsif line.match(/^<NessusClientData>/)
|
||||||
|
readnessus(ARGV[0])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if @options["-s"]
|
||||||
|
summary(Weight['Security Hole'])
|
||||||
|
summary(Weight['Security Warning'])
|
||||||
|
summary(Weight['Security Note'])
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
if @options["-t"]
|
||||||
|
ssltable
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
if @options["-i"]
|
||||||
|
@options["-i"].split(",").each{|key|
|
||||||
|
display(key)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
@vulns.keys.sort.each{|key|
|
||||||
|
display(key) if highestweight(key) == Weight['Security Hole']
|
||||||
|
}
|
||||||
|
@vulns.keys.sort.each{|key|
|
||||||
|
display(key) if highestweight(key) == Weight['Security Warning']
|
||||||
|
}
|
||||||
|
@vulns.keys.sort.each{|key|
|
||||||
|
display(key) if highestweight(key) == Weight['Security Note']
|
||||||
|
}
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue