Skip to content

Commit 96ae5ed

Browse files
ms_defender: Improve reliability and error handling (#11898)
* ms_defender: Improve reliability and error handling * ms_defender: Improve reliability and error handling
1 parent 2c9a32f commit 96ae5ed

File tree

3 files changed

+61
-41
lines changed

3 files changed

+61
-41
lines changed

dojo/tools/ms_defender/parser.py

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import json
2+
import logging
23
import zipfile
34

45
from dojo.models import Endpoint, Finding
56

7+
logger = logging.getLogger(__name__)
8+
69

710
class MSDefenderParser:
811

@@ -53,22 +56,29 @@ def get_findings(self, file, test):
5356
machines[data.get("id")] = data
5457
for vulnerability in vulnerabilities:
5558
try:
56-
self.process_zip(vulnerability, machines[vulnerability["machineId"]])
59+
machine = machines.get(vulnerability["machineId"], None)
60+
if machine is not None:
61+
self.process_zip(vulnerability, machine)
62+
else:
63+
logger.debug("fallback to process without machine: no machine id")
64+
self.process_json(vulnerability)
5765
except (IndexError, KeyError):
66+
logger.exception("fallback to process without machine: exception")
5867
self.process_json(vulnerability)
5968
else:
6069
return []
6170
return self.findings
6271

6372
def process_json(self, vulnerability):
6473
description = ""
65-
description += "cveId: " + str(vulnerability["cveId"]) + "\n"
66-
description += "machineId: " + str(vulnerability["machineId"]) + "\n"
67-
description += "fixingKbId: " + str(vulnerability["fixingKbId"]) + "\n"
68-
description += "productName: " + str(vulnerability["productName"]) + "\n"
69-
description += "productVendor: " + str(vulnerability["productVendor"]) + "\n"
70-
description += "productVersion: " + str(vulnerability["productVersion"]) + "\n"
71-
title = str(vulnerability["cveId"])
74+
description += "cveId: " + str(vulnerability.get("cveId", "")) + "\n"
75+
description += "machineId: " + str(vulnerability.get("machineId", "")) + "\n"
76+
description += "fixingKbId: " + str(vulnerability.get("fixingKbId", "")) + "\n"
77+
description += "productName: " + str(vulnerability.get("productName", "")) + "\n"
78+
description += "productVendor: " + str(vulnerability.get("productVendor", "")) + "\n"
79+
description += "productVersion: " + str(vulnerability.get("productVersion", "")) + "\n"
80+
description += "machine Info: " + "Unable to find or parse machine data, check logs for more information" + "\n"
81+
title = str(vulnerability.get("cveId", ""))
7282
finding = Finding(
7383
title=title + "_" + vulnerability["machineId"],
7484
severity=self.severity_check(vulnerability["severity"]),
@@ -86,35 +96,35 @@ def process_json(self, vulnerability):
8696

8797
def process_zip(self, vulnerability, machine):
8898
description = ""
89-
description += "cveId: " + str(vulnerability["cveId"]) + "\n"
90-
description += "machineId: " + str(vulnerability["machineId"]) + "\n"
91-
description += "fixingKbId: " + str(vulnerability["fixingKbId"]) + "\n"
92-
description += "productName: " + str(vulnerability["productName"]) + "\n"
93-
description += "productVendor: " + str(vulnerability["productVendor"]) + "\n"
94-
description += "productVersion: " + str(vulnerability["productVersion"]) + "\n"
95-
description += "machine Info: id: " + str(machine["id"]) + "\n"
96-
description += "machine Info: osPlatform: " + str(machine["osPlatform"]) + "\n"
97-
description += "machine Info: osVersion: " + str(machine["osVersion"]) + "\n"
98-
description += "machine Info: osProcessor: " + str(machine["osProcessor"]) + "\n"
99-
description += "machine Info: version: " + str(machine["version"]) + "\n"
100-
description += "machine Info: agentVersion: " + str(machine["agentVersion"]) + "\n"
101-
description += "machine Info: osBuild: " + str(machine["osBuild"]) + "\n"
102-
description += "machine Info: healthStatus: " + str(machine["healthStatus"]) + "\n"
103-
description += "machine Info: deviceValue: " + str(machine["deviceValue"]) + "\n"
104-
description += "machine Info: rbacGroupId: " + str(machine["rbacGroupId"]) + "\n"
105-
description += "machine Info: rbacGroupName: " + str(machine["rbacGroupName"]) + "\n"
106-
description += "machine Info: riskScore: " + str(machine["riskScore"]) + "\n"
107-
description += "machine Info: exposureLevel: " + str(machine["exposureLevel"]) + "\n"
108-
description += "machine Info: isAadJoined: " + str(machine["isAadJoined"]) + "\n"
109-
description += "machine Info: aadDeviceId: " + str(machine["aadDeviceId"]) + "\n"
110-
description += "machine Info: defenderAvStatus: " + str(machine["defenderAvStatus"]) + "\n"
111-
description += "machine Info: onboardingStatus: " + str(machine["onboardingStatus"]) + "\n"
112-
description += "machine Info: osArchitecture: " + str(machine["osArchitecture"]) + "\n"
113-
description += "machine Info: managedBy: " + str(machine["managedBy"]) + "\n"
114-
title = str(vulnerability["cveId"])
115-
if str(machine["computerDnsName"]) != "null":
99+
description += "cveId: " + str(vulnerability.get("cveId", "")) + "\n"
100+
description += "machineId: " + str(vulnerability.get("machineId", "")) + "\n"
101+
description += "fixingKbId: " + str(vulnerability.get("fixingKbId", "")) + "\n"
102+
description += "productName: " + str(vulnerability.get("productName", "")) + "\n"
103+
description += "productVendor: " + str(vulnerability.get("productVendor", "")) + "\n"
104+
description += "productVersion: " + str(vulnerability.get("productVersion", "")) + "\n"
105+
description += "machine Info: id: " + str(machine.get("id", "")) + "\n"
106+
description += "machine Info: osPlatform: " + str(machine.get("osPlatform", "")) + "\n"
107+
description += "machine Info: osVersion: " + str(machine.get("osVersion", "")) + "\n"
108+
description += "machine Info: osProcessor: " + str(machine.get("osProcessor", "")) + "\n"
109+
description += "machine Info: version: " + str(machine.get("version", "")) + "\n"
110+
description += "machine Info: agentVersion: " + str(machine.get("agentVersion", "")) + "\n"
111+
description += "machine Info: osBuild: " + str(machine.get("osBuild", "")) + "\n"
112+
description += "machine Info: healthStatus: " + str(machine.get("healthStatus", "")) + "\n"
113+
description += "machine Info: deviceValue: " + str(machine.get("deviceValue", "")) + "\n"
114+
description += "machine Info: rbacGroupId: " + str(machine.get("rbacGroupId", "")) + "\n"
115+
description += "machine Info: rbacGroupName: " + str(machine.get("rbacGroupName", "")) + "\n"
116+
description += "machine Info: riskScore: " + str(machine.get("riskScore", "")) + "\n"
117+
description += "machine Info: exposureLevel: " + str(machine.get("exposureLevel", "")) + "\n"
118+
description += "machine Info: isAadJoined: " + str(machine.get("isAadJoined", "")) + "\n"
119+
description += "machine Info: aadDeviceId: " + str(machine.get("aadDeviceId", "")) + "\n"
120+
description += "machine Info: defenderAvStatus: " + str(machine.get("defenderAvStatus", "")) + "\n"
121+
description += "machine Info: onboardingStatus: " + str(machine.get("onboardingStatus", "")) + "\n"
122+
description += "machine Info: osArchitecture: " + str(machine.get("osArchitecture", "")) + "\n"
123+
description += "machine Info: managedBy: " + str(machine.get("managedBy", "")) + "\n"
124+
title = str(vulnerability.get("cveId", ""))
125+
if "computerDnsName" in machine and str(machine["computerDnsName"]) != "null":
116126
title = title + "_" + str(machine["computerDnsName"])
117-
if str(machine["osPlatform"]) != "null":
127+
if "osPlatform" in machine and str(machine["osPlatform"]) != "null":
118128
title = title + "_" + str(machine["osPlatform"])
119129
finding = Finding(
120130
title=title + "_" + vulnerability["machineId"],
@@ -123,18 +133,18 @@ def process_zip(self, vulnerability, machine):
123133
static_finding=False,
124134
dynamic_finding=True,
125135
)
126-
if vulnerability["fixingKbId"] is not None:
136+
if "fixingKbId" in vulnerability and vulnerability["fixingKbId"] is not None:
127137
finding.mitigation = vulnerability["fixingKbId"]
128-
if vulnerability["cveId"] is not None:
138+
if "cveId" in vulnerability:
129139
finding.unsaved_vulnerability_ids = []
130140
finding.unsaved_vulnerability_ids.append(vulnerability["cveId"])
131141
self.findings.append(finding)
132142
finding.unsaved_endpoints = []
133-
if machine["computerDnsName"] is not None:
143+
if "computerDnsName" in machine and machine["computerDnsName"] is not None:
134144
finding.unsaved_endpoints.append(Endpoint(host=str(machine["computerDnsName"]).replace(" ", "").replace("(", "_").replace(")", "_")))
135-
if machine["lastIpAddress"] is not None:
145+
if "lastIpAddress" in machine and machine["lastIpAddress"] is not None:
136146
finding.unsaved_endpoints.append(Endpoint(host=str(machine["lastIpAddress"])))
137-
if machine["lastExternalIpAddress"] is not None:
147+
if "lastExternalIpAddress" in machine and machine["lastExternalIpAddress"] is not None:
138148
finding.unsaved_endpoints.append(Endpoint(host=str(machine["lastExternalIpAddress"])))
139149

140150
def severity_check(self, input):
Binary file not shown.

unittests/tools/test_ms_defender_parser.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ def test_parser_defender_issue_11217(self):
8181
endpoint.clean()
8282
self.assertEqual("Max_Mustermann_iPadAir_17zoll__2ndgeneration_", finding.unsaved_endpoints[0].host)
8383

84+
def test_parser_defender_error_handling(self):
85+
"""https://github.com/DefectDojo/django-DefectDojo/issues/11896 handle missing values properly, i.e. defenderAvStatus"""
86+
testfile = open(get_unit_tests_scans_path("ms_defender") / "defender_error_handling.zip", encoding="utf-8")
87+
parser = MSDefenderParser()
88+
findings = parser.get_findings(testfile, Test())
89+
testfile.close()
90+
self.assertEqual(421, len(findings))
91+
finding = findings[0]
92+
self.assertEqual(3, len(finding.unsaved_endpoints))
93+
8494
def test_parser_defender_empty_machines(self):
8595
testfile = open(get_unit_tests_scans_path("ms_defender") / "empty_machines.zip", encoding="utf-8")
8696
parser = MSDefenderParser()

0 commit comments

Comments
 (0)