---
# System prepended metadata

title: Exploitable vulnerability report script

---

#!/usr/bin/env python3

# Exploitable vulnerability report script
# Maps vulnerabilities against ExploitDB
# Runs against a customizable IP address range or 0.0.0.0
# Output is in HTML format


from pymongo import MongoClient
import datetime, sys, ipaddress, json
from yattag import Doc, indent

# globals
# Mongo connection parameters
client = MongoClient('mongodb://localhost:27017')
db = client['vulnmgt']
cvedb = client['cvedb']

# CVE to exploitdb map file
cveToExploitdbMap = "/home/andy/cve_searchsploit/cve_searchsploit/exploitdb_mapping_cve.json"

# Output filename
outputFile = "exploitable-vuln-report.html"

def main():
 # check if there's a network. If not, use 0.0.0.0
    if len(sys.argv) > 1:
        network = sys.argv[1]
    else:
        network = '0.0.0.0/0'
    networkObj = ipaddress.ip_network(network)

# load exploit map

    with open(cveToExploitdbMap) as mapfile:
        exploitMap = json.load(mapfile)

# initialize the host to CVE map object
    hostCveMap = {}
# get list of assets with OIDs associated
    hostList = db.hosts.find({'oids': {'$exists' : 'true'}})
# for each asset...
    for host in hostList:
# make string of vulns found, resolving them into CVE IDs (if they exist, otherwise NOCVE)
        ip = host['ip']
        # check if it's in our range
        if ipaddress.ip_address(ip) not in networkObj:
            continue
        for oidItem in host['oids']:
            cveList = db.vulnerabilities.find_one({'oid': oidItem['oid']})['cve']
# because this is a list of one or more items:
            for cve in cveList:

# skip the NOCVE type, since it's not really useful to us
                if cve == "NOCVE":
                    continue
# skip CVEs that aren't in the exploit map
                if cve not in exploitMap:
                    continue

# if there are already IPs mapped to this vulnerability
                if cve in hostCveMap.keys():
# ignore duplicates
                    if ip not in hostCveMap[cve]:
                        hostCveMap[cve].append(ip)
# if there aren't any IPs yet, create a new list with this as the first item
                else:
                    hostCveMap[cve] = [ ip ]

# start the output doc
    doc, tag, text, line = Doc().ttl()

    with tag('html'):
        with tag('head'):
            line('title', 'Exploitable vulnerability report for ' + network)
        with tag('body'):
            line('h1', 'Exploitable vulnerability report for ' + network)

# now, for each CVE (sorted) that we've found...
            for cve in sorted(hostCveMap.keys()):

        # look up CVE details in cve-search database
                cvedetails = cvedb.cves.find_one({'id': cve})

        # get affected host information into a list
                affectedHosts = len(hostCveMap[cve])
                listOfHosts = hostCveMap[cve]

        # assemble into HTML
                line('h2', cve)
                line('b', 'Affected hosts: ')
                text(affectedHosts)
                doc.stag('br')
                if (cvedetails): # if it's not empty!
                    with tag('table'):
                        with tag('tr'):
                            line('td', 'Summary')
                            line('td', cvedetails['summary'])
                        with tag('tr'):
                            line('td', 'CWE')
                            with tag('td'):
                                id=cvedetails['cwe'].split('-')[1]
                                with tag('a', href="https://cwe.mitre.org/data/definitions/"+id):
                                    text(cvedetails['cwe'])
                                cweDetails = cvedb.cwe.find_one({'id': id})
                                if cweDetails:
                                    text(" (" + cweDetails['name'] + ")")
                                else:
                                    text(" (no title)")
                        with tag('tr'):
                            line('td', 'Published')
                            line('td', cvedetails['Published'].strftime("%Y-%m-%d"))
                        with tag('tr'):
                            line('td', 'Modified')
                            line('td', cvedetails['Modified'].strftime("%Y-%m-%d"))
                        with tag('tr'):
                            line('td', 'CVSS')
                            line('td', cvedetails['cvss'])
                        with tag('tr'):
                            with tag('td'):
                                line('b', 'Impacts')
                        with tag('tr'):
                            line('td', "Confidentiality")
                            line('td', cvedetails['impact']['confidentiality'])
                        with tag('tr'):
                            line('td', "Integrity")
                            line('td', cvedetails['impact']['integrity'])
                        with tag('tr'):
                            line('td', "Availability")
                            line('td', cvedetails['impact']['availability'])
                        with tag('tr'):
                            with tag('td'):
                                line('b', 'Access')
                        with tag('tr'):
                            line('td', "Vector")
                            line('td', cvedetails['access']['vector'])
                        with tag('tr'):
                            line('td', "Complexity")
                            line('td', cvedetails['access']['complexity'])
                        with tag('tr'):
                            line('td', "Authentication")
                            line('td', cvedetails['access']['authentication'])
                        with tag('tr'):
                            with tag('td'):
                                line('b', "References")
                        for reference in cvedetails['references']:
                            with tag('tr'):
                                with tag('td'):
                                    with tag('a', href=reference):
                                        text(reference)

                else: # if it's empty
                    line('i', "Details unknown -- update your CVE database")
                    doc.stag('br')

                line('b', "Affected hosts:")
                doc.stag('br')
                for host in sorted(listOfHosts):
                    text(host)
                    doc.stag('br')

    # print exploitdb links
                line('b', "ExploitDB links")
                doc.stag('br')
                for exploitID in exploitMap[cve]:
                    with tag('a', href="https://www.exploit-db.com/exploits/"+exploitID):
                        text("https://www.exploit-db.com/exploits/"+exploitID)
                    doc.stag('br')

# output final HTML
    with open(outputFile, 'w') as htmlOut:
        htmlOut.write(indent(doc.getvalue()))
        htmlOut.close()

main()
