diff --git a/dojo/tools/contrast/parser.py b/dojo/tools/contrast/parser.py index 5131c96279e..4a82ee3c445 100644 --- a/dojo/tools/contrast/parser.py +++ b/dojo/tools/contrast/parser.py @@ -90,7 +90,7 @@ def get_findings(self, filename, test): ) dupe_key = hashlib.sha256( - f"{finding.vuln_id_from_tool}".encode(), + f"{finding.unique_id_from_tool}".encode(), ).digest() if dupe_key in dupes: diff --git a/unittests/scans/contrast/ldap-multiple.csv b/unittests/scans/contrast/ldap-multiple.csv new file mode 100644 index 00000000000..e2e9a9a9270 --- /dev/null +++ b/unittests/scans/contrast/ldap-multiple.csv @@ -0,0 +1,4 @@ +Vulnerability Name,Vulnerability ID,Category,Rule Name,Severity,Status,Number of Events,First Seen,First Seen Datetime,Last Seen,Last Seen Datetime,Application Name,Application ID,Application Code,CWE ID,Request Method,Request Port,Request Protocol,Request Version,Request URI,Request Qs,Request Body +LDAP Injection from "username" Parameter,AAAA-1111-BBBB-2222,Injection,ldap-injection,High,Reported,1,1590144840000,2020-05-22T10:54:00.000Z,1600686000000,2020-09-21T11:00:00.000Z,my-app,app-id-001,,https://cwe.mitre.org/data/definitions/90.html,GET,8080,http,HTTP/1.1,/login,, +LDAP Injection from "group" Parameter,CCCC-3333-DDDD-4444,Injection,ldap-injection,High,Reported,1,1590144840000,2020-05-22T10:54:00.000Z,1600686000000,2020-09-21T11:00:00.000Z,my-app,app-id-001,,https://cwe.mitre.org/data/definitions/90.html,GET,8080,http,HTTP/1.1,/admin,, +LDAP Injection from "filter" Parameter,EEEE-5555-FFFF-6666,Injection,ldap-injection,High,Reported,1,1590144840000,2020-05-22T10:54:00.000Z,1600686000000,2020-09-21T11:00:00.000Z,my-app,app-id-001,,https://cwe.mitre.org/data/definitions/90.html,POST,8080,http,HTTP/1.1,/api/users,, diff --git a/unittests/scans/contrast/path-traversal-duplicate-vuln-id.csv b/unittests/scans/contrast/path-traversal-duplicate-vuln-id.csv new file mode 100644 index 00000000000..f5b6a7def86 --- /dev/null +++ b/unittests/scans/contrast/path-traversal-duplicate-vuln-id.csv @@ -0,0 +1,3 @@ +Vulnerability Name,Vulnerability ID,Category,Rule Name,Severity,Status,Number of Events,First Seen,First Seen Datetime,Last Seen,Last Seen Datetime,Application Name,Application ID,Application Code,CWE ID,Request Method,Request Port,Request Protocol,Request Version,Request URI,Request Qs,Request Body +Path Traversal from "file" Parameter,AAAA-1111-BBBB-2222,Injection,path-traversal,High,Reported,1,1590144840000,2020-05-22T10:54:00.000Z,1600686000000,2020-09-21T11:00:00.000Z,my-app,app-id-001,,https://cwe.mitre.org/data/definitions/22.html,GET,8080,http,HTTP/1.1,/download,, +Path Traversal from "file" Parameter,AAAA-1111-BBBB-2222,Injection,path-traversal,High,Reported,1,1590144840000,2020-05-22T10:54:00.000Z,1600686000000,2020-09-21T11:00:00.000Z,my-app,app-id-001,,https://cwe.mitre.org/data/definitions/22.html,GET,8080,http,HTTP/1.1,/upload,, diff --git a/unittests/tools/test_contrast_parser.py b/unittests/tools/test_contrast_parser.py index ea97422a00c..0fe82e18c2b 100644 --- a/unittests/tools/test_contrast_parser.py +++ b/unittests/tools/test_contrast_parser.py @@ -15,7 +15,7 @@ def test_example_report(self): parser = ContrastParser() findings = parser.get_findings(testfile, test) self.validate_locations(findings) - self.assertEqual(18, len(findings)) + self.assertEqual(52, len(findings)) with self.subTest(i=0): finding = findings[0] self.assertEqual("Info", finding.severity) @@ -30,25 +30,36 @@ def test_example_report(self): self.assertEqual("http", location.protocol) self.assertEqual("0.0.0.0", location.host) # noqa: S104 self.assertEqual("WebGoat/login.mvc", location.path) - with self.subTest(i=11): - finding = findings[11] - self.assertEqual(datetime.date(2018, 4, 23), finding.date.date()) + + def test_ldap_multiple_findings(self): + test = Test() + test.engagement = Engagement() + test.engagement.product = Product() + with (get_unit_tests_scans_path("contrast") / "ldap-multiple.csv").open(encoding="utf-8") as testfile: + parser = ContrastParser() + findings = parser.get_findings(testfile, test) + self.assertEqual(3, len(findings)) + vuln_ids = [f.unique_id_from_tool for f in findings] + self.assertEqual(len(vuln_ids), len(set(vuln_ids)), "Each finding should have a distinct unique_id_from_tool") + for finding in findings: + self.assertEqual("ldap-injection", finding.vuln_id_from_tool) self.assertEqual("High", finding.severity) - self.assertEqual("path-traversal", finding.vuln_id_from_tool) - self.assertIsNone(finding.unique_id_from_tool) # aggregated finding - self.assertEqual(4, finding.nb_occurences) - self.assertEqual(22, finding.cwe) - # endpoints - self.assertIsNotNone(self.get_unsaved_locations(finding)) - self.assertEqual(4, len(self.get_unsaved_locations(finding))) - location = self.get_unsaved_locations(finding)[0] - self.assertEqual("http", location.protocol) - self.assertEqual("0.0.0.0", location.host) # noqa: S104 - self.assertEqual("WebGoat/services/SoapRequest", location.path) - location = self.get_unsaved_locations(finding)[1] - self.assertEqual("http", location.protocol) - self.assertEqual("0.0.0.0", location.host) # noqa: S104 - self.assertEqual("WebGoat/attack", location.path) + self.assertIsNotNone(finding.unique_id_from_tool) + + def test_duplicate_vuln_id_is_merged(self): + test = Test() + test.engagement = Engagement() + test.engagement.product = Product() + with (get_unit_tests_scans_path("contrast") / "path-traversal-duplicate-vuln-id.csv").open(encoding="utf-8") as testfile: + parser = ContrastParser() + findings = parser.get_findings(testfile, test) + self.assertEqual(1, len(findings)) + finding = findings[0] + self.assertEqual("path-traversal", finding.vuln_id_from_tool) + self.assertIsNone(finding.unique_id_from_tool) + self.assertEqual(2, finding.nb_occurences) + self.assertEqual(22, finding.cwe) + self.assertEqual(2, len(self.get_unsaved_locations(finding))) def test_example2_report(self): test = Test()