mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-16 01:21:15 +02:00
Import the OpenVAS bridge from Kost. Go see his talk: http://www.berlinsides.org/node/14
git-svn-id: file:///home/svn/framework3/trunk@11428 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
b3bfb5834e
commit
cd2088ee96
899
lib/openvas/openvas-omp.rb
Normal file
899
lib/openvas/openvas-omp.rb
Normal file
@ -0,0 +1,899 @@
|
||||
#
|
||||
# = openvas-omp.rb: communicate with OpenVAS manager over OMP
|
||||
#
|
||||
# Author:: Vlatko Kosturjak
|
||||
#
|
||||
# (C) Vlatko Kosturjak, Kost. Distributed under MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license.php
|
||||
#
|
||||
# == What is this library?
|
||||
#
|
||||
# This library is used for communication with OpenVAS manager over OMP
|
||||
# You can start, stop, pause and resume scan. Watch progress and status of
|
||||
# scan, download report, etc.
|
||||
#
|
||||
# == Requirements
|
||||
#
|
||||
# Required libraries are standard Ruby libraries: socket,timeout,openssl,
|
||||
# rexml/document, rexml/text, base64
|
||||
#
|
||||
# == Usage:
|
||||
#
|
||||
# require 'openvas-omp'
|
||||
|
||||
require 'socket'
|
||||
require 'timeout'
|
||||
require 'openssl'
|
||||
require 'rexml/document'
|
||||
require 'rexml/text'
|
||||
require 'base64'
|
||||
|
||||
# OpenVASOMP module
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# require 'openvas-omp'
|
||||
|
||||
module OpenVASOMP
|
||||
|
||||
class OMPError < :: RuntimeError
|
||||
attr_accessor :req, :reason
|
||||
def initialize(req, reason = '')
|
||||
self.req = req
|
||||
self.reason = reason
|
||||
end
|
||||
def to_s
|
||||
"OpenVAS OMP: #{self.reason}"
|
||||
end
|
||||
end
|
||||
|
||||
class OMPResponseError < OMPError
|
||||
def initialize
|
||||
self.reason = "Error in OMP request/response"
|
||||
end
|
||||
end
|
||||
|
||||
class OMPAuthError < OMPError
|
||||
def initialize
|
||||
self.reason = "Authentication failed"
|
||||
end
|
||||
end
|
||||
|
||||
class XMLParsingError < OMPError
|
||||
def initialize
|
||||
self.reason = "XML parsing failed"
|
||||
end
|
||||
end
|
||||
|
||||
# Class which uses standard REXML to parse OpenVAS replies.
|
||||
class OpenVASOMP
|
||||
# initialize object: try to connect to OpenVAS using URL, user and password
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov=OpenVASOMP.new(user=>'user',password=>'pass')
|
||||
# # default: host=>'localhost', port=>'9390'
|
||||
#
|
||||
def initialize(p={})
|
||||
if p.has_key?("host")
|
||||
@host=p["host"]
|
||||
else
|
||||
@host="localhost"
|
||||
end
|
||||
if p.has_key?("port")
|
||||
@port=p["port"]
|
||||
else
|
||||
@port=9390
|
||||
end
|
||||
if p.has_key?("user")
|
||||
@user=p["user"]
|
||||
else
|
||||
@user="openvas"
|
||||
end
|
||||
if p.has_key?("password")
|
||||
@password=p["password"]
|
||||
else
|
||||
@password="openvas"
|
||||
end
|
||||
if p.has_key?("bufsize")
|
||||
@bufsize=p["bufsize"]
|
||||
else
|
||||
@bufsize=16384
|
||||
end
|
||||
if p.has_key?("debug")
|
||||
@debug=p["debug"]
|
||||
else
|
||||
@debug=0
|
||||
end
|
||||
|
||||
if @debug>3
|
||||
puts "Host: "+@host
|
||||
puts "Port: "+@port.to_s()
|
||||
puts "User: "+@user
|
||||
end
|
||||
if @debug>99
|
||||
puts "Password: "+@password
|
||||
end
|
||||
@areq=''
|
||||
@read_timeout=3
|
||||
if defined? p["noautoconnect"] and not p["noautoconnect"]
|
||||
connect()
|
||||
if defined? p["noautologin"] and not p["noautologin"]
|
||||
login()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Sets debug level
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.debug(3)
|
||||
#
|
||||
def debug (level)
|
||||
@debug=level
|
||||
end
|
||||
|
||||
# Low level method - Connect to SSL socket
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.connect()
|
||||
#
|
||||
def connect
|
||||
@plain_socket=TCPSocket.open(@host, @port)
|
||||
ssl_context = OpenSSL::SSL::SSLContext.new()
|
||||
@socket = OpenSSL::SSL::SSLSocket.new(@plain_socket, ssl_context)
|
||||
@socket.sync_close = true
|
||||
@socket.connect
|
||||
end
|
||||
|
||||
# Low level method - Disconnect SSL socket
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.disconnect()
|
||||
#
|
||||
def disconnect
|
||||
if @socket
|
||||
@socket.close
|
||||
end
|
||||
end
|
||||
|
||||
# Low level method: Send request and receive response - socket
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.connect();
|
||||
# puts ov.sendrecv("<get_version/>")
|
||||
# ov.disconnect();
|
||||
#
|
||||
def sendrecv (tosend)
|
||||
if not @socket
|
||||
connect
|
||||
end
|
||||
|
||||
if @debug>3 then
|
||||
puts "SENDING: "+tosend
|
||||
end
|
||||
@socket.puts(tosend)
|
||||
|
||||
@rbuf=''
|
||||
size=0
|
||||
begin
|
||||
begin
|
||||
timeout(@read_timeout) {
|
||||
a = @socket.sysread(@bufsize)
|
||||
size=a.length
|
||||
# puts "sysread #{size} bytes"
|
||||
@rbuf << a
|
||||
}
|
||||
rescue Timeout::Error
|
||||
size=0
|
||||
rescue EOFError
|
||||
raise OMPResponseError
|
||||
end
|
||||
end while size>=@bufsize
|
||||
response=@rbuf
|
||||
|
||||
if @debug>3 then
|
||||
puts "RECEIVED: "+response
|
||||
end
|
||||
return response
|
||||
end
|
||||
|
||||
# get OMP version (you don't need to be authenticated)
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.version_get()
|
||||
#
|
||||
def version_get
|
||||
vreq="<get_version/>"
|
||||
resp=sendrecv(vreq)
|
||||
resp = "<X>"+resp+"</X>"
|
||||
begin
|
||||
docxml = REXML::Document.new(resp)
|
||||
version=''
|
||||
version=docxml.root.elements['get_version_response'].elements['version'].text
|
||||
return version
|
||||
rescue
|
||||
raise XMLParsingError
|
||||
end
|
||||
end
|
||||
|
||||
# produce single XML element with attributes specified as hash
|
||||
# low-level function
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.xml_attr()
|
||||
#
|
||||
def xml_attr(name, opts={})
|
||||
xml = REXML::Element.new(name)
|
||||
opts.keys.each do |k|
|
||||
xml.attributes[k] = opts[k]
|
||||
end
|
||||
return xml
|
||||
end
|
||||
|
||||
# produce multiple XML elements with text specified as hash
|
||||
# low-level function
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.xml_ele()
|
||||
#
|
||||
def xml_ele(name, child={})
|
||||
xml = REXML::Element.new(name)
|
||||
child.keys.each do |k|
|
||||
xml.add_element(k)
|
||||
xml.elements[k].text = child[k]
|
||||
end
|
||||
return xml
|
||||
end
|
||||
|
||||
# produce multiple XML elements with text specified as hash
|
||||
# also produce multiple XML elements with attributes
|
||||
# low-level function
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.xml_mix()
|
||||
#
|
||||
def xml_mix(name, child, attr, elem)
|
||||
xml = REXML::Element.new(name)
|
||||
child.keys.each do |k|
|
||||
xml.add_element(k)
|
||||
xml.elements[k].text = child[k]
|
||||
end
|
||||
elem.keys.each do |k|
|
||||
xml.add_element(k)
|
||||
xml.elements[k].attributes[attr] = elem[k]
|
||||
end
|
||||
return xml
|
||||
end
|
||||
|
||||
# login to OpenVAS server.
|
||||
# if successful returns authentication XML for further usage
|
||||
# if unsuccessful returns empty string
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.login()
|
||||
#
|
||||
def login
|
||||
areq="<authenticate>"+xml_ele("credentials", {"username"=>@user, "password"=>@password}).to_s()+"</authenticate>"
|
||||
resp=sendrecv(areq+"<HELP/>")
|
||||
# wrap it inside tags, so rexml does not complain
|
||||
resp = "<X>"+resp+"</X>"
|
||||
|
||||
begin
|
||||
docxml = REXML::Document.new(resp)
|
||||
status=docxml.root.elements['authenticate_response'].attributes['status'].to_i()
|
||||
rescue
|
||||
raise XMLParsingError
|
||||
end
|
||||
if status == 200
|
||||
@areq=areq
|
||||
else
|
||||
raise OMPAuthError
|
||||
end
|
||||
end
|
||||
|
||||
# check if we're successful logged in
|
||||
# if successful returns true
|
||||
# if unsuccessful returns false
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# if ov.logged_in() then
|
||||
# puts "logged in"
|
||||
# end
|
||||
#
|
||||
def logged_in
|
||||
if @areq == ''
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# logout from OpenVAS server.
|
||||
# it actually just sets internal authentication XML to empty str
|
||||
# (as in OMP you have to send username/password each time)
|
||||
# (i.e. there is no session id)
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.logout()
|
||||
#
|
||||
def logout
|
||||
disconnect()
|
||||
@areq = ''
|
||||
end
|
||||
|
||||
# OMP low level method - Send string request wrapped with
|
||||
# authentication XML and return response as string
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.request_xml("<HELP/")
|
||||
#
|
||||
def omp_request_raw (request)
|
||||
resp=sendrecv(@areq+request)
|
||||
return resp
|
||||
end
|
||||
|
||||
# OMP low level method - Send string request wrapped with
|
||||
# authentication XML and return REXML parsed object
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# rexmlobject = ov.request_xml("<HELP/")
|
||||
#
|
||||
def omp_request_xml (request)
|
||||
resp=sendrecv(@areq+request)
|
||||
resp = "<X>"+resp+"</X>"
|
||||
|
||||
begin
|
||||
docxml = REXML::Document.new(resp)
|
||||
status=docxml.root.elements['authenticate_response'].attributes['status'].to_i
|
||||
if status<200 and status>299
|
||||
raise OMPAuthError
|
||||
end
|
||||
return docxml.root
|
||||
rescue
|
||||
raise XMLParsingError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - Create target for scanning
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# target_id = ov.target_create("name"=>"localhost",
|
||||
# "hosts"=>"127.0.0.1","comment"=>"yes")
|
||||
#
|
||||
def target_create (p={})
|
||||
xmlreq=xml_ele("create_target", p).to_s()
|
||||
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
id=xr.elements['create_target_response'].attributes['id']
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return id
|
||||
end
|
||||
|
||||
# OMP - Delete target
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.target_delete(target_id)
|
||||
#
|
||||
def target_delete (id)
|
||||
xmlreq=xml_attr("delete_task",{"target_id" => id}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - Get target for scanning and returns rexml object
|
||||
#
|
||||
# Usage:
|
||||
# rexmlobject = target_get_raw("target_id"=>target_id)
|
||||
#
|
||||
def target_get_raw (p={})
|
||||
xmlreq=xml_attr("get_targets", p).to_s()
|
||||
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
return xr
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - Get all targets for scanning and returns array of hashes
|
||||
# with following keys: id,name,comment,hosts,max_hosts,in_use
|
||||
#
|
||||
# Usage:
|
||||
# array_of_hashes = target_get_all()
|
||||
#
|
||||
def target_get_all (p={})
|
||||
begin
|
||||
xr=target_get_raw(p)
|
||||
list=Array.new
|
||||
xr.elements.each('//get_targets_response/target') do |target|
|
||||
td=Hash.new
|
||||
td["id"]=target.attributes["id"]
|
||||
td["name"]=target.elements["name"].text
|
||||
td["comment"]=target.elements["comment"].text
|
||||
td["hosts"]=target.elements["hosts"].text
|
||||
td["max_hosts"]=target.elements["max_hosts"].text
|
||||
td["in_use"]=target.elements["in_use"].text
|
||||
list.push td
|
||||
end
|
||||
return list
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
def target_get_byid (id)
|
||||
begin
|
||||
xr=target_get_raw("target_id"=>id)
|
||||
xr.elements.each('//get_targets_response/target') do |target|
|
||||
td=Hash.new
|
||||
td["id"]=target.attributes["id"]
|
||||
td["name"]=target.elements["name"].text
|
||||
td["comment"]=target.elements["comment"].text
|
||||
td["hosts"]=target.elements["hosts"].text
|
||||
td["max_hosts"]=target.elements["max_hosts"].text
|
||||
td["in_use"]=target.elements["in_use"].text
|
||||
return td
|
||||
end
|
||||
return list
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - get reports and returns raw rexml object as response
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# rexmlobject=ov.report_get_raw("format"=>"PDF")
|
||||
#
|
||||
# rexmlobject=ov.report_get_raw(
|
||||
# "report_id" => "",
|
||||
# "format"=>"PDF")
|
||||
#
|
||||
def report_get_raw (p={})
|
||||
xmlreq=xml_attr("get_reports",p).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - get report by id and format, returns report
|
||||
# (already base64 decoded if needed)
|
||||
#
|
||||
# format can be: HTML, NBE, PDF, ...
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# pdf_content=ov.report_get_byid(id,"PDF")
|
||||
# File.open('report.pdf', 'w') {|f| f.write(pdf_content) }
|
||||
#
|
||||
def report_get_byid (id,format)
|
||||
decode=Array["HTML","NBE","PDF"]
|
||||
xr=report_get_raw("report_id"=>id,"format"=>format)
|
||||
resp=xr.elements['get_reports_response'].elements['report'].text
|
||||
if decode.include?(format)
|
||||
resp=Base64.decode64(resp)
|
||||
end
|
||||
return resp
|
||||
end
|
||||
|
||||
# OMP - get report all, returns report
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# pdf_content=ov.report_get_all()
|
||||
#
|
||||
def report_get_all ()
|
||||
begin
|
||||
xr=report_get_raw("format"=>"NBE")
|
||||
list=Array.new
|
||||
xr.elements.each('//get_reports_response/report') do |report|
|
||||
td=Hash.new
|
||||
td["id"]=target.attributes["id"]
|
||||
td["name"]=target.elements["name"].text
|
||||
td["comment"]=target.elements["comment"].text
|
||||
td["hosts"]=target.elements["hosts"].text
|
||||
td["max_hosts"]=target.elements["max_hosts"].text
|
||||
td["in_use"]=target.elements["in_use"].text
|
||||
list.push td
|
||||
end
|
||||
return list
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - get reports and returns raw rexml object as response
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# rexmlobject=ov.result_get_raw("notes"=>0)
|
||||
#
|
||||
def result_get_raw (p={})
|
||||
begin
|
||||
xmlreq=xml_attr("get_results",p).to_s()
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - get configs and returns rexml object as response
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# rexmldocument=ov.config_get_raw()
|
||||
#
|
||||
def config_get_raw (p={})
|
||||
xmlreq=xml_attr("get_configs",p).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
return xr
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# OMP - get configs and returns hash as response
|
||||
# hash[config_id]=config_name
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# array_of_hashes=ov.config_get_all()
|
||||
#
|
||||
def config_get_all (p={})
|
||||
begin
|
||||
xr=config_get_raw(p)
|
||||
tc=Array.new
|
||||
xr.elements.each('//get_configs_response/config') do |config|
|
||||
c=Hash.new
|
||||
c["id"]=config.attributes["id"]
|
||||
c["name"]=config.elements["name"].text
|
||||
c["comment"]=config.elements["comment"].text
|
||||
tc.push c
|
||||
end
|
||||
return tc
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# OMP - get configs and returns hash as response
|
||||
# hash[config_id]=config_name
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# all_configs_hash=ov.config.get()
|
||||
#
|
||||
# config_id=ov.config_get().index("Full and fast")
|
||||
#
|
||||
def config_get (p={})
|
||||
begin
|
||||
xr=config_get_raw(p)
|
||||
list=Hash.new
|
||||
xr.elements.each('//get_configs_response/config') do |config|
|
||||
id=config.attributes["id"]
|
||||
name=config.elements["name"].text
|
||||
list[id]=name
|
||||
end
|
||||
return list
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# OMP - copy config with new name and returns new id
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# new_config_id=config_copy(config_id,"new_name");
|
||||
#
|
||||
def config_copy (config_id,name)
|
||||
xmlreq=xml_attr("create_config",
|
||||
{"copy"=>config_id,"name"=>name}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
id=xr.elements['create_config_response'].attributes['id']
|
||||
return id
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - create config with specified RC file and returns new id
|
||||
# name = name of new config
|
||||
# rcfile = base64 encoded OpenVAS rcfile
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# config_id=config_create("name",rcfile);
|
||||
#
|
||||
def config_create (name,rcfile)
|
||||
xmlreq=xml_attr("create_config",
|
||||
{"name"=>name,"rcfile"=>rcfile}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
id=xr.elements['create_config_response'].attributes['id']
|
||||
return id
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - creates task and returns id of created task
|
||||
#
|
||||
# Parameters which usually fit in p hash and i hash:
|
||||
# p = name,comment,rcfile
|
||||
# i = config,target,escalator,schedule
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# task_id=ov.task_create_raw()
|
||||
#
|
||||
def task_create_raw (p={}, i={})
|
||||
xmlreq=xml_mix("create_task",p,"id",i).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
id=xr.elements['create_task_response'].attributes['id']
|
||||
return id
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - creates task and returns id of created task
|
||||
#
|
||||
# parameters = name,comment,rcfile,config,target,escalator,
|
||||
# schedule
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# config_id=o.config_get().index("Full and fast")
|
||||
# target_id=o.target_create(
|
||||
# {"name"=>"localtarget", "hosts"=>"127.0.0.1", "comment"=>"t"})
|
||||
# task_id=ov.task_create(
|
||||
# {"name"=>"testlocal","comment"=>"test", "target"=>target_id,
|
||||
# "config"=>config_id}
|
||||
#
|
||||
def task_create (p={})
|
||||
specials=Array["config","target","escalator","schedule"]
|
||||
ids = Hash.new
|
||||
specials.each do |spec|
|
||||
if p.has_key?(spec)
|
||||
ids[spec]=p[spec]
|
||||
p.delete(spec)
|
||||
end
|
||||
end
|
||||
return task_create_raw(p,ids)
|
||||
end
|
||||
|
||||
# OMP - deletes task specified by task_id
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.task_delete(task_id)
|
||||
#
|
||||
def task_delete (task_id)
|
||||
xmlreq=xml_attr("delete_task",{"task_id" => task_id}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - get task and returns raw rexml object as response
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# rexmlobject=ov.task_get_raw("details"=>"0")
|
||||
#
|
||||
def task_get_raw (p={})
|
||||
xmlreq=xml_attr("get_tasks",p).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
return xr
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - get all tasks and returns array with hashes with
|
||||
# following content:
|
||||
# id,name,comment,status,progress,first_report,last_report
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# array_of_hashes=ov.task_get_all()
|
||||
#
|
||||
def task_get_all (p={})
|
||||
xr=task_get_raw(p)
|
||||
t=Array.new
|
||||
xr.elements.each('//get_tasks_response/task') do |task|
|
||||
td=Hash.new
|
||||
td["id"]=task.attributes["id"]
|
||||
td["name"]=task.elements["name"].text
|
||||
td["comment"]=task.elements["comment"].text
|
||||
td["status"]=task.elements["status"].text
|
||||
td["progress"]=task.elements["progress"].text
|
||||
if defined? task.elements["first_report"].elements["report"].attributes["id"] then
|
||||
td["firstreport"]=task.elements["first_report"].elements["report"].attributes["id"]
|
||||
else
|
||||
td["firstreport"]=nil
|
||||
end
|
||||
if defined? task.elements["last_report"].elements["report"].attributes["id"] then
|
||||
td["lastreport"]=task.elements["last_report"].elements["report"].attributes["id"]
|
||||
else
|
||||
td["lastreport"]=nil
|
||||
end
|
||||
t.push td
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
# OMP - get task specified by task_id and returns hash with
|
||||
# following content:
|
||||
# id,name,comment,status,progress,first_report,last_report
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# hash=ov.task_get_byid(task_id)
|
||||
#
|
||||
def task_get_byid (id)
|
||||
xr=task_get_raw("task_id"=>id,"details"=>0)
|
||||
xr.elements.each('//get_tasks_response/task') do |task|
|
||||
td=Hash.new
|
||||
td["id"]=task.attributes["id"]
|
||||
td["name"]=task.elements["name"].text
|
||||
td["comment"]=task.elements["comment"].text
|
||||
td["status"]=task.elements["status"].text
|
||||
td["progress"]=task.elements["progress"].text
|
||||
if defined? task.elements["first_report"].elements["report"].attributes["id"] then
|
||||
td["firstreport"]=task.elements["first_report"].elements["report"].attributes["id"]
|
||||
else
|
||||
td["firstreport"]=nil
|
||||
end
|
||||
if defined? task.elements["last_report"].elements["report"].attributes["id"] then
|
||||
td["lastreport"]=task.elements["last_report"].elements["report"].attributes["id"]
|
||||
else
|
||||
td["lastreport"]=nil
|
||||
end
|
||||
return (td)
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - check if task specified by task_id is finished
|
||||
# (it checks if task status is "Done" in OMP)
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# if ov.task_finished(task_id)
|
||||
# puts "Task finished"
|
||||
# end
|
||||
#
|
||||
def task_finished (id)
|
||||
xr=task_get_raw("task_id"=>id,"details"=>0)
|
||||
xr.elements.each('//get_tasks_response/task') do |task|
|
||||
if status=task.elements["status"].text == "Done"
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - check progress of task specified by task_id
|
||||
# (OMP returns -1 if task is finished, not started, etc)
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# print "Progress: "
|
||||
# puts ov.task_progress(task_id)
|
||||
#
|
||||
def task_progress (id)
|
||||
xr=task_get_raw("task_id"=>id,"details"=>0)
|
||||
xr.elements.each('//get_tasks_response/task') do |task|
|
||||
return task.elements["progress"].text.to_i()
|
||||
end
|
||||
end
|
||||
|
||||
# OMP - starts task specified by task_id
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.task_start(task_id)
|
||||
#
|
||||
def task_start (task_id)
|
||||
xmlreq=xml_attr("start_task",{"task_id" => task_id}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - stops task specified by task_id
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.task_stop(task_id)
|
||||
#
|
||||
def task_stop (task_id)
|
||||
xmlreq=xml_attr("stop_task",{"task_id" => task_id}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - pauses task specified by task_id
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.task_pause(task_id)
|
||||
#
|
||||
def task_pause (task_id)
|
||||
xmlreq=xml_attr("pause_task",{"task_id" => task_id}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
# OMP - resumes (or starts) task specified by task_id
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ov.task_resume_or_start(task_id)
|
||||
#
|
||||
def task_resume_or_start (task_id)
|
||||
xmlreq=xml_attr("resume_or_start_task",{"task_id" => task_id}).to_s()
|
||||
begin
|
||||
xr=omp_request_xml(xmlreq)
|
||||
rescue
|
||||
raise OMPResponseError
|
||||
end
|
||||
return xr
|
||||
end
|
||||
|
||||
end # end of Class
|
||||
|
||||
end # of Module
|
||||
|
737
plugins/openvas.rb
Normal file
737
plugins/openvas.rb
Normal file
@ -0,0 +1,737 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# This plugin provides integration with OpenVAS. Written by kost.
|
||||
# Distributed under MIT license:
|
||||
# http://www.opensource.org/licenses/mit-license.php
|
||||
#
|
||||
# Typical usage:
|
||||
# load openvas
|
||||
# db_create
|
||||
# openvas_connect test test localhost 9390 ok
|
||||
# openvas_scan localhost
|
||||
|
||||
require 'openvas/openvas-omp'
|
||||
|
||||
module Msf
|
||||
class Plugin::OpenVAS < Msf::Plugin
|
||||
class OpenVASCommandDispatcher
|
||||
include Msf::Ui::Console::CommandDispatcher
|
||||
|
||||
def name
|
||||
"OpenVAS"
|
||||
end
|
||||
|
||||
def commands
|
||||
{
|
||||
'openvas_help' => "Displays help",
|
||||
'openvas_connect' => "Connect to a OpenVAS manager using OMP ( user:pass@host[:port] )",
|
||||
'openvas_task_list' => "Display list of tasks",
|
||||
'openvas_task_create' => "Creates task (name, comment, target, config)",
|
||||
'openvas_task_start' => "Start task by ID",
|
||||
'openvas_task_stop' => "Stop task by ID",
|
||||
'openvas_task_pause' => "Pause task by ID",
|
||||
'openvas_task_resume' => "Resume task by ID",
|
||||
'openvas_task_resume_or_start' => "Resume task or start task by ID",
|
||||
'openvas_task_status' => "Get status of task ID",
|
||||
'openvas_task_delete' => "Delete task by ID",
|
||||
|
||||
'openvas_target_create' => "Create target (name, hosts, comment)",
|
||||
'openvas_target_list' => "Display list of targets",
|
||||
'openvas_target_delete' => "Delete target by ID",
|
||||
|
||||
'openvas_config_list' => "Quickly display list of configs",
|
||||
'openvas_report_import' => "Import report specified by ID to framework",
|
||||
'openvas_report_save' => "Save report specified by ID and format to file",
|
||||
|
||||
'openvas_scan' => "Launch an automatic OpenVAS scan against a specific IP range and import the results",
|
||||
|
||||
'openvas_debug' => "Sets debug level",
|
||||
'openvas_disconnect' => "Disconnect from OpenVAS manager",
|
||||
|
||||
}
|
||||
end
|
||||
|
||||
def cmd_openvas_help (*args)
|
||||
usage="
|
||||
openvas_help Display this help
|
||||
|
||||
CONNECTION
|
||||
==========
|
||||
openvas_connect Connects to OpenVAS
|
||||
openvas_disconnect Disconnects from OpenVAS
|
||||
|
||||
TARGETS
|
||||
=======
|
||||
openvas_target_list Lists targets
|
||||
openvas_target_create Create target
|
||||
openvas_target_delete Deletes target specified by ID
|
||||
|
||||
TASKS
|
||||
=====
|
||||
openvas_task_list Lists tasks
|
||||
openvas_task_create Create task
|
||||
openvas_task_start Starts task specified by ID
|
||||
openvas_task_stop Stops task specified by ID
|
||||
openvas_task_pause Pauses task specified by ID
|
||||
openvas_task_resume Resumes task specified by ID
|
||||
openvas_task_resume_or_start Resumes or starts task specified by ID
|
||||
|
||||
CONFIGS
|
||||
=======
|
||||
openvas_config_list Lists configs
|
||||
|
||||
REPORTS
|
||||
=======
|
||||
openvas_report_import Imports OpenVAS report in framework spec. by ID
|
||||
openvas_report_save Saves OpenVAS report specified by ID and format
|
||||
|
||||
AUTO
|
||||
====
|
||||
openvas_scan Launch an automatic OpenVAS scan against a specific IP range and import the results automatically with optional autopwn
|
||||
"
|
||||
print_status(usage)
|
||||
end
|
||||
|
||||
def openvas_verify
|
||||
if ! @ov
|
||||
print_error("No active OpenVAS instance has been configured, please use 'openvas_connect'")
|
||||
return false
|
||||
end
|
||||
|
||||
if ! (framework.db and framework.db.usable)
|
||||
print_error("No database has been configured, please use db_create/db_connect first")
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def cmd_openvas_debug(*args)
|
||||
usagecmd="openvas_debug <level>
|
||||
Example: openvas_debug 99"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
level=args[0]
|
||||
@ov.debug(level)
|
||||
print_good("Command completed successfuly: "+level)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_start(*args)
|
||||
usagecmd="openvas_task_start <id>
|
||||
Example: openvas_task_start 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.task_start(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_create(*args)
|
||||
usagecmd="openvas_task_create <name> <comment> <config_id> <target_id>
|
||||
Example: openvas_task_create newtask MyNewTask abc12345-a234-46a1-c01c-123456789012 9abc0790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length != 4 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=@ov.task_create({"name"=>args[0],"comment"=>arg[1],"config"=>args[2],"target"=>args[3]})
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_stop(*args)
|
||||
usagecmd="openvas_task_stop <id>
|
||||
Example: openvas_task_stop 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.task_stop(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_pause(*args)
|
||||
usagecmd="openvas_task_pause <id>
|
||||
Example: openvas_task_pause 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.task_pause(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_resume(*args)
|
||||
usagecmd="openvas_task_resume <id>
|
||||
Example: openvas_task_resume 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.task_resume(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_resume_or_start(*args)
|
||||
usagecmd="openvas_task_resume_or_start <id>
|
||||
Example: openvas_task_resume_or_start 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.task_resume_or_start(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_delete(*args)
|
||||
usagecmd="openvas_task_delete <id>
|
||||
Example: openvas_task_delete 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.task_delete(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_status(*args)
|
||||
usagecmd="openvas_task_status <id>
|
||||
Example: openvas_task_status 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if (args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Columns' =>
|
||||
[ "ID", "Name", "Status", "Progress", "Comment","First Report","Last Report" ]
|
||||
)
|
||||
@ov.task_get_all("task_id"=>id).each do |task|
|
||||
tbl << [ task["id"] , task["name"] ,
|
||||
task["status"],
|
||||
task["progress"],
|
||||
task["comment"],
|
||||
task["firstreport"],
|
||||
task["lastreport"]
|
||||
]
|
||||
end
|
||||
print_good("OpenVAS task status")
|
||||
puts "\n"
|
||||
puts tbl.to_s + "\n"
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_task_list(*args)
|
||||
usagecmd="openvas_task_list [id]
|
||||
Example: openvas_task_list
|
||||
Example: openvas_task_list 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if (args[0] == "-h") then
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
if not (args.length == 0 or args[0].empty?) then
|
||||
id=args[0]
|
||||
end
|
||||
begin
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Columns' =>
|
||||
[ "ID", "Name", "Status", "Progress" ]
|
||||
)
|
||||
p={}
|
||||
if id
|
||||
p={"task_id"=>id}
|
||||
end
|
||||
@ov.task_get_all(p).each do |task|
|
||||
tbl << [ task["id"] , task["name"] ,
|
||||
task["status"] , task["progress"] ]
|
||||
end
|
||||
print_good("OpenVAS list of tasks")
|
||||
puts "\n"
|
||||
puts tbl.to_s + "\n"
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_target_list(*args)
|
||||
usagecmd="openvas_target_list [id]
|
||||
Example: openvas_target_list
|
||||
Example: openvas_target_list 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if (args[0] == "-h") then
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
if not (args.length == 0 or args[0].empty?) then
|
||||
id=args[0]
|
||||
end
|
||||
begin
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Columns' => [ "ID","Name","Hosts" ])
|
||||
p={}
|
||||
if id
|
||||
p={"target_id"=>id}
|
||||
end
|
||||
@ov.target_get_all(p).each do |target|
|
||||
tbl << [target["id"],
|
||||
target["name"],
|
||||
target["hosts"] ]
|
||||
end
|
||||
print_good("OpenVAS list of targets")
|
||||
puts "\n"
|
||||
puts tbl.to_s + "\n"
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_target_create(*args)
|
||||
usagecmd="openvas_target_create <name> <hosts> <comment>
|
||||
|
||||
Example: openvas_target_create mylocalhost 127.0.0.1 MyLocalHostComment"
|
||||
return if not openvas_verify
|
||||
if(args.length != 3 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=@ov.target_create({"name"=>args[0],"comment"=>arg[2],"hosts"=>args[1]})
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_target_delete(*args)
|
||||
usagecmd="openvas_target_delete <id>
|
||||
Example: openvas_target_delete 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
@ov.target_delete(id)
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_connect(*args)
|
||||
usagecmd = "Usage:
|
||||
openvas_connect username:password@host[:port] <ssl-confirm>
|
||||
-OR-
|
||||
openvas_connect username password host port <ssl-confirm>"
|
||||
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
|
||||
user = pass = host = port = sslv = nil
|
||||
|
||||
case args.length
|
||||
when 1,2
|
||||
cred,targ = args[0].split('@', 2)
|
||||
user,pass = cred.split(':', 2)
|
||||
targ ||= '127.0.0.1:9390'
|
||||
host,port = targ.split(':', 2)
|
||||
port ||= '9390'
|
||||
sslv = args[1]
|
||||
when 4,5
|
||||
user,pass,host,port,sslv = args
|
||||
else
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if ! ((user and user.length > 0) and (host and host.length > 0) and (port and port.length > 0 and port.to_i > 0) and (pass and pass.length > 0))
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
|
||||
# taken from NeXpose WARNING
|
||||
if(host != "localhost" and host != "127.0.0.1" and sslv != "ok")
|
||||
print_error("Warning: SSL connections are not verified in this release, it is possible for an attacker")
|
||||
print_error(" with the ability to man-in-the-middle the OpenVAS traffic to capture the OpenVAS")
|
||||
print_error(" credentials. If you are running this on a trusted network, please pass in 'ok'")
|
||||
print_error(" as an additional parameter to this command.")
|
||||
return
|
||||
end
|
||||
|
||||
# Wrap this so a duplicate session doesnt prevent a new login
|
||||
begin
|
||||
cmd_openvas_disconnect
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception
|
||||
end
|
||||
|
||||
begin
|
||||
print_status("Connecting to OpenVAS instance at #{host}:#{port} with username #{user}...")
|
||||
ov = OpenVASOMP::OpenVASOMP.new("user"=>user,"password"=>pass,"host"=>host,"port"=>port)
|
||||
rescue OpenVASOMP::OMPAuthError => e
|
||||
print_error("Connection failed: #{e.reason}")
|
||||
return
|
||||
end
|
||||
|
||||
@ov = ov
|
||||
end
|
||||
|
||||
def cmd_openvas_config_list(*args)
|
||||
usagecmd="openvas_config_list [id]
|
||||
Example: openvas_config_list
|
||||
Example: openvas_config_list 9fd90790-a79b-49e0-b08e-6912afde72f4"
|
||||
return if not openvas_verify
|
||||
if (args[0] == "-h") then
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
if not (args.length == 0 or args[0].empty?) then
|
||||
id=args[0]
|
||||
end
|
||||
begin
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Columns' =>
|
||||
[ "ID", "Name", "Comments" ]
|
||||
)
|
||||
p={}
|
||||
if id
|
||||
p={"config_id"=>id}
|
||||
end
|
||||
@ov.config_get_all(p).each do |config|
|
||||
tbl << [ config["id"], config["name"],
|
||||
config["comment"] ]
|
||||
end
|
||||
print_good("OpenVAS list of configs")
|
||||
puts "\n"
|
||||
puts tbl.to_s + "\n"
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_report_import(*args)
|
||||
usagecmd="openvas_report_import <id>
|
||||
Example: openvas_report_import 9fd90790-a79b-49e0-b08e-6912afde72f4
|
||||
Note: gets NBE report from the OpenVAS and tries to import it into framework
|
||||
"
|
||||
return if not openvas_verify
|
||||
if(args.length == 0 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
content=@ov.report_get_byid(id,'NBE')
|
||||
framework.db.import({:data => content})
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_report_save(*args)
|
||||
usagecmd="openvas_report_save <id> <format> <file>
|
||||
Example: openvas_report_save 9fd90790-a79b-49e0-b08e-6912afde72f4 PDF /tmp/a.pdf"
|
||||
return if not openvas_verify
|
||||
if(args.length != 3 or args[0].empty? or args[0] == "-h")
|
||||
print_status(usagecmd)
|
||||
return
|
||||
end
|
||||
begin
|
||||
id=args[0]
|
||||
content=@ov.report_get_byid(id,args[1])
|
||||
File.open(args[2], 'w') {|f| f.write(content) }
|
||||
print_good("Command completed successfuly: "+id)
|
||||
rescue ::Exception
|
||||
print_error("Error executing")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_scan(*args)
|
||||
opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "This help menu"],
|
||||
"-t" => [ true, "The scan template to use (default:Full and fast )"],
|
||||
"-P" => [ false, "Leave the scan data on the server when it completes (this counts against the maximum licensed IPs)"],
|
||||
"-x" => [ false, "Automatically launch all exploits by matching reference after the scan completes (unsafe)"],
|
||||
"-X" => [ false, "Automatically launch all exploits by matching reference and port after the scan completes (unsafe)"],
|
||||
"-d" => [ false, "Scan hosts based on the contents of the existing database"],
|
||||
"-v" => [ false, "Display diagnostic information about the scanning process"],
|
||||
"-I" => [ true, "Only scan systems with an address within the specified range"],
|
||||
"-E" => [ true, "Exclude hosts in the specified range from the scan"],
|
||||
"-R" => [ true, "Specify a minimum exploit rank to use for automated exploitation"]
|
||||
)
|
||||
|
||||
opt_template = "Full and fast"
|
||||
opt_verbose = false
|
||||
opt_preserve = false
|
||||
opt_autopwn = false
|
||||
opt_rescandb = false
|
||||
opt_addrinc = nil
|
||||
opt_addrexc = nil
|
||||
opt_scanned = []
|
||||
opt_minrank = "manual"
|
||||
|
||||
opt_ranges = []
|
||||
|
||||
opts.parse(args) do |opt, idx, val|
|
||||
case opt
|
||||
when "-h"
|
||||
print_line("Usage: openvas_scan [options] <Target IP Ranges>")
|
||||
print_line(opts.usage)
|
||||
return
|
||||
when "-v"
|
||||
opt_verbose = true
|
||||
when "-t"
|
||||
opt_template = val
|
||||
when "-P"
|
||||
opt_preserve = true
|
||||
when "-X"
|
||||
opt_autopwn = "-p -x"
|
||||
when "-x"
|
||||
opt_autopwn = "-x" unless opt_autopwn
|
||||
when "-d"
|
||||
opt_rescandb = true
|
||||
when '-I'
|
||||
opt_addrinc = OptAddressRange.new('TEMPRANGE', [ true, '' ]).normalize(val)
|
||||
when '-E'
|
||||
opt_addrexc = OptAddressRange.new('TEMPRANGE', [ true, '' ]).normalize(val)
|
||||
else
|
||||
opt_ranges << val
|
||||
end
|
||||
end
|
||||
|
||||
return if not openvas_verify
|
||||
|
||||
# Include all database hosts as scan targets if specified
|
||||
if(opt_rescandb)
|
||||
print_status("Loading scan targets from the active database...") if opt_verbose
|
||||
framework.db.hosts.each do |host|
|
||||
next if host.state != ::Msf::HostState::Alive
|
||||
opt_ranges << host.address
|
||||
end
|
||||
end
|
||||
|
||||
opt_ranges = opt_ranges.join(',')
|
||||
|
||||
if(opt_ranges.strip.empty?)
|
||||
print_line("Usage: openvas_scan [options] <Target IP Ranges>")
|
||||
print_line(opts.usage)
|
||||
return
|
||||
end
|
||||
|
||||
if(opt_verbose)
|
||||
print_status("Creating a new scan using config #{opt_template} against #{opt_ranges}")
|
||||
end
|
||||
|
||||
range_inp = ::Msf::OptAddressRange.new('TEMPRANGE', [ true, '' ]).normalize(opt_ranges)
|
||||
range = ::Rex::Socket::RangeWalker.new(range_inp)
|
||||
include_range = opt_addrinc ? ::Rex::Socket::RangeWalker.new(opt_addrinc) : nil
|
||||
exclude_range = opt_addrexc ? ::Rex::Socket::RangeWalker.new(opt_addrexc) : nil
|
||||
|
||||
completed = 0
|
||||
total = range.num_ips
|
||||
count = 0
|
||||
|
||||
print_status("Scanning #{total} addresses with config #{opt_template}")
|
||||
|
||||
while(completed < total)
|
||||
count += 1
|
||||
queue = []
|
||||
|
||||
while(ip = range.next_ip )
|
||||
|
||||
if(exclude_range and exclude_range.include?(ip))
|
||||
print_status(" >> Skipping host #{ip} due to exclusion") if opt_verbose
|
||||
next
|
||||
end
|
||||
|
||||
if(include_range and ! include_range.include?(ip))
|
||||
print_status(" >> Skipping host #{ip} due to inclusion filter") if opt_verbose
|
||||
next
|
||||
end
|
||||
|
||||
opt_scanned << ip
|
||||
queue << ip
|
||||
end
|
||||
|
||||
break if queue.empty?
|
||||
print_status("Scanning #{queue[0]}-#{queue[-1]}...") if opt_verbose
|
||||
|
||||
msfid = Time.now.to_i
|
||||
|
||||
ipstr=''
|
||||
queue.each do |ip|
|
||||
ipstr=ipstr+","+ip
|
||||
end
|
||||
# Create a temporary site
|
||||
mname="Metasploit-#{msfid}"
|
||||
mcomment="Autocreated by the Metasploit Framework"
|
||||
mtarget=@ov.target_create({"name"=>mname, "hosts"=>ipstr, "comment"=>mcomment})
|
||||
|
||||
print_status(" >> Created temporary target #{mname} with id #{mtarget}") if opt_verbose
|
||||
|
||||
mconfig=@ov.config_get().index(opt_template)
|
||||
|
||||
if mconfig
|
||||
print_status(" >> Found config #{opt_template} with id #{mconfig}") if opt_verbose
|
||||
else
|
||||
print_error("Config not found")
|
||||
break
|
||||
end
|
||||
|
||||
# Create temporary task
|
||||
mtask = @ov.task_create({"name"=>mname,"comment"=>mcomment, "target"=>mtarget, "config"=>mconfig})
|
||||
if mtask
|
||||
print_status(" >> Created task #{mname} with id #{mtask}") if opt_verbose
|
||||
else
|
||||
print_error("Task could not be created")
|
||||
break
|
||||
end
|
||||
|
||||
|
||||
@ov.task_start(mtask)
|
||||
|
||||
print_status(" >> Scan has been launched with ID #{mtask}") if opt_verbose
|
||||
|
||||
rep = true
|
||||
begin
|
||||
prev = nil
|
||||
while(true)
|
||||
stat = @ov.task_get_byid(mtask)
|
||||
break if stat["status"] == "Done"
|
||||
percent=stat["progress"]
|
||||
|
||||
stat = "Progress: #{percent} %"
|
||||
if(stat != prev)
|
||||
print_status(" >> #{stat}") if opt_verbose
|
||||
end
|
||||
prev = stat
|
||||
select(nil, nil, nil, 5.0)
|
||||
end
|
||||
print_status(" >> Scan has been completed with task ID #{mtask}") if opt_verbose
|
||||
rescue ::Interrupt
|
||||
rep = false
|
||||
print_status(" >> Terminating task ID #{mtask} due to console interupt") if opt_verbose
|
||||
@ov.task_stop(mtask)
|
||||
break
|
||||
end
|
||||
|
||||
# Wait for the automatic report generation to complete
|
||||
if(rep)
|
||||
print_status(" >> Getting report...") if opt_verbose
|
||||
stat = @ov.task_get_byid(mtask)
|
||||
|
||||
if stat["status"] != "Done"
|
||||
content=@ov.report_get_byid(stat["lastreport"],'NBE')
|
||||
print_status(" >> Importing the report data from OpenVAS...") if opt_verbose
|
||||
framework.db.import({:data => content})
|
||||
|
||||
end
|
||||
|
||||
if ! opt_preserve
|
||||
print_status(" >> Deleting the temporary task and target...") if opt_verbose
|
||||
@ov.task_delete(mtask)
|
||||
@ov.target_delete(mtarget)
|
||||
end
|
||||
end
|
||||
|
||||
print_status("Completed the scan of #{total} addresses")
|
||||
|
||||
if(opt_autopwn)
|
||||
print_status("Launching an automated exploitation session")
|
||||
driver.run_single("db_autopwn -q -r -e -t #{opt_autopwn} -R #{opt_minrank} -I #{opt_scanned.join(",")}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_openvas_disconnect(*args)
|
||||
@ov.logout if @ov
|
||||
@ov = nil
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Plugin initialization
|
||||
#
|
||||
|
||||
def initialize(framework, opts)
|
||||
super
|
||||
add_console_dispatcher(OpenVASCommandDispatcher)
|
||||
print "Welcome to OpenVAS integration by kost\n\n"
|
||||
print "Use openvas_help for list of commands you can use.\n"
|
||||
print "Note that you should have database ready. After that you should connect with:\n"
|
||||
print "openvas_connect (try with -h for help on connecting)\n"
|
||||
print_status("OpenVAS integration has been activated")
|
||||
end
|
||||
|
||||
def cleanup
|
||||
remove_console_dispatcher('OpenVAS')
|
||||
end
|
||||
|
||||
def name
|
||||
"OpenVAS"
|
||||
end
|
||||
|
||||
def desc
|
||||
"Integrates with the OpenVAS - open source vulnerability management"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user