Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add legacy parsing method for qualys #9861

Merged
merged 2 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions dojo/settings/settings.dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)


Expand Down Expand Up @@ -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')


# ------------------------------------------------------------------------------
Expand Down
33 changes: 25 additions & 8 deletions dojo/tools/qualys/csv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/severity_levels.htm
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
Expand All @@ -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
Expand Down Expand Up @@ -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"],
Expand Down
61 changes: 37 additions & 24 deletions dojo/tools/qualys/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/severity_levels.htm
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
Expand Down Expand Up @@ -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()))
Expand Down
Loading