Last active
October 14, 2018 08:06
-
-
Save nopslider/0beb1f2f45cb2cf2c0f96d27e5204717 to your computer and use it in GitHub Desktop.
Qualys Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import xml.etree.ElementTree as ET | |
import argparse | |
import ipaddress | |
parser = argparse.ArgumentParser() | |
parser.add_argument("firstscan") | |
parser.add_argument("secondscan") | |
parser.add_argument("-s","--severitylevel",type=int,choices=[0,1,2,3],default=1,help="Filter vulnerabilities of this severity level and lower") | |
args = parser.parse_args() | |
severitydesc = ["INFO","LOW","MEDIUM","HIGH","CRITICAL"] | |
firsttree = ET.parse(args.firstscan) | |
firstroot = firsttree.getroot() | |
secondtree = ET.parse(args.secondscan) | |
secondroot = secondtree.getroot() | |
firstscanhosts = {} | |
secondscanhosts = {} | |
newips = set() | |
lostips = set() | |
countofcurrentvulns = [0,0,0,0,0] | |
countofpreviousvulns = [0,0,0,0,0] | |
firsttargets = set() | |
secondtargets = set() | |
countfirsttargets = 0 | |
countsecondtargets = 0 | |
firstuniqvulns = [{},{},{},{},{}] | |
countfirstuniqvulns = 0 | |
seconduniqvulns = [{},{},{},{},{}] | |
countseconduniqvulns = 0 | |
for ip in firstroot.iter('IP'): | |
address = ip.attrib["value"] | |
firstscanhosts[address] = set() | |
vulns = ip.find('VULNS') | |
if not vulns: | |
continue | |
for cat in vulns.iter('CAT'): | |
try: | |
proto = cat.attrib["protocol"] | |
except KeyError: | |
proto = "Unknown" | |
try: | |
port = cat.attrib["port"] | |
except KeyError: | |
port = "Unknown" | |
for vuln in cat.iter('VULN'): | |
title = vuln.find('TITLE').text | |
severity = int(vuln.attrib["severity"]) - 1 | |
countofpreviousvulns[severity] = countofpreviousvulns[severity] + 1 | |
if severity >= args.severitylevel: | |
firstscanhosts[address].add((title,severity,proto,port)) | |
if title not in firstuniqvulns[severity]: | |
firstuniqvulns[severity][title] = 1 | |
countfirstuniqvulns = countfirstuniqvulns + 1 | |
else: | |
firstuniqvulns[severity][title] = firstuniqvulns[severity][title] + 1 | |
for ip in secondroot.iter('IP'): | |
address = ip.attrib["value"] | |
secondscanhosts[address] = set() | |
vulns = ip.find('VULNS') | |
if address not in firstscanhosts: | |
newips.add(address) | |
if not vulns: | |
continue | |
for cat in vulns.iter('CAT'): | |
try: | |
proto = cat.attrib["protocol"] | |
except KeyError: | |
proto = "Unknown" | |
try: | |
port = cat.attrib["port"] | |
except KeyError: | |
port = "Unknown" | |
for vuln in cat.iter('VULN'): | |
title = vuln.find('TITLE').text | |
severity = int(vuln.attrib["severity"]) - 1 | |
countofcurrentvulns[severity] = countofcurrentvulns[severity] + 1 | |
if severity >= args.severitylevel: | |
secondscanhosts[address].add((title,severity,proto,port)) | |
if title not in seconduniqvulns[severity]: | |
seconduniqvulns[severity][title] = 1 | |
countseconduniqvulns = countseconduniqvulns + 1 | |
else: | |
seconduniqvulns[severity][title] = seconduniqvulns[severity][title] + 1 | |
for ip in firstscanhosts: | |
if ip not in secondscanhosts: | |
lostips.add(ip) | |
print("\nNumber of live hosts:") | |
print("\n {} - previously {}\n".format(len(secondscanhosts),len(firstscanhosts))) | |
print("Number of vulnerabilities:\n") | |
for i,count in enumerate(countofcurrentvulns): | |
if i >= args.severitylevel: | |
print(" {}\t{} (previously {})".format(count,severitydesc[i],countofpreviousvulns[i])) | |
print("\nNumber of unique vulnerabilities:\n") | |
for severity in range(4,args.severitylevel-1,-1): | |
print(" {} {}, previously {}".format(severitydesc[severity],len(seconduniqvulns[severity]),len(firstuniqvulns[severity]))) | |
print("\nUnique vulnerabilities ({}, previously {}):\n".format(countseconduniqvulns,countfirstuniqvulns)) | |
for severity in range(4,args.severitylevel-1,-1): | |
for vuln in seconduniqvulns[severity]: | |
if vuln in firstuniqvulns[severity]: | |
print(" {} ({}) - {} hosts (previously {} hosts)".format(vuln,severitydesc[severity],seconduniqvulns[severity][vuln],firstuniqvulns[severity][vuln])) | |
else: | |
print(" + {} ({}) - {} hosts (NEW VULNERABILITY)".format(vuln,severitydesc[severity],seconduniqvulns[severity][vuln])) | |
print("\nUnique vulnerabilities TSV ({}, previously {}):\n".format(countseconduniqvulns,countfirstuniqvulns)) | |
for severity in range(4,args.severitylevel-1,-1): | |
for vuln in seconduniqvulns[severity]: | |
if vuln in firstuniqvulns[severity]: | |
print("{}|{}|{}|{}".format(vuln,severitydesc[severity],seconduniqvulns[severity][vuln],firstuniqvulns[severity][vuln])) | |
else: | |
print("{}|{}|{}|0".format(vuln,severitydesc[severity],seconduniqvulns[severity][vuln])) | |
found = False | |
for severity in range(4,args.severitylevel-1,-1): | |
for vuln in firstuniqvulns[severity]: | |
if vuln not in seconduniqvulns[severity]: | |
if not found: | |
print("\nRemediated Vulnerabilities:\n") | |
found = True | |
print(" - {} no longer present (was previously reported on {} hosts)".format(vuln,firstuniqvulns[severity][vuln])) | |
found = False | |
for severity in range(4,args.severitylevel-1,-1): | |
for vuln in firstuniqvulns[severity]: | |
if vuln not in seconduniqvulns[severity]: | |
if not found: | |
print("\nRemediated Vulnerabilities TSV:\n") | |
found = True | |
print("{}|{}|0|{}".format(vuln,severitydesc[severity],firstuniqvulns[severity][vuln])) | |
if len(newips) > 0: | |
print("\nThese are new IPs seen in the second scan ({}):\n".format(len(newips))) | |
for ip in newips: | |
vulns = sorted(secondscanhosts[ip], key = lambda element : element[1],reverse=True) | |
if len(vulns) > 0: | |
print("{} ({} vulnerabilities):".format(ip,len(vulns))) | |
for vuln in vulns: | |
print(" + {} ({})".format(vuln[0],vuln[1])) | |
else: | |
if args.severitylevel == 0: | |
print("{}\t(No vulnerabilities)".format(ip)) | |
else: | |
print("{}\t(No vulnerabilities reported - NB: excluding vulnerabilities rated below {})".format(ip,severitydesc[args.severitylevel])) | |
print("\n") | |
if len(lostips) > 0: | |
print("These are IPs that were previously seen, but are not present in the second scan ({}):\n".format(len(lostips))) | |
print("\n".join(lostips)) | |
print("\n") | |
change = False | |
for host in secondscanhosts: | |
if (host not in newips) and (host not in lostips): | |
if firstscanhosts[host] != secondscanhosts[host]: | |
if not change: | |
change = True | |
print("The following hosts have changed between scans:") | |
print("\n{}\tFirst scan: {}\tSecond scan: {}".format(host,len(firstscanhosts[host]),len(secondscanhosts[host]))) | |
print("----------------------------------------------------") | |
firstvulns = sorted(firstscanhosts[host], key = lambda element : element[1],reverse=True) | |
secondvulns = sorted(secondscanhosts[host], key = lambda element : element[1],reverse=True) | |
for vuln in firstvulns: | |
if vuln not in secondvulns: | |
print(" - {} ({}/{}) ({})".format(vuln[0],vuln[3],vuln[2],severitydesc[vuln[1]])) | |
for vuln in secondvulns: | |
if vuln not in firstvulns: | |
print(" + {} ({}/{}) ({})".format(vuln[0],vuln[3],vuln[2],severitydesc[vuln[1]])) | |
if not change: | |
print("No changes between scans.") | |
for host in secondscanhosts: | |
secondvulns = sorted(secondscanhosts[host], key = lambda element : element[1],reverse=True) | |
if len(secondvulns) > 0: | |
print("\nCurrent risk profile for {}".format(host)) | |
print("----------------------------------------------------") | |
for vuln in secondvulns: | |
print(" {} ({}/{}) ({})".format(vuln[0],vuln[3],vuln[2],severitydesc[vuln[1]])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment