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