Skip to content

Commit 10ca004

Browse files
authored
Add legacy parsing method for qualys (DefectDojo#9861)
* Add legacy parsing method for qualys * Update comment links [skip actions]
1 parent c17cc27 commit 10ca004

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

dojo/settings/settings.dist.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@
282282
DD_ENABLE_AUDITLOG=(bool, True),
283283
# Specifies whether the "first seen" date of a given report should be used over the "last seen" date
284284
DD_USE_FIRST_SEEN=(bool, False),
285+
# When set to True, use the older version of the qualys parser that is a more heavy handed in setting severity
286+
# with the use of CVSS scores to potentially override the severity found in the report produced by the tool
287+
DD_QUALYS_LEGACY_SEVERITY_PARSING=(bool, True),
285288
)
286289

287290

@@ -1699,6 +1702,7 @@ def saml2_attrib_map_format(dict):
16991702
AUDITLOG_FLUSH_RETENTION_PERIOD = env('DD_AUDITLOG_FLUSH_RETENTION_PERIOD')
17001703
ENABLE_AUDITLOG = env('DD_ENABLE_AUDITLOG')
17011704
USE_FIRST_SEEN = env('DD_USE_FIRST_SEEN')
1705+
USE_QUALYS_LEGACY_SEVERITY_PARSING = env('DD_QUALYS_LEGACY_SEVERITY_PARSING')
17021706

17031707

17041708
# ------------------------------------------------------------------------------

dojo/tools/qualys/csv_parser.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,30 @@ def _clean_cve_data(cve_string: str) -> list:
109109
return cve_list
110110

111111

112+
def get_severity(value: str) -> str:
113+
legacy_severity_lookup = {
114+
"1": "Info",
115+
"2": "Low",
116+
"3": "Medium",
117+
"4": "High",
118+
"5": "Critical",
119+
}
120+
# Severity mapping taken from
121+
# https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/severity_levels.htm
122+
qualys_severity_lookup = {
123+
"1": "Low",
124+
"2": "Low",
125+
"3": "Medium",
126+
"4": "High",
127+
"5": "High",
128+
}
129+
130+
if settings.USE_QUALYS_LEGACY_SEVERITY_PARSING:
131+
return legacy_severity_lookup.get(value, "Info")
132+
else:
133+
return qualys_severity_lookup.get(value, "Info")
134+
135+
112136
def build_findings_from_dict(report_findings: [dict]) -> [Finding]:
113137
"""
114138
Takes a list of Dictionaries built from CSV and creates a Finding object
@@ -117,13 +141,6 @@ def build_findings_from_dict(report_findings: [dict]) -> [Finding]:
117141
Returns:
118142
119143
"""
120-
severity_lookup = {
121-
"1": "Info",
122-
"2": "Low",
123-
"3": "Medium",
124-
"4": "High",
125-
"5": "Critical",
126-
}
127144
dojo_findings = []
128145
for report_finding in report_findings:
129146
# Get endpoint meta
@@ -167,7 +184,7 @@ def build_findings_from_dict(report_findings: [dict]) -> [Finding]:
167184
title=f"QID-{report_finding['QID']} | {report_finding['Title']}",
168185
mitigation=report_finding["Solution"],
169186
description=f"{report_finding['Threat']}\nResult Evidence: \n{report_finding.get('Threat', 'Not available')}",
170-
severity=severity_lookup.get(report_finding["Severity"], "Info"),
187+
severity=get_severity(report_finding["Severity"]),
171188
impact=report_finding["Impact"],
172189
date=date,
173190
vuln_id_from_tool=report_finding["QID"],

dojo/tools/qualys/parser.py

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,42 @@
5656
}
5757

5858

59+
def get_severity(severity_value: int, cvss_value: float) -> str:
60+
legacy_severity_lookup = {
61+
1: "Informational",
62+
2: "Low",
63+
3: "Medium",
64+
4: "High",
65+
5: "Critical",
66+
}
67+
# Severity mapping taken from
68+
# https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/severity_levels.htm
69+
qualys_severity_lookup = {
70+
1: "Low",
71+
2: "Low",
72+
3: "Medium",
73+
4: "High",
74+
5: "High",
75+
}
76+
77+
if settings.USE_QUALYS_LEGACY_SEVERITY_PARSING:
78+
sev = "Informational"
79+
if cvss_value is not None and cvss_value > 0:
80+
if 0.1 <= float(cvss_value) <= 3.9:
81+
sev = "Low"
82+
elif 4.0 <= float(cvss_value) <= 6.9:
83+
sev = "Medium"
84+
elif 7.0 <= float(cvss_value) <= 8.9:
85+
sev = "High"
86+
elif float(cvss_value) >= 9.0:
87+
sev = "Critical"
88+
elif severity_value is not None:
89+
sev = legacy_severity_lookup.get(severity_value, "Informational")
90+
return sev
91+
else:
92+
return qualys_severity_lookup.get(severity_value, "Informational")
93+
94+
5995
def htmltext(blob):
6096
h = html2text.HTML2Text()
6197
h.ignore_links = False
@@ -211,30 +247,7 @@ def parse_finding(host, tree):
211247
# The CVE in Qualys report might not have a CVSS score, so findings are informational by default
212248
# unless we can find map to a Severity OR a CVSS score from the
213249
# findings detail.
214-
sev = None
215-
if _temp.get("CVSS_value") is not None and _temp["CVSS_value"] > 0:
216-
if 0.1 <= float(_temp["CVSS_value"]) <= 3.9:
217-
sev = "Low"
218-
elif 4.0 <= float(_temp["CVSS_value"]) <= 6.9:
219-
sev = "Medium"
220-
elif 7.0 <= float(_temp["CVSS_value"]) <= 8.9:
221-
sev = "High"
222-
elif float(_temp["CVSS_value"]) >= 9.0:
223-
sev = "Critical"
224-
elif vuln_item.findtext("SEVERITY") is not None:
225-
if int(vuln_item.findtext("SEVERITY")) == 1:
226-
sev = "Informational"
227-
elif int(vuln_item.findtext("SEVERITY")) == 2:
228-
sev = "Low"
229-
elif int(vuln_item.findtext("SEVERITY")) == 3:
230-
sev = "Medium"
231-
elif int(vuln_item.findtext("SEVERITY")) == 4:
232-
sev = "High"
233-
elif int(vuln_item.findtext("SEVERITY")) == 5:
234-
sev = "Critical"
235-
elif sev is None:
236-
sev = "Informational"
237-
250+
sev = get_severity(vuln_item.findtext("SEVERITY"), _temp.get("CVSS_value", None))
238251
finding = None
239252
if _temp_cve_details:
240253
refs = "\n".join(list(_cl.values()))

0 commit comments

Comments
 (0)