Adds portlist_to_portspec and portspec_to_portlist. Merges in Qualys XML support from Sertan Kolat
git-svn-id: file:///home/svn/framework3/trunk@8949 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
deeb00e4ae
commit
09dd8c1fcc
|
@ -1100,6 +1100,8 @@ class DBManager
|
|||
return import_nessus_xml(data, wspace)
|
||||
when "NessusClientData_v2"
|
||||
return import_nessus_xml_v2(data, wspace)
|
||||
when "SCAN"
|
||||
return import_qualys_xml(data, wspace)
|
||||
else
|
||||
# Give up if we haven't hit the root tag in the first few lines
|
||||
break if line_count > 10
|
||||
|
@ -1493,6 +1495,85 @@ class DBManager
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Import Qualys' xml output
|
||||
#
|
||||
def import_qualys_xml_file(filename, wspace=workspace)
|
||||
f = File.open(filename, 'r')
|
||||
data = f.read(f.stat.size)
|
||||
import_qualys_xml(data, wspace)
|
||||
end
|
||||
|
||||
def import_qualys_xml(data, wspace=workspace)
|
||||
|
||||
doc = REXML::Document.new(data)
|
||||
doc.elements.each('/SCAN/IP') do |host|
|
||||
addr = host.attributes['value']
|
||||
hname = host.attributes['name'] || ''
|
||||
|
||||
report_host(:workspace => wspace, :host => addr, :name => hname, :state => Msf::HostState::Alive)
|
||||
|
||||
if host.elements["OS"]
|
||||
hos = host.elements["OS"].text
|
||||
report_note(
|
||||
:workspace => wspace,
|
||||
:host => addr,
|
||||
:type => 'host.os.qualys_fingerprint',
|
||||
:data => {
|
||||
:os => hos
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
# Open TCP Services List (Qualys ID 82023)
|
||||
services_tcp = host.elements["SERVICES/CAT/SERVICE[@number='82023']/RESULT"]
|
||||
if services_tcp
|
||||
services_tcp.text.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, addr, match[0].to_s, 'tcp', 0, nil, nil, name)
|
||||
end
|
||||
end
|
||||
# Open UDP Services List (Qualys ID 82004)
|
||||
services_udp = host.elements["SERVICES/CAT/SERVICE[@number='82004']/RESULT"]
|
||||
if services_udp
|
||||
services_udp.text.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, addr, match[0].to_s, 'udp', 0, nil, nil, name)
|
||||
end
|
||||
end
|
||||
|
||||
# VULNS are confirmed, PRACTICES are unconfirmed vulnerabilities
|
||||
host.elements.each('VULNS/CAT | PRACTICES/CAT') do |cat|
|
||||
port = cat.attributes['port']
|
||||
protocol = cat.attributes['protocol']
|
||||
cat.elements.each('VULN | PRACTICE') do |vuln|
|
||||
refs = []
|
||||
qid = vuln.attributes['number']
|
||||
severity = vuln.attributes['severity']
|
||||
vuln.elements.each('VENDOR_REFERENCE_LIST/VENDOR_REFERENCE') do |ref|
|
||||
refs.push(ref.elements['ID'].text.to_s)
|
||||
end
|
||||
vuln.elements.each('CVE_ID_LIST/CVE_ID') do |ref|
|
||||
refs.push('CVE-' + /C..-([0-9\-]{9})/.match(ref.elements['ID'].text.to_s)[1])
|
||||
end
|
||||
vuln.elements.each('BUGTRAQ_ID_LIST/BUGTRAQ_ID') do |ref|
|
||||
refs.push('BID-' + ref.elements['ID'].text.to_s)
|
||||
end
|
||||
|
||||
handle_qualys(wspace, addr, port, protocol, qid, severity, refs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def import_ip_list_file(filename, wspace=workspace)
|
||||
f = File.open(filename, 'r')
|
||||
data = f.read(f.stat.size)
|
||||
|
@ -1510,6 +1591,7 @@ class DBManager
|
|||
data = f.read(f.stat.size)
|
||||
import_amap_log(data, wspace)
|
||||
end
|
||||
|
||||
def import_amap_mlog(data, wspace)
|
||||
data.each_line do |line|
|
||||
next if line =~ /^#/
|
||||
|
@ -1643,6 +1725,31 @@ protected
|
|||
:refs => refs)
|
||||
end
|
||||
|
||||
#
|
||||
# Qualys report parsing/handling
|
||||
#
|
||||
def handle_qualys(wspace, addr, port, protocol, qid, severity, refs, name=nil)
|
||||
|
||||
port = port.to_i
|
||||
|
||||
info = { :workspace => wspace, :host => addr, :port => port, :proto => protocol }
|
||||
if name and name != 'unknown'
|
||||
info[:name] = name
|
||||
end
|
||||
|
||||
report_service(info)
|
||||
|
||||
return if qid == 0
|
||||
|
||||
report_vuln(
|
||||
:workspace => wspace,
|
||||
:host => addr,
|
||||
:port => port,
|
||||
:proto => protocol,
|
||||
:name => 'QUALYS-' + qid,
|
||||
:refs => refs)
|
||||
end
|
||||
|
||||
def process_nexpose_data_sxml_refs(vuln)
|
||||
refs = []
|
||||
vid = vuln.attributes['id'].to_s.downcase
|
||||
|
|
|
@ -61,6 +61,7 @@ class Db
|
|||
"db_import_nessus_nbe" => "Import a Nessus scan result file (NBE)",
|
||||
"db_import_nessus_xml" => "Import a Nessus scan result file (NESSUS)",
|
||||
"db_import_nmap_xml" => "Import a Nmap scan results file (-oX)",
|
||||
"db_import_qualys_xml" => "Import a Qualys scan results file (XML)",
|
||||
"db_nmap" => "Executes nmap and records the output automatically",
|
||||
}
|
||||
|
||||
|
@ -456,9 +457,9 @@ class Db
|
|||
when '-X'
|
||||
targ_exc << OptAddressRange.new('TEMPRANGE', [ true, '' ]).normalize(args.shift)
|
||||
when '-PI'
|
||||
port_inc = Rex::Socket.portspec_crack(args.shift)
|
||||
port_inc = Rex::Socket.portspec_to_portlist(args.shift)
|
||||
when '-PX'
|
||||
port_exc = Rex::Socket.portspec_crack(args.shift)
|
||||
port_exc = Rex::Socket.portspec_to_portlist(args.shift)
|
||||
when '-m'
|
||||
regx = args.shift
|
||||
when '-R'
|
||||
|
@ -929,6 +930,22 @@ class Db
|
|||
framework.db.import_nmap_xml_file(args[0])
|
||||
end
|
||||
|
||||
#
|
||||
# Import Qualys XML files
|
||||
#
|
||||
def cmd_db_import_qualys_xml(*args)
|
||||
if not (args and args.length == 1)
|
||||
print_status("Usage: db_import_qualys_xml <result.xml>")
|
||||
return
|
||||
end
|
||||
|
||||
if not File.readable?(args[0])
|
||||
print_status("Could not read the Qualys file")
|
||||
return
|
||||
end
|
||||
framework.db.import_qualys_xml_file(args[0])
|
||||
end
|
||||
|
||||
#
|
||||
# Import IP List from a file
|
||||
#
|
||||
|
|
|
@ -350,11 +350,16 @@ module Socket
|
|||
[ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
|
||||
end
|
||||
|
||||
|
||||
def self.portspec_crack(pspec)
|
||||
portspec_to_portlist(pspec)
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a port specification like "80,21-23,443" into a sorted,
|
||||
# unique array of valid port numbers like [21,22,23,80,443]
|
||||
#
|
||||
def self.portspec_crack(pspec)
|
||||
def self.portspec_to_portlist(pspec)
|
||||
ports = []
|
||||
|
||||
# Build ports array from port specification
|
||||
|
@ -370,7 +375,38 @@ module Socket
|
|||
end
|
||||
|
||||
# Sort, and remove dups and invalid ports
|
||||
ports.sort.uniq.delete_if { |p| p < 0 or p > 65535 }
|
||||
ports.sort.uniq.delete_if { |p| p < 1 or p > 65535 }
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a port list like [1,2,3,4,5,100] into a
|
||||
# range specification like "1-5,100"
|
||||
#
|
||||
def self.portlist_to_portspec(parr)
|
||||
ranges = []
|
||||
range = []
|
||||
lastp = nil
|
||||
|
||||
parr.uniq.sort{|a,b| a<=>b}.map{|a| a.to_i}.each do |n|
|
||||
next if (n < 1 or n > 65535)
|
||||
if not lastp
|
||||
range = [n]
|
||||
lastp = n
|
||||
next
|
||||
end
|
||||
|
||||
if lastp == n - 1
|
||||
range << n
|
||||
else
|
||||
ranges << range
|
||||
range = [n]
|
||||
end
|
||||
lastp = n
|
||||
end
|
||||
|
||||
ranges << range
|
||||
ranges.delete(nil)
|
||||
ranges.uniq.map{|x| x.length == 1 ? "#{x[0]}" : "#{x[0]}-#{x[-1]}"}.join(",")
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -396,18 +432,18 @@ module Socket
|
|||
#
|
||||
# Create a TCP socket pair.
|
||||
#
|
||||
# sf: This create a socket pair using native ruby sockets and will work
|
||||
# sf: This create a socket pair using native ruby sockets and will work
|
||||
# on Windows where ::Socket.pair is not implemented.
|
||||
# Note: OpenSSL requires native ruby sockets for its io.
|
||||
#
|
||||
def self.tcp_socket_pair
|
||||
lsock = nil
|
||||
rsock = nil
|
||||
laddr = '127.0.0.1'
|
||||
laddr = '127.0.0.1'
|
||||
lport = 0
|
||||
threads = []
|
||||
mutex = ::Mutex.new
|
||||
|
||||
|
||||
threads << ::Thread.new {
|
||||
server = nil
|
||||
mutex.synchronize {
|
||||
|
@ -424,31 +460,31 @@ module Socket
|
|||
lsock, saddr = server.accept
|
||||
server.close
|
||||
}
|
||||
|
||||
|
||||
threads.each { |t| t.join }
|
||||
|
||||
|
||||
return [lsock, rsock]
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Create a UDP socket pair using native ruby UDP sockets.
|
||||
#
|
||||
def self.udp_socket_pair
|
||||
laddr = '127.0.0.1'
|
||||
|
||||
laddr = '127.0.0.1'
|
||||
|
||||
lsock = ::UDPSocket.new
|
||||
lsock.bind( laddr, 0 )
|
||||
|
||||
|
||||
rsock = ::UDPSocket.new
|
||||
rsock.bind( laddr, 0 )
|
||||
|
||||
|
||||
rsock.connect( *lsock.addr.values_at(3,1) )
|
||||
|
||||
|
||||
lsock.connect( *rsock.addr.values_at(3,1) )
|
||||
|
||||
|
||||
return [lsock, rsock]
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
#
|
||||
# Class initialization
|
||||
|
|
Loading…
Reference in New Issue