Skip to content

Instantly share code, notes, and snippets.

@kost
Created April 6, 2017 13:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kost/7ce2c1f73822ced9673f3da0d33110e0 to your computer and use it in GitHub Desktop.
Save kost/7ce2c1f73822ced9673f3da0d33110e0 to your computer and use it in GitHub Desktop.
Nessus
#!/usr/bin/env ruby
# Filter Nessus XML report to get services identified
# Copyright (C) Kost
require 'nokogiri'
require 'optparse'
require 'logger'
require 'csv'
$PRGNAME="nessus-services.rb"
$options = {}
$options['loglevel'] = 'WARN'
$options['logname'] = nil
# helpful class for logger
class MultiDelegator
def initialize(*targets)
@targets = targets
end
def self.delegate(*methods)
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
self
end
class <<self
alias to new
end
end
begin
optyaml = YAML::load_file(ENV['HOME']+'/.nessus-services')
rescue # Errno::ENOENT
end
if optyaml != nil then
$options.merge!(optyaml)
end
# initialize logger
if $options['logname'] != nil then
log_file = File.open($options['logname'], 'a')
@log = Logger.new MultiDelegator.delegate(:write, :close).to(STDERR, log_file)
else
@log = Logger.new MultiDelegator.delegate(:write, :close).to(STDERR)
end
loglevel = Logger.const_get $options['loglevel'] # Logger::INFO # default is ::WARN
@log.level = loglevel
# pp $options
OptionParser.new do |opts|
opts.banner = "Usage: #{$PRGNAME} [options]"
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
$options['verbose'] = v
@log.level = Logger::INFO
end
opts.on("-d", "--[no-]debug", "Run in debug mode") do |v|
$options['debug'] = v
@log.level = Logger::DEBUG
end
opts.on("-w", "--[no-]web", "output only web in schema:// format") do |optarg|
$options['web'] = optarg
end
opts.on("-c", "--[no-]csv", "output in CSV format") do |optarg|
$options['csv'] = optarg
end
opts.on("-n", "--[no-]nikto", "output in nikto format") do |optarg|
$options['nikto'] = optarg
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
opts.on("-f", "--filter NAME", "filter by service NAME") do |optarg|
$options['filter'] = optarg
end
opts.on("-l", "--log FILE", "log to FILE") do |optarg|
$options['logname'] = optarg
end
opts.separator ""
opts.separator "Example #1: #{$PRGNAME} -w report.nessus"
opts.separator "Example #2: #{$PRGNAME} -c -f ssh report.nessus"
opts.separator "Example #3: #{$PRGNAME} -n report.nessus"
end.parse!
# pp $options
# start scan
if ARGV.empty? then
@log.error("Provide at least one file to process as argument")
end
ARGV.each do |xmlfile|
xmlf=open(xmlfile)
xmldoc = Nokogiri::XML(xmlf)
xmldoc.xpath("/NessusClientData_v2/Report/ReportHost").each do |hostxml|
hostname=hostxml.attribute("name").to_s
hostxml.xpath("./ReportItem[@pluginID='22964']").each do |ri|
port=ri.attribute("port").to_s
protocol=ri.attribute("protocol").to_s
svc_name=ri.attribute("svc_name").to_s
niktossl = ''
plugin_output=ri.at_xpath("./plugin_output").content.chomp
scheme=svc_name
if svc_name == "www" then
scheme = 'http'
if plugin_output.include?("through") then
scheme = 'https'
niktossl = '-ssl'
end
if $options['web'] then
puts "#{scheme}://#{hostname}:#{port}/"
end
if $options['nikto'] then
puts "-host #{hostname} -port #{port} #{niktossl} -output nikto-#{hostname}-#{port}-#{scheme}"
end
end
if $options['filter'] and svc_name != $options['filter'] then
next
end
if $options['csv'] then
csv_string = CSV.generate do |csv|
csv << [ hostname, port, protocol, svc_name, scheme, plugin_output ]
end
puts csv_string
# puts "#{hostname};#{protocol};#{port};#{svc_name};#{scheme};#{plugin_output}"
end
end
end
xmlf.close
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment