2010-09-15 08:22:28 +00:00
|
|
|
#!/usr/bin/env ruby
|
|
|
|
# = nessus-cli.rb: Nessus command line interface for XML-RPC
|
|
|
|
# Author:: Vlatko Kosturjak
|
|
|
|
#
|
|
|
|
# (C) Vlatko Kosturjak, Kost. Distributed under GPL and BSD (dual licensed).
|
|
|
|
|
|
|
|
require 'nessus-xmlrpc'
|
|
|
|
require 'getoptlong'
|
|
|
|
|
|
|
|
verbose = 0
|
|
|
|
debug = 0
|
|
|
|
operation = ''
|
|
|
|
targets = ''
|
|
|
|
deletereport = false
|
|
|
|
user = ''
|
|
|
|
password = ''
|
|
|
|
scanname = ''
|
|
|
|
output = ''
|
|
|
|
output1 = ''
|
|
|
|
wait = ''
|
|
|
|
policy = ''
|
|
|
|
url = ''
|
|
|
|
|
|
|
|
def intro
|
|
|
|
$stderr.print $0 + ": Nessus command line interface for XML-RPC\n"
|
|
|
|
$stderr.print "(C) Vlatko Kosturjak, Kost. Distributed under GPL.\n"
|
|
|
|
$stderr.print "\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
intro
|
|
|
|
|
|
|
|
def give_help
|
|
|
|
puts <<-EOF
|
|
|
|
--user <user> user for login to Nessus server
|
|
|
|
--password <p> password for login to Nessus server
|
|
|
|
--scan <name> start scan with name
|
|
|
|
--target <ip> specify list of targets, separated by comma
|
|
|
|
--policy <pol> specify policy to use (name of policy)
|
|
|
|
--url <url> url of Nessus server (default: localhost:8834)
|
|
|
|
--wait [t] wait scan to finish (ask in regular periods of <t> for status)
|
|
|
|
--output <f> output report XML to file <f>
|
|
|
|
--output1 <f> output report XML v1 to file <f>
|
|
|
|
--reportdelete delete report after finish or delete report by id (if alone)
|
|
|
|
--stop <id> stop scan identified by <id>
|
|
|
|
--stop-all stop all scans
|
|
|
|
--pause <id> pause scan identified by <id>
|
|
|
|
--pause-all pause all scans
|
|
|
|
--resume <id> resume scan identified by <id>
|
|
|
|
--resume-all resume all scans
|
|
|
|
--report <id> download report identified by <id>
|
|
|
|
--list-scans list scans
|
|
|
|
--list-policy list policies
|
|
|
|
--status <id> get status of scan by <id>
|
|
|
|
--verbose be verbose
|
|
|
|
--debug be even more verbose
|
|
|
|
--help this help
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
#{$0} --user john --password doe --scan scan-localhost --wait --output report.xml --target localhost
|
|
|
|
EOF
|
|
|
|
exit 0
|
|
|
|
end
|
|
|
|
|
|
|
|
if ARGV.length < 1
|
|
|
|
give_help
|
|
|
|
end
|
|
|
|
|
|
|
|
opt = GetoptLong.new(
|
|
|
|
["--help", "-h", GetoptLong::NO_ARGUMENT],
|
|
|
|
["--verbose", "-v", GetoptLong::OPTIONAL_ARGUMENT],
|
|
|
|
["--target", "-t", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--user", "-u", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--policy", "-P", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--url", "-U", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--deletereport", "-D", GetoptLong::OPTIONAL_ARGUMENT],
|
|
|
|
["--wait", "-w", GetoptLong::OPTIONAL_ARGUMENT],
|
|
|
|
["--scan", "-s", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--list-scans", "-l", GetoptLong::NO_ARGUMENT],
|
|
|
|
["--list-policy", "-L", GetoptLong::NO_ARGUMENT],
|
|
|
|
["--status", "-W", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--stop", "-S", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--stop-all", "-a", GetoptLong::NO_ARGUMENT],
|
|
|
|
["--pause", "-q", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--pause-all", "-Q", GetoptLong::NO_ARGUMENT],
|
|
|
|
["--resume", "-e", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--resume-all", "-E", GetoptLong::NO_ARGUMENT],
|
|
|
|
["--report", "-r", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--output", "-o", GetoptLong::REQUIRED_ARGUMENT],
|
|
|
|
["--output1", "-1", GetoptLong::REQUIRED_ARGUMENT]
|
|
|
|
)
|
|
|
|
|
|
|
|
def give_error
|
|
|
|
$stderr.print "You used incompatible options, probably you mixed --scan with --stop"
|
|
|
|
$stderr.print "or something similar."
|
|
|
|
exit 0
|
|
|
|
end
|
|
|
|
|
|
|
|
opt.each do |opt,arg|
|
|
|
|
case opt
|
|
|
|
when '--help'
|
|
|
|
give_help
|
|
|
|
when '--user'
|
|
|
|
user = arg
|
|
|
|
when '--password'
|
|
|
|
password = arg
|
|
|
|
when '--stop'
|
|
|
|
if operation == ''
|
|
|
|
operation = "stop"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--pause'
|
|
|
|
if operation == ''
|
|
|
|
operation = "pause"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--resume'
|
|
|
|
if operation == ''
|
|
|
|
operation = "resume"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--stop-all'
|
|
|
|
if operation == ''
|
|
|
|
operation = "stop-all"
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--pause-all'
|
|
|
|
if operation == ''
|
|
|
|
operation = "pause-all"
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--resume-all'
|
|
|
|
if operation == ''
|
|
|
|
operation = "resume-all"
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--report'
|
|
|
|
if operation == ''
|
|
|
|
operation = "report"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--scan'
|
|
|
|
if operation == ''
|
|
|
|
operation = "scan"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--target'
|
|
|
|
if arg[0..6] == 'file://'
|
|
|
|
f = File.open(arg[7..-1], "r")
|
|
|
|
f.each_line do |line|
|
|
|
|
line=line.chomp
|
|
|
|
line=line.strip
|
|
|
|
unless line == '' or line == nil
|
|
|
|
if targets == ''
|
|
|
|
targets = line
|
|
|
|
else
|
|
|
|
targets = targets + "," + line
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
f.close
|
|
|
|
else
|
|
|
|
# if there's multiple target options, add comma
|
|
|
|
if targets == ''
|
|
|
|
targets = arg
|
|
|
|
|
|
|
|
else
|
|
|
|
targets = targets + "," + arg
|
|
|
|
end
|
|
|
|
end
|
|
|
|
when '--wait'
|
|
|
|
if arg == ''
|
|
|
|
wait = 15
|
|
|
|
else
|
|
|
|
wait = arg.to_i
|
|
|
|
end
|
|
|
|
when '--reportdelete'
|
2012-04-24 04:06:52 +00:00
|
|
|
if arg == ''
|
2010-09-15 08:22:28 +00:00
|
|
|
deletereport=true
|
|
|
|
else
|
|
|
|
operation = "reportdelete"
|
|
|
|
scanname = arg
|
|
|
|
end
|
|
|
|
|
|
|
|
when '--output'
|
|
|
|
output = arg
|
|
|
|
when '--output1'
|
|
|
|
output1 = arg
|
|
|
|
when '--policy'
|
|
|
|
policy = arg
|
|
|
|
when '--status'
|
|
|
|
if operation == ''
|
|
|
|
operation = "status"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--url'
|
|
|
|
url = arg
|
|
|
|
when '--verbose'
|
|
|
|
if arg == ''
|
|
|
|
verbose += 1
|
|
|
|
else
|
|
|
|
verbose = arg.to_i
|
|
|
|
end
|
|
|
|
when '--debug'
|
|
|
|
if arg == ''
|
|
|
|
debug += 1
|
|
|
|
else
|
|
|
|
debug = arg.to_i
|
|
|
|
end
|
|
|
|
when '--list-scans'
|
|
|
|
if operation == ''
|
|
|
|
operation = "list-scans"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
when '--list-policy'
|
|
|
|
if operation == ''
|
|
|
|
operation = "list-policy"
|
|
|
|
scanname = arg
|
|
|
|
else
|
|
|
|
give_error
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if (user == '') or (password == '')
|
|
|
|
$stderr.print "User and password is required to login to Nessus server"
|
|
|
|
$stderr.print "Try --help!"
|
|
|
|
exit 1
|
|
|
|
end
|
|
|
|
|
|
|
|
$stderr.print "[i] Targets: " + targets +"\n" if verbose > 0
|
|
|
|
$stderr.print "[i] Connecting to nessus server: " if verbose > 0
|
|
|
|
n=NessusXMLRPC::NessusXMLRPC.new(url,user,password)
|
|
|
|
if n.logged_in
|
|
|
|
$stderr.print "OK!\n" if verbose > 0
|
|
|
|
else
|
|
|
|
$stderr.print "[e] Error connecting/logging to the server!\n"
|
|
|
|
exit 2
|
|
|
|
end
|
|
|
|
|
|
|
|
case operation
|
|
|
|
when "scan"
|
|
|
|
if policy == ''
|
|
|
|
$stderr.print "[w] Policy not defined, using first served from the server\n"
|
|
|
|
pid,name = n.policy_get_first
|
|
|
|
$stderr.print "[w] using policy id " + pid + " with name " + name + "\n"
|
|
|
|
else
|
|
|
|
pid=n.policy_get_id(policy)
|
|
|
|
if pid == ''
|
|
|
|
$stderr.print "[e] policy doesn't exit: " + policy + "\n"
|
|
|
|
exit 3
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if targets == ''
|
|
|
|
$stderr.print "[w] Targets not defined, using localhost as target\n"
|
|
|
|
targets = '127.0.0.1'
|
|
|
|
end
|
|
|
|
$stderr.print "[i] Initiating scan with targets: "+targets+': ' if verbose > 0
|
|
|
|
uid=n.scan_new(pid,scanname,targets)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
unless wait == ''
|
|
|
|
while not n.scan_finished(uid)
|
|
|
|
$stderr.print "[v] Sleeping for " + wait.to_s() + ": " if verbose > 1
|
|
|
|
sleep wait
|
|
|
|
$stderr.print "done\n" if verbose > 1
|
|
|
|
stat = n.scan_status(uid)
|
|
|
|
print "\r" + stat if verbose > 0
|
|
|
|
end
|
|
|
|
else
|
|
|
|
puts uid
|
|
|
|
exit 0
|
|
|
|
end
|
|
|
|
unless output == ''
|
|
|
|
$stderr.print "[i] Output XML report to file: "+output if verbose > 0
|
|
|
|
content=n.report_file_download(uid)
|
|
|
|
File.open(output, 'w') {|f| f.write(content) }
|
|
|
|
$stderr.print ": done\n" if verbose > 0
|
|
|
|
end
|
|
|
|
unless output1 == ''
|
|
|
|
$stderr.print "[i] Output XML1 report to file: "+output1 if verbose > 0
|
|
|
|
content=n.report_file1_download(uid)
|
|
|
|
File.open(output, 'w') {|f| f.write(content) }
|
|
|
|
$stderr.print ": done\n" if verbose > 0
|
|
|
|
end
|
|
|
|
if deletereport
|
|
|
|
$stderr.print "[i] Deleting report: " if verbose > 0
|
|
|
|
n.report_delete(uid)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
end
|
|
|
|
when "report"
|
|
|
|
uid=scanname
|
|
|
|
if (output == '') and (output1 == '')
|
|
|
|
$stderr.print "[e] You want report, but specify filename with --output or output1\n"
|
|
|
|
end
|
|
|
|
unless output == ''
|
|
|
|
$stderr.print "[i] Output XML report to file: "+output if verbose > 0
|
|
|
|
content=n.report_file_download(uid)
|
|
|
|
File.open(output, 'w') {|f| f.write(content) }
|
|
|
|
$stderr.print ": done\n" if verbose > 0
|
|
|
|
end
|
|
|
|
unless output1 == ''
|
|
|
|
$stderr.print "[i] Output XML1 report to file: "+output1 if verbose > 0
|
|
|
|
content=n.report1_file_download(uid)
|
|
|
|
File.open(output, 'w') {|f| f.write(content) }
|
|
|
|
$stderr.print ": done\n" if verbose > 0
|
|
|
|
end
|
|
|
|
if deletereport
|
|
|
|
$stderr.print "[i] Deleting report: " if verbose > 0
|
|
|
|
n.report_delete(uid)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
end
|
|
|
|
when "stop"
|
|
|
|
$stderr.print "[i] Stopping scan: " + scanname if verbose > 0
|
|
|
|
n.scan_stop(scanname)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
when "stop-all"
|
|
|
|
$stderr.print "[i] Stopping all scans: " if verbose > 0
|
|
|
|
list=n.scan_stop_all
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
if verbose > 1
|
|
|
|
list.each {|uuid| puts "[v] Stop all: " + uuid }
|
|
|
|
end
|
|
|
|
when "pause"
|
|
|
|
$stderr.print "[i] Pausing scan: " + scanname if verbose > 0
|
|
|
|
n.scan_pause(scanname)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
when "pause-all"
|
|
|
|
$stderr.print "[i] Pausing all scans: " if verbose > 0
|
|
|
|
list=n.scan_pause_all
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
if verbose > 1
|
|
|
|
list.each {|uuid| puts "[v] Pause all: " + uuid }
|
|
|
|
end
|
|
|
|
when "resume"
|
|
|
|
$stderr.print "[i] Resuming scan: " + scanname if verbose > 0
|
|
|
|
n.scan_resume(scanname)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
when "resume-all"
|
|
|
|
$stderr.print "[i] Resuming all scans: " if verbose > 0
|
|
|
|
list=n.scan_resume_all
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
if verbose > 1
|
|
|
|
list.each {|uuid| puts "[v] Resume all: " + uuid }
|
|
|
|
end
|
|
|
|
when "reportdelete"
|
|
|
|
$stderr.print "[i] Deleting report: " + scanname if verbose > 0
|
|
|
|
n.report_delete(scanname)
|
|
|
|
$stderr.print "done\n" if verbose > 0
|
|
|
|
when "status"
|
|
|
|
puts "status: " + n.scan_status(scanname)
|
|
|
|
when "list-scans"
|
|
|
|
list=n.scan_list_hash
|
|
|
|
list.each {|scan|
|
|
|
|
puts scan['id']+":"+scan['name']+":"+ \
|
|
|
|
scan['current']+"/"+scan['total']
|
|
|
|
}
|
|
|
|
when "list-policy"
|
|
|
|
list=n.policy_list_names
|
|
|
|
list.each {|policy|
|
|
|
|
puts policy
|
|
|
|
}
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
$stderr.print "[v] End reached.\n" if verbose > 1
|