Skip to content

Commit 8d841bc

Browse files
committed
Update AppScanDynamicReader2.java per pull request #157, with additional changes by me, including running spotless properly.
1 parent 4247b45 commit 8d841bc

File tree

2 files changed

+162
-84
lines changed

2 files changed

+162
-84
lines changed

src/main/java/org/owasp/benchmark/helpers/Utils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ public static String encodeForHTML(Object param) {
386386

387387
String value = "objectTypeUnknown";
388388
if (param instanceof String) {
389+
value = (String) param;
389390
} else if (param instanceof java.io.InputStream) {
390391
byte[] buff = new byte[1000];
391392
int length = 0;

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

Lines changed: 161 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,21 @@
1919

2020
import java.io.File;
2121
import java.io.FileInputStream;
22+
import java.util.ArrayList;
2223
import java.util.List;
2324
import javax.xml.parsers.DocumentBuilder;
2425
import javax.xml.parsers.DocumentBuilderFactory;
2526
import org.owasp.benchmark.score.BenchmarkScore;
2627
import org.owasp.benchmark.score.TestCaseResult;
2728
import org.owasp.benchmark.score.TestSuiteResults;
2829
import org.w3c.dom.Document;
30+
import org.w3c.dom.NamedNodeMap;
2931
import org.w3c.dom.Node;
3032
import org.xml.sax.InputSource;
3133

3234
public class AppScanDynamicReader2 extends Reader {
3335

34-
// This is the new AppScan Dynamnic reader, where they generate ".xml" files.
36+
// This is the new AppScan Dynamic reader, where they generate ".xml" files.
3537

3638
public TestSuiteResults parse(File f) throws Exception {
3739

@@ -44,6 +46,10 @@ public TestSuiteResults parse(File f) throws Exception {
4446

4547
Node root = doc.getDocumentElement();
4648
Node scanInfo = getNamedChild("scan-information", root);
49+
50+
Node scanConfiguration = getNamedChild("scan-configuration", root);
51+
String startingUrl = getNamedChild("starting-url", scanConfiguration).getTextContent();
52+
4753
TestSuiteResults tr =
4854
new TestSuiteResults("IBM AppScan Dynamic", true, TestSuiteResults.ToolType.DAST);
4955

@@ -58,130 +64,201 @@ public TestSuiteResults parse(File f) throws Exception {
5864
Node allIssues = getNamedChild("url-group", root);
5965
List<Node> vulnerabilities = getNamedChildren("item", allIssues);
6066

67+
Node allIssueVariants = getNamedChild("issue-group", root);
68+
List<Node> variants = getNamedChildren("item", allIssueVariants);
69+
6170
// Loop through all the vulnerabilities
6271
for (Node vulnerability : vulnerabilities) {
63-
64-
// First get the type of vuln, and if we don't care about that type, move on
6572
String issueType = getNamedChild("issue-type", vulnerability).getTextContent();
6673

6774
String url = getNamedChild("name", vulnerability).getTextContent();
6875
// to give DAST tools some credit, if they report a similar vuln in a different area, we
6976
// count it.
7077
// e.g., SQLi in the XPATHi tests. To do that, we have to pull out the vuln type from
7178
// the URL.
72-
String urlElements[] = url.split("/");
73-
String testArea =
74-
urlElements[urlElements.length - 2].split("-")[0]; // .split strips off the -##
75-
// System.out.println("Candidate test area is: " + testArea);
76-
77-
int vtype = cweLookup(issueType, testArea);
78-
// System.out.println("Vuln type: " + issueType + " has CWE of: " + vtype);
79-
80-
// Then get the filename containing the vuln. And if not in a test case, skip it.
81-
// Parse out test number from:
82-
// https://localhost:port/benchmark/testarea-##/BenchmarkTest02603
83-
int startOfTestCase = url.lastIndexOf("/") + 1;
84-
String testcase = url.substring(startOfTestCase, url.length());
85-
testcase =
86-
testcase.split("\\.")[
87-
0]; // if test case has extension (e.g., BenchmarkTestCase#####.html),
88-
// strip it off.
89-
// System.out.println("Candidate test case is: " + testcase);
90-
if (testcase.startsWith(BenchmarkScore.TESTCASENAME)) {
91-
int tn = -1;
92-
String testno = testcase.substring(BenchmarkScore.TESTCASENAME.length());
93-
try {
94-
tn = Integer.parseInt(testno);
95-
} catch (NumberFormatException e) {
96-
e.printStackTrace();
97-
}
98-
99-
// if (tn == -1) System.out.println("Found vuln outside of test case of type: " +
100-
// issueType);
10179

102-
// Add the vuln found in a test case to the results for this tool
103-
TestCaseResult tcr = new TestCaseResult();
104-
tcr.setNumber(tn);
105-
tcr.setCategory(issueType); // TODO: Is this right?
106-
tcr.setCWE(vtype);
107-
tcr.setEvidence(issueType);
80+
NamedNodeMap itemNode = vulnerability.getAttributes();
81+
String variantItemID = itemNode.getNamedItem("id").getNodeValue();
10882

83+
List<String> testCaseElementsFromVariants =
84+
variantLookup(issueType, variantItemID, startingUrl, variants);
85+
if (testCaseElementsFromVariants.isEmpty()) {
86+
// Handle non-variant issue types , Older xml format as in 9.x release versions and
87+
// before
88+
// First get the type of vuln, and if we don't care about that type, move on
89+
TestCaseResult tcr = TestCaseLookup(issueType, url);
10990
tr.put(tcr);
91+
} else {
92+
// Handle issues which are Variants, new xml format after 10.x release
93+
for (String testArea : testCaseElementsFromVariants) {
94+
TestCaseResult tcr = TestCaseLookup(issueType, testArea);
95+
tr.put(tcr);
96+
}
11097
}
11198
}
99+
112100
return tr;
113101
}
114102

115-
// e.g., 3 Hour(s) 7 Minute(s) 58 Second(s)
116-
/* private String parseTime(String message) {
117-
String[] parts = message.split( "\\) ");
118-
String hours = parts[0].substring( 0, parts[0].indexOf(' ') ).trim();
119-
if ( hours.length() < 2 ) hours = "0" + hours;
120-
String mins = parts[1].substring( 0, parts[1].indexOf(' ') ).trim();
121-
if ( mins.length() < 2 ) mins = "0" + mins;
122-
String secs = parts[2].substring( 0, parts[2].indexOf(' ') ).trim();
123-
if ( secs.length() < 2 ) secs = "0" + secs;
124-
return hours + ":" + mins + ":" + secs;
103+
/// Issues which are not variants
104+
private static TestCaseResult TestCaseLookup(String issueType, String url) {
105+
TestCaseResult tcr = new TestCaseResult();
106+
String urlElements[] = url.split("/");
107+
String testArea =
108+
urlElements[urlElements.length - 2].split("-")[0]; // .split strips off the -##
109+
110+
int vtype = cweLookup(issueType, testArea);
111+
112+
// Then get the filename containing the vuln. And if not in a test case, skip it.
113+
// Parse out test number from:
114+
// https://localhost:port/benchmark/testarea-##/BenchmarkTest02603
115+
int startOfTestCase = url.lastIndexOf("/") + 1;
116+
String testcase = url.substring(startOfTestCase, url.length());
117+
// if test case has extension (e.g., BenchmarkTestCase#####.html), strip it off.
118+
testcase = testcase.split("\\.")[0];
119+
// System.out.println("Candidate test case is: " + testcase);
120+
if (testcase.startsWith(BenchmarkScore.TESTCASENAME)) {
121+
int tn = -1;
122+
String testno = testcase.substring(BenchmarkScore.TESTCASENAME.length());
123+
try {
124+
tn = Integer.parseInt(testno);
125+
} catch (NumberFormatException e) {
126+
e.printStackTrace();
127+
}
128+
129+
// if (tn == -1) System.out.println("Found vuln outside of test case of type: " +
130+
// issueType);
131+
132+
// Add the vuln found in a test case to the results for this tool
133+
tcr.setNumber(tn);
134+
tcr.setCategory(issueType); // TODO: Is this right?
135+
tcr.setCWE(vtype);
136+
tcr.setEvidence(issueType);
125137
}
126-
*/
138+
return tcr;
139+
}
140+
141+
// Fetch Issues listed as variants, to cater to post 10.x release xml format
142+
private static List<String> variantLookup(
143+
String issueType, String itemID, String startingUrl, List<Node> variants) {
144+
List<String> testCaseElementsFromVariants = new ArrayList<String>();
145+
146+
// System.out.println("Variant Lookup Item ID: " + itemID);
147+
148+
for (Node variant : variants) {
149+
String variantUrlRefId = getNamedChild("url", variant).getTextContent().trim();
150+
String variantIssueType = getNamedChild("issue-type", variant).getTextContent().trim();
151+
// System.out.println("Variant Url Ref ID: " + variantUrlRefId);
152+
153+
// Add the record only if the issue type matches for the relevant variants
154+
if (issueType.equals(variantIssueType) && itemID.equals(variantUrlRefId)) {
155+
Node variantNodes = getNamedChild("variant-group", variant);
156+
List<Node> variantNodeChildren = getNamedChildren("item", variantNodes);
157+
for (Node variantNodeChild : variantNodeChildren) {
158+
String httpTraffic =
159+
getNamedChild("test-http-traffic", variantNodeChild).getTextContent();
160+
String[] variantUrl = httpTraffic.split(" ");
161+
162+
String benchMarkTestCase = variantUrl[1].trim();
163+
164+
if (benchMarkTestCase.contains("BenchmarkTest")) {
165+
String urlElements[] = benchMarkTestCase.split("/");
166+
167+
String testAreaUrl =
168+
startingUrl
169+
+ urlElements[urlElements.length - 2]
170+
+ "/"
171+
+ urlElements[urlElements.length - 1];
172+
String testArea = testAreaUrl.split("\\?")[0]; // .split strips off the -##
173+
174+
if (testArea.contains("BenchmarkTest"))
175+
testCaseElementsFromVariants.add(testArea);
176+
}
177+
}
178+
}
179+
}
180+
181+
return testCaseElementsFromVariants;
182+
}
183+
127184
private static int cweLookup(String vtype, String testArea) {
128-
int cwe = cweLookup(vtype);
129-
if ("xpathi".equals(testArea) && cwe == 89) cwe = 643; // CWE for xpath injection
130-
if ("ldapi".equals(testArea) && cwe == 89) cwe = 90; // CWE for xpath injection
185+
int cwe = cweLookup(vtype); // Do the standard CWE lookup
186+
187+
// Then map some to other CWEs based on the test area being processed.
188+
if ("xpathi".equals(testArea) && cwe == 89) cwe = 643; // CWE for XPath injection
189+
if ("ldapi".equals(testArea) && cwe == 89) cwe = 90; // CWE for LDAP injection
131190

132191
return cwe;
133192
}
134193

135194
private static int cweLookup(String vtype) {
136195
switch (vtype) {
137-
case "attBlindSqlInjectionStrings":
138-
return 89; // Score worse or better?
139-
case "attCachedSSL":
140-
return 00;
196+
case "attDirectoryFound":
197+
case "attDirOptions":
198+
case "attFileUnix":
199+
return 22;
200+
201+
case "attApplicationRemoteCodeExecutionAdns":
141202
case "attCodeInjectionInSystemCall":
142-
return 78; // Score worse or better?
203+
case "attCommandInjectionAdns":
204+
case "attCommandInjectionUnixTws":
205+
case "attFileParamPipe":
206+
return 78;
207+
143208
case "attCrossSiteScripting":
144209
return 79;
145-
case "attJSCookie":
146-
return 00;
147-
// case "attLinkInjection" : return 00;
210+
211+
case "attBlindSqlInjectionStrings":
212+
case "attSqlInjectionChecks":
213+
return 89;
214+
215+
case "attLDAPInjection":
216+
case "attLDAPInjection2":
217+
case "attBlindLDAPInjection":
218+
return 90;
219+
220+
case "SHA1CipherSuites":
221+
return 327; // Better if set to 327?
222+
223+
case "passParamGET":
224+
return 523;
225+
148226
case "attRespCookieNotSecureSSL":
149227
return 614;
150-
case "attSqlInjectionChecks":
151-
return 89; // Score worse or better?
228+
229+
case "attXPathInjection":
230+
case "attBlindXpathInjectionSingleQuote":
231+
case "attBlindXPathInjection":
232+
return 643;
233+
234+
// These don't map to anything we care about
235+
case "attContentSecurityPolicyObjectSrc":
236+
case "attContentSecurityPolicyScriptSrc":
237+
case "attCachedSSL":
238+
case "attJSCookie":
239+
// case "attLinkInjection" : return 00;
152240
case "attUndefinedState":
153-
return 00;
154241
case "bodyParamsInQuery":
155-
return 00;
156242
case "ContentSecurityPolicy":
157-
return 00;
158243
case "ContentTypeOptions":
159-
return 00;
160-
161-
// case "GD_EmailAddress" : return 00;
244+
case "GD_EmailAddress":
162245
case "GETParamOverSSL":
163-
return 00;
164-
// case "GV_SQLErr" : return 89; // Score worse or better with this or 00?
165-
// case "HSTS" : return 00;
246+
case "GV_SQLErr":
247+
// case "HSTS" : return 00;
166248

167-
// Microsoft MHTML XSS - Giving AppScan 'credit' for this introduces ~2.4% False
168-
// Positives and no real ones so I disabled it instead
249+
// Microsoft MHTML XSS - Giving AppScan XSS 'credit' for this introduces ~2.4% False
250+
// Positives and no real ones so I (shivababuh) disabled it instead
169251
case "MHTMLXSS":
170-
return 00;
171-
172-
// case "OpenSource" : return 00; // Known vuln in open source lib.
173-
// case "phishingInFrames" : return 00;
174-
case "SHA1CipherSuites":
175-
return 327; // Better if set to 327?
252+
// case "OpenSource" : return 00; // Known vuln in open source lib.
253+
// case "phishingInFrames" : return 00;
176254
case "ShellShockCheck":
177-
return 00; // don't care
178255
case "SriSupport":
179-
return 00; // don't care
180-
// case "SSL_CertWithBadCN" : return 00; // don't care
181-
// case "XSSProtectionHeader" : return 00;
256+
// case "SSL_CertWithBadCN" : return 00;
257+
// case "XSSProtectionHeader" : return 00;
258+
return 00;
182259

183260
default:
184-
System.out.println("Identified unknown type of: " + vtype);
261+
System.out.println("Identified unknown vulnerability type of: " + vtype);
185262
}
186263
return 0;
187264
}

0 commit comments

Comments
 (0)