-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Checkmarx Cxflow SAST parser (#9719)
* draf parser * fix typo * draft parser path node * add parser * add dedup aglo * integration docs * commented unused var * Revert "Merge remote-tracking branch 'upstream/dev' into feature-checkmarx-cxflow-sast" This reverts commit b167f2b5205b427ac0b26ae7fd3f6b4667a01cde, reversing changes made to 5257a25204dbc9e6603b3b64bc1d78eddb824140. * Revert "Revert "Merge remote-tracking branch 'upstream/dev' into feature-checkmarx-cxflow-sast"" This reverts commit f9cdafb. * update doc and remove unused var * update parser * update parser test * Revert "update parser test" This reverts commit c159233. * fix ruff * Update .settings.dist.py.sha256sum * fix ruff * fix ruff * fix ruff #n * trigger ci * trigger ci * Fix ruff --------- Co-authored-by: biennd4 <[email protected]> Co-authored-by: Cody Maffucci <[email protected]>
- Loading branch information
1 parent
cd12513
commit 7ecef22
Showing
8 changed files
with
1,680 additions
and
0 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
docs/content/en/connecting_your_tools/parsers/file/checkmarx_cxflow_sast.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
title: "Checkmarx CxFlow SAST" | ||
toc_hide: true | ||
--- | ||
|
||
CxFlow is a Spring Boot application written by Checkmarx that enables initiations of scans and result orchestration. | ||
CxFlow support interactive with various Checkmarx product. | ||
This parser support JSON format export by bug tracker. | ||
|
||
``` | ||
#YAML | ||
cx-flow: | ||
bug-tracker:Json | ||
#CLI | ||
--cx-flow.bug-tracker=json | ||
``` | ||
|
||
- `Checkmarx CxFlow SAST`: JSON report from Checkmarx Cxflow. | ||
|
||
### Sample Scan Data | ||
Sample Checkmarx CxFlow SAST scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/checkmarx_cxflow_sast). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import json | ||
import logging | ||
|
||
import dateutil.parser | ||
|
||
from dojo.models import Finding | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class _PathNode: | ||
def __init__(self, file: str, line: str, column: str, node_object: str, length: str, snippet: str): | ||
self.file = file | ||
self.line = line | ||
self.column = int(column) | ||
self.node_object = node_object | ||
self.length = int(length) | ||
self.snippet = snippet | ||
|
||
@classmethod | ||
def from_json_object(cls, data): | ||
return _PathNode( | ||
data.get("file"), | ||
data.get("line"), | ||
data.get("column"), | ||
data.get("object"), | ||
data.get("length"), | ||
data.get("snippet"), | ||
) | ||
|
||
|
||
class _Path: | ||
def __init__(self, sink: _PathNode, source: _PathNode, state: str, paths: [_PathNode]): | ||
self.sink = sink | ||
self.source = source | ||
self.state = state | ||
self.paths = paths | ||
|
||
|
||
class CheckmarxCXFlowSastParser: | ||
def __init__(self): | ||
pass | ||
|
||
def get_scan_types(self): | ||
return ["Checkmarx CxFlow SAST"] | ||
|
||
def get_label_for_scan_types(self, scan_type): | ||
return scan_type # no custom label for now | ||
|
||
def get_description_for_scan_types(self, scan_type): | ||
return "Detailed Report. Import all vulnerabilities from checkmarx without aggregation" | ||
|
||
def get_findings(self, file, test): | ||
if file.name.strip().lower().endswith(".json"): | ||
return self._get_findings_json(file, test) | ||
# TODO: support CxXML format | ||
logger.warning(f"Not supported file format ${file}") | ||
return [] | ||
|
||
def _get_findings_json(self, file, test): | ||
data = json.load(file) | ||
findings = [] | ||
additional_details = data.get("additionalDetails") | ||
scan_start_date = additional_details.get("scanStartDate") | ||
|
||
issues = data.get("xissues", []) | ||
|
||
for issue in issues: | ||
vulnerability = issue.get("vulnerability") | ||
status = issue.get("vulnerabilityStatus") | ||
cwe = issue.get("cwe") | ||
description = issue.get("description") | ||
language = issue.get("language") | ||
severity = issue.get("severity") | ||
link = issue.get("link") | ||
filename = issue.get("filename") | ||
similarity_id = issue.get("similarityId") | ||
|
||
issue_additional_details = issue.get("additionalDetails") | ||
categories = issue_additional_details.get("categories") | ||
results = issue_additional_details.get("results") | ||
|
||
map_paths = {} | ||
|
||
for result in results: | ||
# all path nodes exclude sink, source, state | ||
path_keys = sorted(filter(lambda k: isinstance(k, str) and k.isnumeric(), result.keys())) | ||
|
||
path = _Path( | ||
sink=_PathNode.from_json_object(result.get("sink")), | ||
source=_PathNode.from_json_object(result.get("source")), | ||
state=result.get("state"), | ||
paths=[result[k] for k in path_keys], | ||
) | ||
|
||
map_paths[str(path.source.line)] = path | ||
|
||
for detail_key in issue.get("details"): | ||
if detail_key not in map_paths: | ||
logger.warning(f"{detail_key} not found in path, ignore") | ||
else: | ||
detail = map_paths[detail_key] | ||
|
||
finding_detail = f"**Category:** {categories}\n" | ||
finding_detail += f"**Language:** {language}\n" | ||
finding_detail += f"**Status:** {status}\n" | ||
finding_detail += f"**Finding link:** [{link}]({link})\n" | ||
finding_detail += f"**Description:** {description}\n" | ||
finding_detail += f"**Source snippet:** `{detail.source.snippet if detail.source is not None else ''}`\n" | ||
finding_detail += f"**Sink snippet:** `{detail.sink.snippet if detail.sink is not None else ''}`\n" | ||
|
||
finding = Finding( | ||
title=vulnerability.replace("_", " ") + " " + detail.sink.file.split("/")[ | ||
-1] if detail.sink is not None else "", | ||
cwe=int(cwe), | ||
date=dateutil.parser.parse(scan_start_date), | ||
static_finding=True, | ||
test=test, | ||
sast_source_object=detail.source.node_object if detail.source is not None else None, | ||
sast_sink_object=detail.sink.node_object if detail.sink is not None else None, | ||
sast_source_file_path=detail.source.file if detail.source is not None else None, | ||
sast_source_line=detail.source.line if detail.source is not None else None, | ||
vuln_id_from_tool=similarity_id, | ||
severity=severity, | ||
file_path=filename, | ||
line=detail.sink.line, | ||
false_p=issue.get("details")[detail_key].get("falsePositive") or self.is_not_exploitable( | ||
detail.state), | ||
description=finding_detail, | ||
verified=self.is_verify(detail.state), | ||
active=self.is_active(detail.state), | ||
) | ||
|
||
findings.append(finding) | ||
|
||
return findings | ||
|
||
def is_verify(self, state): | ||
# Confirmed, urgent | ||
verifiedStates = ["2", "3"] | ||
return state in verifiedStates | ||
|
||
def is_active(self, state): | ||
# To verify, Confirmed, Urgent, Proposed not exploitable | ||
activeStates = ["0", "2", "3", "4"] | ||
return state in activeStates | ||
|
||
def is_not_exploitable(self, state): | ||
return state == "1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
{ | ||
"projectId": "6", | ||
"team": "CxServer", | ||
"project": "some-example", | ||
"link": "http://CX-FLOW-CLEAN/CxWebClient/ViewerMain.aspx?scanid=1000026&projectid=6", | ||
"files": "1", | ||
"loc": "268", | ||
"scanType": "Full", | ||
"version":"8.9.0.210", | ||
"additionalDetails": { | ||
"flow-summary": { | ||
"High": 1 | ||
}, | ||
"scanId": "1000026", | ||
"scanStartDate": "Sunday, January 19, 2020 2:40:11 AM" | ||
}, | ||
"xissues": [ | ||
{ | ||
"vulnerability": "Reflected_XSS_All_Clients", | ||
"vulnerabilityStatus": "TO VERIFY", | ||
"similarityId": "14660819", | ||
"cwe": "79", | ||
"description": "", | ||
"language": "Java", | ||
"severity": "High", | ||
"link": "http://CX-FLOW-CLEAN/CxWebClient/ViewerMain.aspx?scanid=1000026&projectid=6&pathid=2", | ||
"filename": "DOS_Login.java", | ||
"falsePositiveCount": 0, | ||
"details": { | ||
"88": { | ||
"falsePositive": false, | ||
"codeSnippet": "username = s.getParser().getRawParameter(USERNAME);", | ||
"comment": "" | ||
} | ||
}, | ||
"additionalDetails": { | ||
"recommendedFix": "http://CX-FLOW-CLEAN/CxWebClient/ScanQueryDescription.aspx?queryID=591&queryVersionCode=56110529&queryTitle=Reflected_XSS_All_Clients", | ||
"categories": "PCI DSS v3.2;PCI DSS (3.2) - 6.5.7 - Cross-site scripting (XSS),OWASP Top 10 2013;A3-Cross-Site Scripting (XSS),FISMA 2014;System And Information Integrity,NIST SP 800-53;SI-15 Information Output Filtering (P0),OWASP Top 10 2017;A7-Cross-Site Scripting (XSS)", | ||
"results": [ | ||
{ | ||
"sink": { | ||
"file": "AnotherFile.java", | ||
"line": "107", | ||
"column": "9", | ||
"object": "username", | ||
"length" : "8", | ||
"snippet" : "+ username + \"' and password = '\" + password + \"'\";" | ||
}, | ||
"state": "0", | ||
"source": { | ||
"file": "DOS_Login.java", | ||
"line": "88", | ||
"column": "46", | ||
"object": "getRawParameter", | ||
"length" : "1", | ||
"snippet" : "username = s.getParser().getRawParameter(USERNAME);" | ||
}, | ||
"1" : { | ||
"snippet" : "username = s.getParser().getRawParameter(USERNAME);", | ||
"file" : "DOS_Login.java", | ||
"line" : "88", | ||
"column" : "46", | ||
"length" : "1", | ||
"object" : "getRawParameter" | ||
}, | ||
"2" : { | ||
"snippet" : "username = s.getParser().getRawParameter(USERNAME);", | ||
"file" : "DOS_Login.java", | ||
"line" : "88", | ||
"column" : "6", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"3" : { | ||
"snippet" : "if (username.equals(\"jeff\") || username.equals(\"dave\"))", | ||
"file" : "DOS_Login.java", | ||
"line" : "92", | ||
"column" : "37", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"4" : { | ||
"snippet" : "if (username.equals(\"jeff\") || username.equals(\"dave\"))", | ||
"file" : "DOS_Login.java", | ||
"line" : "92", | ||
"column" : "10", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"5" : { | ||
"snippet" : "+ username + \"' and password = '\" + password + \"'\";", | ||
"file" : "AnotherFile.java", | ||
"line" : "107", | ||
"column" : "9", | ||
"length" : "8", | ||
"object" : "username" | ||
} | ||
} | ||
], | ||
"CodeBashingLesson" : "https://cxa.codebashing.com/courses/" | ||
}, | ||
"allFalsePositive": false | ||
} | ||
], | ||
"unFilteredIssues": [ { | ||
"vulnerability" : "Reflected_XSS_All_Clients", | ||
"vulnerabilityStatus" : "TO VERIFY", | ||
"similarityId" : "14660819", | ||
"cwe" : "79", | ||
"description" : "", | ||
"language" : "Java", | ||
"severity" : "High", | ||
"link" : "http://CX-FLOW-CLEAN/CxWebClient/ViewerMain.aspx?scanid=1000026&projectid=6&pathid=2", | ||
"filename" : "DOS_Login.java", | ||
"gitUrl" : "", | ||
"falsePositiveCount" : 0, | ||
"details" : { | ||
"88" : { | ||
"falsePositive" : false, | ||
"comment" : "" | ||
} | ||
}, | ||
"additionalDetails" : { | ||
"recommendedFix" : "http://CX-FLOW-CLEAN/CxWebClient/ScanQueryDescription.aspx?queryID=591&queryVersionCode=56110529&queryTitle=Reflected_XSS_All_Clients", | ||
"categories" : "PCI DSS v3.2;PCI DSS (3.2) - 6.5.7 - Cross-site scripting (XSS),OWASP Top 10 2013;A3-Cross-Site Scripting (XSS),FISMA 2014;System And Information Integrity,NIST SP 800-53;SI-15 Information Output Filtering (P0),OWASP Top 10 2017;A7-Cross-Site Scripting (XSS)", | ||
"results" : [ { | ||
"1" : { | ||
"snippet" : "username = s.getParser().getRawParameter(USERNAME);", | ||
"file" : "DOS_Login.java", | ||
"line" : "88", | ||
"column" : "46", | ||
"length" : "1", | ||
"object" : "getRawParameter" | ||
}, | ||
"2" : { | ||
"snippet" : "username = s.getParser().getRawParameter(USERNAME);", | ||
"file" : "DOS_Login.java", | ||
"line" : "88", | ||
"column" : "6", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"3" : { | ||
"snippet" : "if (username.equals(\"jeff\") || username.equals(\"dave\"))", | ||
"file" : "DOS_Login.java", | ||
"line" : "92", | ||
"column" : "37", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"4" : { | ||
"snippet" : "if (username.equals(\"jeff\") || username.equals(\"dave\"))", | ||
"file" : "DOS_Login.java", | ||
"line" : "92", | ||
"column" : "10", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"5" : { | ||
"snippet" : "+ username + \"' and password = '\" + password + \"'\";", | ||
"file" : "AnotherFile.java", | ||
"line" : "107", | ||
"column" : "9", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"sink" : { | ||
"snippet" : "+ username + \"' and password = '\" + password + \"'\";", | ||
"file" : "AnotherFile.java", | ||
"line" : "107", | ||
"column" : "9", | ||
"length" : "8", | ||
"object" : "username" | ||
}, | ||
"state" : "0", | ||
"source" : { | ||
"snippet" : "username = s.getParser().getRawParameter(USERNAME);", | ||
"file" : "DOS_Login.java", | ||
"line" : "88", | ||
"column" : "46", | ||
"length" : "1", | ||
"object" : "getRawParameter" | ||
} | ||
} ] | ||
}, | ||
"allFalsePositive" : false | ||
} ], | ||
"reportCreationTime":"Sunday, January 19, 2020 2:41:53 AM", | ||
"deepLink":"http://CX-FLOW-CLEAN/CxWebClient/ViewerMain.aspx?scanid=1000026&projectid=6", | ||
"scanTime":"00h:01m:30s", | ||
"sastResults": false | ||
} |
Oops, something went wrong.