Adds another Qualys formatted XML importer for ASSET_DATA_REPORT files.
git-svn-id: file:///home/svn/framework3/trunk@12575 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
cdeb44747f
commit
50b26cb2d6
|
@ -2070,7 +2070,7 @@ class DBManager
|
|||
end
|
||||
|
||||
# Returns one of: :nexpose_simplexml :nexpose_rawxml :nmap_xml :openvas_xml
|
||||
# :nessus_xml :nessus_xml_v2 :qualys_xml :msf_xml :nessus_nbe :amap_mlog
|
||||
# :nessus_xml :nessus_xml_v2 :qualys_scan_xml, :qualys_asset_xml, :msf_xml :nessus_nbe :amap_mlog
|
||||
# :amap_log :ip_list, :msf_zip, :libpcap
|
||||
# If there is no match, an error is raised instead.
|
||||
def import_filetype_detect(data)
|
||||
|
@ -2140,8 +2140,11 @@ class DBManager
|
|||
@import_filedata[:type] = "Nessus XML (v2)"
|
||||
return :nessus_xml_v2
|
||||
when "SCAN"
|
||||
@import_filedata[:type] = "Qualys XML"
|
||||
return :qualys_xml
|
||||
@import_filedata[:type] = "Qualys Scan XML"
|
||||
return :qualys_scan_xml
|
||||
when "ASSET_DATA_REPORT"
|
||||
@import_filedata[:type] = "Qualys Asset XML"
|
||||
return :qualys_asset_xml
|
||||
when /MetasploitExpressV[1234]/
|
||||
@import_filedata[:type] = "Metasploit XML"
|
||||
return :msf_xml
|
||||
|
@ -4381,10 +4384,114 @@ class DBManager
|
|||
REXML::Document.parse_stream(data, parser)
|
||||
end
|
||||
|
||||
def find_qualys_asset_vuln_refs(doc)
|
||||
vuln_refs = {}
|
||||
doc.elements.each("/ASSET_DATA_REPORT/GLOSSARY/VULN_DETAILS_LIST/VULN_DETAILS") do |vuln|
|
||||
next unless vuln.elements['QID'] && vuln.elements['QID'].first
|
||||
qid = vuln.elements['QID'].first.to_s
|
||||
vuln_refs[qid] ||= []
|
||||
if vuln.elements["CVE_ID_LIST/CVE_ID/ID"]
|
||||
vuln.elements["CVE_ID_LIST/CVE_ID/ID"].each do |ref|
|
||||
next unless ref
|
||||
next unless ref.to_s[/^C..-[0-9\-]{9}/]
|
||||
vuln_refs[qid] << ref.to_s.gsub(/^C../, "CVE")
|
||||
end
|
||||
end
|
||||
if vuln.elements["BUGTRAQ_ID_LIST/BUGTRAQ_ID/ID"]
|
||||
vuln.elements["BUGTRAQ_ID_LIST/BUGTRAQ_ID/ID"].each do |ref|
|
||||
next unless ref
|
||||
next unless ref.to_s[/^[0-9]{1,9}/]
|
||||
vuln_refs[qid] << "BID-#{ref}"
|
||||
end
|
||||
end
|
||||
end
|
||||
return vuln_refs
|
||||
end
|
||||
|
||||
# Pull out vulnerabilities that have at least one matching
|
||||
# ref -- many "vulns" are not vulns, just audit information.
|
||||
def find_qualys_asset_vulns(host,wspace,hobj,vuln_refs,&block)
|
||||
host.elements.each("VULN_INFO_LIST/VULN_INFO") do |vi|
|
||||
next unless vi.elements["QID"]
|
||||
vi.elements.each("QID") do |qid|
|
||||
next if vuln_refs[qid.text].nil? || vuln_refs[qid.text].empty?
|
||||
handle_qualys(wspace, hobj, nil, nil, qid.text, nil, vuln_refs[qid.text], nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Takes QID numbers and finds the discovered services in
|
||||
# a qualys_asset_xml.
|
||||
def find_qualys_asset_ports(i=82023,host,wspace,hobj)
|
||||
return unless (i == 82023 || i == 82004)
|
||||
proto = i == 82023 ? 'tcp' : 'udp'
|
||||
qid = host.elements["VULN_INFO_LIST/VULN_INFO/QID[@id='qid_#{i}']"]
|
||||
qid_result = qid.parent.elements["RESULT[@format='table']"] if qid
|
||||
hports = qid_result.first.to_s if qid_result
|
||||
if hports
|
||||
hports.scan(/([0-9]+)\t(.*?)\t.*?\t([^\t\n]*)/) do |match|
|
||||
if match[2] == nil or match[2].strip == 'unknown'
|
||||
name = match[1].strip
|
||||
else
|
||||
name = match[2].strip
|
||||
end
|
||||
handle_qualys(wspace, hobj, match[0].to_s, proto, 0, nil, nil, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Import Qualys' xml output
|
||||
# Import Qualys's Asset Data Report format
|
||||
#
|
||||
def import_qualys_asset_xml(args={}, &block)
|
||||
data = args[:data]
|
||||
wspace = args[:wspace] || workspace
|
||||
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
|
||||
doc = rexmlify(data)
|
||||
vuln_refs = find_qualys_asset_vuln_refs(doc)
|
||||
|
||||
# 2nd pass, actually grab the hosts.
|
||||
doc.elements.each("/ASSET_DATA_REPORT/HOST_LIST/HOST") do |host|
|
||||
hobj = nil
|
||||
addr = host.elements["IP"].text if host.elements["IP"]
|
||||
next unless validate_ips(addr)
|
||||
if bl.include? addr
|
||||
next
|
||||
else
|
||||
yield(:address,addr) if block
|
||||
end
|
||||
hname = ( # Prefer NetBIOS over DNS
|
||||
(host.elements["NETBIOS"].text if host.elements["NETBIOS"]) ||
|
||||
(host.elements["DNS"].text if host.elements["DNS"]) ||
|
||||
"" )
|
||||
hobj = report_host(:workspace => wspace, :host => addr, :name => hname, :state => Msf::HostState::Alive)
|
||||
report_import_note(wspace,hobj)
|
||||
|
||||
if host.elements["OPERATING_SYSTEM"]
|
||||
hos = host.elements["OPERATING_SYSTEM"].text
|
||||
report_note(
|
||||
:workspace => wspace,
|
||||
:host => hobj,
|
||||
:type => 'host.os.qualys_fingerprint',
|
||||
:data => { :os => hos }
|
||||
)
|
||||
end
|
||||
|
||||
# Report open ports.
|
||||
find_qualys_asset_ports(82023,host,wspace,hobj) # TCP
|
||||
find_qualys_asset_ports(82004,host,wspace,hobj) # UDP
|
||||
|
||||
# Report vulns
|
||||
find_qualys_asset_vulns(host,wspace,hobj,vuln_refs,&block)
|
||||
|
||||
end # host
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
def import_qualys_xml_file(args={})
|
||||
# Import Qualys' Scan xml output
|
||||
#
|
||||
def import_qualys_scan_xml_file(args={})
|
||||
filename = args[:filename]
|
||||
wspace = args[:wspace] || workspace
|
||||
|
||||
|
@ -4392,10 +4499,10 @@ class DBManager
|
|||
::File.open(filename, 'rb') do |f|
|
||||
data = f.read(f.stat.size)
|
||||
end
|
||||
import_qualys_xml(args.merge(:data => data))
|
||||
import_qualys_scan_xml(args.merge(:data => data))
|
||||
end
|
||||
|
||||
def import_qualys_xml(args={}, &block)
|
||||
def import_qualys_scan_xml(args={}, &block)
|
||||
data = args[:data]
|
||||
wspace = args[:wspace] || workspace
|
||||
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
|
||||
|
@ -4849,7 +4956,7 @@ protected
|
|||
#
|
||||
def handle_qualys(wspace, hobj, port, protocol, qid, severity, refs, name=nil)
|
||||
addr = hobj.address
|
||||
port = port.to_i
|
||||
port = port.to_i if port
|
||||
|
||||
info = { :workspace => wspace, :host => hobj, :port => port, :proto => protocol }
|
||||
if name and name != 'unknown'
|
||||
|
|
|
@ -1276,6 +1276,8 @@ class Db
|
|||
warnings = 0
|
||||
framework.db.import_file(:filename => filename) do |type,data|
|
||||
case type
|
||||
when :debug
|
||||
print_status("DEBUG: #{data.inspect}")
|
||||
when :filetype
|
||||
print_status("Importing '#{data}' data")
|
||||
when :address
|
||||
|
|
Loading…
Reference in New Issue