Skip to content

Commit

Permalink
Merge pull request #69 from cisagov/improvement/support-cvss-v3
Browse files Browse the repository at this point in the history
Support CVSSv3 scores and severities
  • Loading branch information
dav3r authored Jun 8, 2022
2 parents 674dbdb + 5212891 commit 073798f
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 15 deletions.
14 changes: 10 additions & 4 deletions bin/cyhy-nvdsync
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,21 @@ def parse_json(db, json_stream):

for entry in data.get("CVE_Items", []):
cve_id = entry["cve"]["CVE_data_meta"]["ID"]
if "baseMetricV2" not in entry["impact"]:
# NVD 'reject' CVEs do not have 'baseMetricV2' CVSS data
# Reject CVEs that don't have baseMetricV2 or baseMetricV3 CVSS data
if ("baseMetricV2" or "baseMetricV3") not in entry["impact"]:
# Make sure they are removed from our db.
db.CVEDoc.collection.remove({"_id": cve_id}, safe=False)
print "x",
else:
print ".",
cvss_base_score = entry["impact"]["baseMetricV2"]["cvssV2"]["baseScore"]
entry_doc = db.CVEDoc({"_id": cve_id, "cvss_score": float(cvss_base_score)})
version = "V3" if "baseMetricV3" in entry["impact"] else "V2"
cvss_base_score = entry["impact"]["baseMetric" + version]["cvss" + version]["baseScore"]
cvss_version = entry["impact"]["baseMetric" + version]["cvss" + version]["version"]
entry_doc = db.CVEDoc({
"_id": cve_id,
"cvss_score": float(cvss_base_score),
"cvss_version": cvss_version
})
entry_doc.save(safe=False)
print "\n\n"

Expand Down
49 changes: 39 additions & 10 deletions cyhy/db/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1568,24 +1568,53 @@ def children(self):

class CVEDoc(RootDoc):
__collection__ = CVE_COLLECTION
structure = {"_id": basestring, "cvss_score": float, "severity": int} # CVE String
required_fields = ["_id", "cvss_score", "severity"]
structure = {
"_id": basestring, # CVE string
"cvss_score": float,
"cvss_version": basestring,
"severity": int
}
required_fields = ["_id", "cvss_score", "cvss_version", "severity"]
default_values = {}

def get_indices(self):
return tuple()

def save(self, *args, **kwargs):
# Calculate severity from cvss on save
# Source: https://nvd.nist.gov/vuln-metrics/cvss
#
# Notes:
# - The CVSS score to severity mapping is not continuous (e.g. a
# score of 8.95 is undefined according to their table). However,
# the CVSS equation documentation
# (https://www.first.org/cvss/specification-document#CVSS-v3-1-Equations)
# specifies that all CVSS scores are rounded up to the nearest tenth
# of a point, so our severity mapping below is valid.
# - CVSSv3 specifies that a score of 0.0 has a severity of "None", but
# we have chosen to map 0.0 to severity 1 ("Low") because CyHy code
# has historically assumed severities between 1 and 4 (inclusive).
# Since we have not seen CVSSv3 scores lower than 3.1, this will
# hopefully never be an issue.
cvss = self["cvss_score"]
if cvss == 10:
self["severity"] = 4
elif cvss >= 7.0:
self["severity"] = 3
elif cvss >= 4.0:
self["severity"] = 2
else:
self["severity"] = 1
if self["cvss_version"] == "2.0":
if cvss == 10:
self["severity"] = 4
elif cvss >= 7.0:
self["severity"] = 3
elif cvss >= 4.0:
self["severity"] = 2
else:
self["severity"] = 1
elif self["cvss_version"] in ["3.0", "3.1"]:
if cvss >= 9.0:
self["severity"] = 4
elif cvss >= 7.0:
self["severity"] = 3
elif cvss >= 4.0:
self["severity"] = 2
else:
self["severity"] = 1
super(CVEDoc, self).save(*args, **kwargs)


Expand Down
44 changes: 43 additions & 1 deletion cyhy/db/ticket_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ def __generate_ticket_details(self, vuln, ticket, check_for_changes=True):

new_details = {
"cve": vuln.get("cve"),
"cvss_base_score": vuln["cvss_base_score"],
"cvss_base_score": vuln.get("cvss3_base_score", vuln["cvss_base_score"]),
"cvss_version": "3" if "cvss3_base_score" in vuln else "2",
"kev": False,
"name": vuln["plugin_name"],
"score_source": vuln["source"],
Expand All @@ -109,13 +110,54 @@ def __generate_ticket_details(self, vuln, ticket, check_for_changes=True):
cve_doc = self.__db.CVEDoc.find_one({"_id": vuln["cve"]})
if cve_doc:
new_details["cvss_base_score"] = cve_doc["cvss_score"]
new_details["cvss_version"] = cve_doc["cvss_version"]
new_details["score_source"] = "nvd"
new_details["severity"] = cve_doc["severity"]
# if the CVE is listed in the KEV collection, we'll mark it as such
kev_doc = self.__db.KEVDoc.find_one({"_id": vuln["cve"]})
if kev_doc:
new_details["kev"] = True

# As of May 2022, some Nessus plugins report a severity that is
# inconsistent with their (non-NVD, non-CVE-based) CVSS v3 score.
# To reduce confusion, we ensure that the severity is correct here.
# For examples, see the following plugins:
# 34460, 104572, 107056, 140770, 156560, 156941, 156441
if new_details["score_source"] != "nvd":
cvss = new_details["cvss_base_score"]
# Source: https://nvd.nist.gov/vuln-metrics/cvss
#
# Notes:
# - The CVSS score to severity mapping is not continuous (e.g. a
# score of 8.95 is undefined according to their table).
# However, the CVSS equation documentation
# (https://www.first.org/cvss/specification-document#CVSS-v3-1-Equations)
# specifies that all CVSS scores are rounded up to the nearest
# tenth of a point, so our severity mapping below is valid.
# - CVSSv3 specifies that a score of 0.0 has a severity of "None",
# but we have chosen to map 0.0 to severity 1 ("Low") because
# CyHy code has historically assumed severities between 1 and 4
# (inclusive). Since we have not seen CVSSv3 scores lower than
# 3.1, this will hopefully never be an issue.
if new_details["cvss_version"] == "2":
if cvss == 10:
new_details["severity"] = 4
elif cvss >= 7.0:
new_details["severity"] = 3
elif cvss >= 4.0:
new_details["severity"] = 2
else:
new_details["severity"] = 1
elif new_details["cvss_version"] == "3":
if cvss >= 9.0:
new_details["severity"] = 4
elif cvss >= 7.0:
new_details["severity"] = 3
elif cvss >= 4.0:
new_details["severity"] = 2
else:
new_details["severity"] = 1

delta = []
if check_for_changes:
delta = self.__calculate_delta(ticket["details"], new_details)
Expand Down

0 comments on commit 073798f

Please sign in to comment.