Skip to content

Commit 9b8cfb6

Browse files
committed
Add support for OWASP ZAP reports with merged alerts
Change class ZapReader to cope with reports that contain merged alerts. Since version 2.4.2 of OWASP ZAP it's possible to create reports where alerts of same type are merged into one (which greatly reduce the size of the report by removing duplicated information). One single alert can have multiple URIs and its details (param, attack and evidence). The XML structure of reports with merged alerts is changed from: <alert> <!-- other alert details (name, description, cweid...) --> <uri /> <param /> <attack /> <evidence /> </alert> to: <alert> <!-- other alert details (name, description, cweid...) --> <instances> <instance> <uri /> <param /> <attack /> <evidence /> </instance> <!-- more "instance" elements per merged alert --> </instances> </alert> The class ZapReader now checks for the presence of "instances" element in the alert, if it has it, it creates a TestCaseResult per "instance" element otherwise it's created just one TestCaseResult, as before.
1 parent fcbf203 commit 9b8cfb6

File tree

1 file changed

+67
-17
lines changed

1 file changed

+67
-17
lines changed

src/main/java/org/owasp/benchmark/score/parsers/ZapReader.java

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,7 @@ public TestResults parse(File f) throws Exception {
5454

5555
for ( Node flaw : issueList ) {
5656
try {
57-
TestCaseResult tcr = parseZapIssue(flaw);
58-
if (tcr != null ) {
59-
// System.out.println( tcr.getNumber() + " " + tcr.getName() + " -> " + tcr.getCWE() + "\t" + tcr.getEvidence() );
60-
tr.put(tcr);
61-
}
57+
parseAndAddZapIssues(flaw, tr);
6258
} catch( Exception e ) {
6359
// print and continue
6460
e.printStackTrace();
@@ -80,9 +76,20 @@ public TestResults parse(File f) throws Exception {
8076
// <riskdesc>Low (Medium)</riskdesc>
8177
// <desc>Web Browser XSS Protection is not enabled, or is disabled by the configuration of the 'X-XSS-Protection' HTTP response header on the web server
8278
// </desc>
79+
8380
// <uri>http://localhost:8080/benchmark/BenchmarkTest00028.html</uri>
8481
// <param/>
8582
// <attack/>
83+
// OR, for merged reports:
84+
// <instances>
85+
// <instance>
86+
// <uri>http://localhost:8080/benchmark/BenchmarkTest00028.html</uri>
87+
// <param/>
88+
// <attack/>
89+
// </instance>
90+
// <!-- more "instance" elements per merged alert -->
91+
// </instances>
92+
8693
// <otherinfo>The X-XSS-Protection HTTP response header allows the web server to enable or disable the web browser's XSS protection mechanism. The following values would attempt to enable it:
8794
// <solution>Ensure that the web browser's XSS filter is enabled, by setting the X-XSS-Protection HTTP response header to '1'.
8895
// </solution>
@@ -98,23 +105,43 @@ public TestResults parse(File f) throws Exception {
98105

99106

100107

101-
private TestCaseResult parseZapIssue(Node flaw) throws URISyntaxException {
102-
TestCaseResult tcr = new TestCaseResult();
108+
private void parseAndAddZapIssues(Node flaw, TestResults tr) throws URISyntaxException {
109+
int cwe = -1;
103110
Node rule = getNamedChild("cweid", flaw);
104111
if ( rule != null ) {
105-
tcr.setCWE( cweLookup( rule.getTextContent() ) );
112+
cwe = cweLookup( rule.getTextContent() );
106113
}
107114

108115
String cat = getNamedChild("alert", flaw).getTextContent();
109-
tcr.setCategory( cat );
110116

111-
String conf = getNamedChild( "confidence", flaw ).getTextContent();
112-
tcr.setConfidence( Integer.parseInt( conf ) );
117+
int conf = Integer.parseInt(getNamedChild( "confidence", flaw ).getTextContent());
118+
119+
Node instances = getNamedChild("instances", flaw);
120+
if (instances == null) {
121+
addIssue(flaw, tr, cwe, cat, conf);
122+
return;
123+
}
124+
125+
List<Node> instanceList = getNamedChildren("instance", instances);
126+
for (Node instance : instanceList) {
127+
addIssue(instance, tr, cwe, cat, conf);
128+
}
129+
}
130+
131+
private void addIssue(Node alertData, TestResults tr, int cwe, String category, int confidence) throws URISyntaxException {
132+
int testNumber = extractTestNumber(getNamedChild("uri", alertData).getTextContent());
133+
if (testNumber != -1) {
134+
TestCaseResult tcr = createTestCaseResult(cwe, category, confidence, testNumber);
135+
// System.out.println( tcr.getNumber() + " " + tcr.getName() + " -> " + tcr.getCWE() + "\t" + tcr.getEvidence() );
136+
tr.put(tcr);
137+
}
138+
}
113139

114-
tcr.setEvidence( cat );
140+
private static int extractTestNumber(String uri) throws URISyntaxException {
141+
// Remove the query and fragment from the URI because some of alert URIs (e.g. generated by DOM XSS) might be malformed
142+
// (characters that should be escaped are not) which leads to exceptions when parsed by java.net.URI.
143+
URI url = new URI(removeQueryAndFragment(uri));
115144

116-
String uri = getNamedChild( "uri", flaw ).getTextContent();
117-
URI url = new URI( uri );
118145
String testfile = url.getPath();
119146
testfile = testfile.substring( testfile.lastIndexOf('/') +1 );
120147

@@ -124,15 +151,38 @@ private TestCaseResult parseZapIssue(Node flaw) throws URISyntaxException {
124151
testno = testno.substring(0, testno.length() -5 );
125152
}
126153
try {
127-
tcr.setNumber( Integer.parseInt( testno ) );
128-
return tcr;
154+
return Integer.parseInt( testno );
129155
} catch( NumberFormatException e ) {
130156
System.out.println( "> Parse error " + testfile + ":: " + testno );
131157
}
132158
}
133-
return null;
159+
return -1;
134160
}
135161

162+
private static String removeQueryAndFragment(String uri) {
163+
String strippedUri = uri;
164+
int idx = strippedUri.indexOf('?');
165+
if (idx != -1) {
166+
strippedUri = strippedUri.substring(0, idx);
167+
}
168+
idx = strippedUri.indexOf('#');
169+
if (idx != -1) {
170+
strippedUri = strippedUri.substring(0, idx);
171+
}
172+
return strippedUri;
173+
}
174+
175+
private static TestCaseResult createTestCaseResult(int cwe, String category, int confidence, int testNumber) {
176+
TestCaseResult tcr = new TestCaseResult();
177+
if (cwe != -1) {
178+
tcr.setCWE(cwe);
179+
}
180+
tcr.setCategory(category);
181+
tcr.setEvidence(category);
182+
tcr.setConfidence(confidence);
183+
tcr.setNumber(testNumber);
184+
return tcr;
185+
}
136186

137187
private int cweLookup(String orig) {
138188

0 commit comments

Comments
 (0)