From 97fde458b783df035c4606fa0657b710d3d5d177 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:49:03 -0500 Subject: [PATCH 1/2] Add legacy parsing method for qualys --- dojo/settings/settings.dist.py | 4 +++ dojo/tools/qualys/csv_parser.py | 33 +++++++++++++----- dojo/tools/qualys/parser.py | 61 ++++++++++++++++++++------------- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index 409b3636cf2..611bad2b65d 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -282,6 +282,9 @@ DD_ENABLE_AUDITLOG=(bool, True), # Specifies whether the "first seen" date of a given report should be used over the "last seen" date DD_USE_FIRST_SEEN=(bool, False), + # When set to True, use the older version of the qualys parser that is a more heavy handed in setting severity + # with the use of CVSS scores to potentially override the severity found in the report produced by the tool + DD_QUALYS_LEGACY_SEVERITY_PARSING=(bool, True), ) @@ -1699,6 +1702,7 @@ def saml2_attrib_map_format(dict): AUDITLOG_FLUSH_RETENTION_PERIOD = env('DD_AUDITLOG_FLUSH_RETENTION_PERIOD') ENABLE_AUDITLOG = env('DD_ENABLE_AUDITLOG') USE_FIRST_SEEN = env('DD_USE_FIRST_SEEN') +USE_QUALYS_LEGACY_SEVERITY_PARSING = env('DD_QUALYS_LEGACY_SEVERITY_PARSING') # ------------------------------------------------------------------------------ diff --git a/dojo/tools/qualys/csv_parser.py b/dojo/tools/qualys/csv_parser.py index f5f42cad6d8..7eea3f97118 100644 --- a/dojo/tools/qualys/csv_parser.py +++ b/dojo/tools/qualys/csv_parser.py @@ -109,6 +109,30 @@ def _clean_cve_data(cve_string: str) -> list: return cve_list +def get_severity(value: str) -> str: + legacy_severity_lookup = { + "1": "Info", + "2": "Low", + "3": "Medium", + "4": "High", + "5": "Critical", + } + # Severity mapping taken from + # https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/ + qualys_severity_lookup = { + "1": "Low", + "2": "Low", + "3": "Medium", + "4": "High", + "5": "High", + } + + if settings.USE_QUALYS_LEGACY_SEVERITY_PARSING: + return legacy_severity_lookup.get(value, "Info") + else: + return qualys_severity_lookup.get(value, "Info") + + def build_findings_from_dict(report_findings: [dict]) -> [Finding]: """ 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]: Returns: """ - severity_lookup = { - "1": "Info", - "2": "Low", - "3": "Medium", - "4": "High", - "5": "Critical", - } dojo_findings = [] for report_finding in report_findings: # Get endpoint meta @@ -167,7 +184,7 @@ def build_findings_from_dict(report_findings: [dict]) -> [Finding]: title=f"QID-{report_finding['QID']} | {report_finding['Title']}", mitigation=report_finding["Solution"], description=f"{report_finding['Threat']}\nResult Evidence: \n{report_finding.get('Threat', 'Not available')}", - severity=severity_lookup.get(report_finding["Severity"], "Info"), + severity=get_severity(report_finding["Severity"]), impact=report_finding["Impact"], date=date, vuln_id_from_tool=report_finding["QID"], diff --git a/dojo/tools/qualys/parser.py b/dojo/tools/qualys/parser.py index 145869611c7..9e0e3772255 100644 --- a/dojo/tools/qualys/parser.py +++ b/dojo/tools/qualys/parser.py @@ -56,6 +56,42 @@ } +def get_severity(severity_value: int, cvss_value: float) -> str: + legacy_severity_lookup = { + 1: "Informational", + 2: "Low", + 3: "Medium", + 4: "High", + 5: "Critical", + } + # Severity mapping taken from + # https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/ + qualys_severity_lookup = { + 1: "Low", + 2: "Low", + 3: "Medium", + 4: "High", + 5: "High", + } + + if settings.USE_QUALYS_LEGACY_SEVERITY_PARSING: + sev = "Informational" + if cvss_value is not None and cvss_value > 0: + if 0.1 <= float(cvss_value) <= 3.9: + sev = "Low" + elif 4.0 <= float(cvss_value) <= 6.9: + sev = "Medium" + elif 7.0 <= float(cvss_value) <= 8.9: + sev = "High" + elif float(cvss_value) >= 9.0: + sev = "Critical" + elif severity_value is not None: + sev = legacy_severity_lookup.get(severity_value, "Informational") + return sev + else: + return qualys_severity_lookup.get(severity_value, "Informational") + + def htmltext(blob): h = html2text.HTML2Text() h.ignore_links = False @@ -211,30 +247,7 @@ def parse_finding(host, tree): # The CVE in Qualys report might not have a CVSS score, so findings are informational by default # unless we can find map to a Severity OR a CVSS score from the # findings detail. - sev = None - if _temp.get("CVSS_value") is not None and _temp["CVSS_value"] > 0: - if 0.1 <= float(_temp["CVSS_value"]) <= 3.9: - sev = "Low" - elif 4.0 <= float(_temp["CVSS_value"]) <= 6.9: - sev = "Medium" - elif 7.0 <= float(_temp["CVSS_value"]) <= 8.9: - sev = "High" - elif float(_temp["CVSS_value"]) >= 9.0: - sev = "Critical" - elif vuln_item.findtext("SEVERITY") is not None: - if int(vuln_item.findtext("SEVERITY")) == 1: - sev = "Informational" - elif int(vuln_item.findtext("SEVERITY")) == 2: - sev = "Low" - elif int(vuln_item.findtext("SEVERITY")) == 3: - sev = "Medium" - elif int(vuln_item.findtext("SEVERITY")) == 4: - sev = "High" - elif int(vuln_item.findtext("SEVERITY")) == 5: - sev = "Critical" - elif sev is None: - sev = "Informational" - + sev = get_severity(vuln_item.findtext("SEVERITY"), _temp.get("CVSS_value", None)) finding = None if _temp_cve_details: refs = "\n".join(list(_cl.values())) From 171134df1a589388d9fd2734d5fd3ec4de6c1c26 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:32:52 -0500 Subject: [PATCH 2/2] Update comment links [skip actions] --- dojo/tools/qualys/csv_parser.py | 2 +- dojo/tools/qualys/parser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dojo/tools/qualys/csv_parser.py b/dojo/tools/qualys/csv_parser.py index 7eea3f97118..53b792af8b9 100644 --- a/dojo/tools/qualys/csv_parser.py +++ b/dojo/tools/qualys/csv_parser.py @@ -118,7 +118,7 @@ def get_severity(value: str) -> str: "5": "Critical", } # Severity mapping taken from - # https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/ + # https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/severity_levels.htm qualys_severity_lookup = { "1": "Low", "2": "Low", diff --git a/dojo/tools/qualys/parser.py b/dojo/tools/qualys/parser.py index 9e0e3772255..a415b4487f5 100644 --- a/dojo/tools/qualys/parser.py +++ b/dojo/tools/qualys/parser.py @@ -65,7 +65,7 @@ def get_severity(severity_value: int, cvss_value: float) -> str: 5: "Critical", } # Severity mapping taken from - # https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/ + # https://qualysguard.qg2.apps.qualys.com/portal-help/en/malware/knowledgebase/severity_levels.htm qualys_severity_lookup = { 1: "Low", 2: "Low",