22
22
import java .io .FileNotFoundException ;
23
23
import java .io .FileWriter ;
24
24
import java .io .IOException ;
25
+ import java .nio .file .Files ;
26
+ import java .nio .file .Paths ;
25
27
import java .util .ArrayList ;
26
28
import java .util .Date ;
29
+ import java .util .HashMap ;
27
30
import java .util .List ;
31
+ import java .util .Map ;
28
32
import java .util .stream .Collectors ;
29
33
import javax .xml .bind .JAXBException ;
30
34
import javax .xml .parsers .ParserConfigurationException ;
@@ -68,10 +72,12 @@ public class BenchmarkCrawlerVerification extends BenchmarkCrawler {
68
72
private static boolean isTimingEnabled = false ;
69
73
// private boolean verifyFixed = false; // DEBUG
70
74
private String configurationDirectory = Utils .DATA_DIR ;
71
- private String defaultOutputDirectory = Utils .DATA_DIR ;
72
- private String defaultBeforeFixOutputDirectory =
73
- new File (new File (Utils .DATA_DIR ).getParent (), "before_data" )
74
- .getAbsolutePath (); // DEBUG: Utils.DATA_DIR;
75
+ private String defaultOutputDirectory = configurationDirectory ;
76
+ // private String defaultFixedOutputDirectory = Paths.get(Utils.DATA_DIR,
77
+ // "fixstatus").toString();
78
+ // private String defaultUnfixedSrcDirectory =
79
+ // new File(new File(Utils.DATA_DIR).getParent(), "before_data")
80
+ // .getAbsolutePath(); // DEBUG: Utils.DATA_DIR;
75
81
private static final String FILENAME_TIMES_ALL = "crawlerTimes.txt" ;
76
82
private static final String FILENAME_TIMES = "crawlerSlowTimes.txt" ;
77
83
private static final String FILENAME_NON_DISCRIMINATORY_LOG = "nonDiscriminatoryTestCases.txt" ;
@@ -88,21 +94,27 @@ public class BenchmarkCrawlerVerification extends BenchmarkCrawler {
88
94
SimpleFileLogger eLogger ;
89
95
SimpleFileLogger uLogger ;
90
96
91
- @ Parameter (property = "json " , defaultValue = "false" )
97
+ @ Parameter (property = "generateJSONResults " , defaultValue = "false" )
92
98
private String generateJSONResults ;
93
99
94
100
@ Parameter (property = "verifyFixed" , defaultValue = "false" )
95
101
private String verifyFixed ;
96
102
97
- @ Parameter (property = "beforeFixOutputDirectory" )
98
- private String beforeFixOutputDirectory ;
103
+ @ Parameter (property = "unfixedSrcDirectory" )
104
+ private String unfixedSourceDirectory ;
105
+
106
+ @ Parameter (property = "fixedSrcDirectory" )
107
+ private String fixedSourceDirectory ;
99
108
100
109
@ Parameter (property = "outputDirectory" )
101
110
private String outputDirectory ;
102
111
103
112
@ Parameter (property = "testCaseName" )
104
113
private String selectedTestCaseName ;
105
114
115
+ private Map <String , TestCaseVerificationResults > testCaseNameToTestCaseVerificationResultsMap =
116
+ new HashMap <>();
117
+
106
118
BenchmarkCrawlerVerification () {
107
119
// A default constructor required to support Maven plugin API.
108
120
// The theCrawlerFile has to be instantiated before a crawl can be done.
@@ -352,7 +364,7 @@ protected void crawl(TestSuite testSuite) throws Exception {
352
364
353
365
// Then generate JSON file with ALL verification results if generateJSONResults
354
366
// is enabled. This has to go at end because previous methods have some side
355
- // affects that fill in test case verification values.
367
+ // effects that fill in test case verification values.
356
368
RegressionTesting .genAllTCResultsToJsonFile (
357
369
resultsCollection ,
358
370
getOutputDirectory (),
@@ -391,7 +403,7 @@ protected void crawl(TestSuite testSuite) throws Exception {
391
403
* @param testSuite
392
404
* @throws Exception
393
405
*/
394
- protected void crawlToVerifyFix (TestSuite testSuite , String beforeFixOutputDirectory )
406
+ protected void crawlToVerifyFix (TestSuite testSuite , String unfixedOutputDirectory )
395
407
throws Exception {
396
408
397
409
// Get config directory for RUN 1 from CLI option
@@ -481,15 +493,15 @@ private void log(ResponseInfo responseInfo) throws IOException {
481
493
/**
482
494
* For the verification crawler, processing the result means verifying whether the test case is
483
495
* actually vulnerable or not, relative to whether it is supposed to be vulnerable. This method
484
- * has a side-affect of setting request.setPassed() for the current test case. Passing means it
496
+ * has a side-effect of setting request.setPassed() for the current test case. Passing means it
485
497
* was exploitable for a True Positive and appears to not be exploitable for a False Positive.
486
498
*
487
499
* @param result - The results required to verify this test case.
488
500
* @throws FileNotFoundException
489
501
* @throws LoggerConfigurationException
490
502
*/
491
503
protected void handleResponse (TestCaseVerificationResults results )
492
- throws FileNotFoundException , LoggerConfigurationException {
504
+ throws FileNotFoundException , IOException , LoggerConfigurationException {
493
505
494
506
// Check to see if this specific test case has a specified expected response value.
495
507
// If so, run it through verification using it's specific attackSuccessIndicator.
@@ -498,18 +510,46 @@ protected void handleResponse(TestCaseVerificationResults results)
498
510
RegressionTesting .verifyTestCase (results );
499
511
500
512
if (Boolean .parseBoolean (verifyFixed )) {
501
- TestCaseVerificationResultsCollection beforeFixResultsCollection =
502
- loadTestCaseVerificationResults (beforeFixOutputDirectory );
503
- TestCaseVerificationResults beforeFixResults =
504
- beforeFixResultsCollection .getResultsObjects ().get (0 );
505
- if (beforeFixResults .getTestCase ().getName ().equals (results .getTestCase ().getName ())) {
506
- verifyFix (beforeFixResults , results );
513
+ String unfixedOutputDirectory = configurationDirectory ;
514
+
515
+ TestCaseVerificationResults fixedResults = results ;
516
+ TestCaseVerificationResultsCollection unfixedResultsCollection =
517
+ loadTestCaseVerificationResults (unfixedOutputDirectory );
518
+ TestCaseVerificationResults unfixedResults =
519
+ testCaseNameToTestCaseVerificationResultsMap .get (
520
+ fixedResults .getTestCase ().getName ());
521
+ if (unfixedResults
522
+ .getTestCase ()
523
+ .getName ()
524
+ .equals (fixedResults .getTestCase ().getName ())) {
525
+ // FIXME: Generalize this so it can support languages other than Java and multiple
526
+ // source files per testcase.
527
+ String unfixedSourceFile =
528
+ Paths .get (unfixedSourceDirectory , unfixedResults .getTestCase ().getName ())
529
+ .toString ()
530
+ + ".java" ;
531
+ String fixedSourceFile =
532
+ Paths .get (fixedSourceDirectory , fixedResults .getTestCase ().getName ())
533
+ .toString ()
534
+ + ".java" ;
535
+ String unfixedSourceFileContents =
536
+ new String (Files .readAllBytes (Paths .get (unfixedSourceFile )));
537
+ String fixedSourceFileContents =
538
+ new String (Files .readAllBytes (Paths .get (fixedSourceFile )));
539
+ if (!unfixedSourceFileContents .equals (fixedSourceFileContents )) {
540
+ verifyFix (unfixedResults , fixedResults );
541
+ } else {
542
+ System .out .println (
543
+ "WARNING: Testcase "
544
+ + fixedResults .getTestCase ().getName ()
545
+ + " source file unmodified" );
546
+ }
507
547
} else {
508
548
System .out .println (
509
549
"WARNING: After fix testcase is "
510
- + results .getTestCase ().getName ()
550
+ + fixedResults .getTestCase ().getName ()
511
551
+ " but before fix testcase is "
512
- + beforeFixResults .getTestCase ().getName ());
552
+ + unfixedResults .getTestCase ().getName ());
513
553
}
514
554
}
515
555
}
@@ -522,6 +562,11 @@ private TestCaseVerificationResultsCollection loadTestCaseVerificationResults(
522
562
results =
523
563
Utils .jsonToTestCaseVerificationResultsList (
524
564
new File (directory , FILENAME_TC_VERIF_RESULTS_JSON ));
565
+ for (TestCaseVerificationResults testCaseResults : results .getResultsObjects ()) {
566
+ testCaseNameToTestCaseVerificationResultsMap .put (
567
+ testCaseResults .getTestCase ().getName (), testCaseResults );
568
+ }
569
+
525
570
} catch (JAXBException
526
571
| FileNotFoundException
527
572
| SAXException
@@ -554,6 +599,10 @@ private boolean verifyFix(
554
599
TestCaseVerificationResults beforeFixResults ,
555
600
TestCaseVerificationResults afterFixResults ) {
556
601
602
+ boolean wasNotVerfiable =
603
+ afterFixResults .getTestCase ().isVulnerability ()
604
+ && afterFixResults .getTestCase ().isUnverifiable ()
605
+ && afterFixResults .isPassed ();
557
606
boolean wasExploited =
558
607
afterFixResults .getTestCase ().isVulnerability ()
559
608
&& !afterFixResults .getTestCase ().isUnverifiable ()
@@ -563,6 +612,9 @@ private boolean verifyFix(
563
612
.getResponseToSafeValue ()
564
613
.getResponseString ()
565
614
.equals (afterFixResults .getResponseToSafeValue ().getResponseString ());
615
+ if (wasNotVerfiable ) {
616
+ System .out .println ("NOT FIXED: Vulnerability could not be verified" );
617
+ }
566
618
if (wasExploited ) {
567
619
System .out .println ("NOT FIXED: Vulnerability was exploited" );
568
620
}
@@ -573,6 +625,7 @@ private boolean verifyFix(
573
625
File verifyFixResultFile = new File (getOutputDirectory (), FILENAME_VERIFY_FIX_RESULT );
574
626
try (BufferedWriter writer = new BufferedWriter (new FileWriter (verifyFixResultFile ))) {
575
627
VerifyFixOutput verifyFixOutput = new VerifyFixOutput ();
628
+ verifyFixOutput .setWasNotVerfiable (wasNotVerfiable );
576
629
verifyFixOutput .setWasExploited (wasExploited );
577
630
verifyFixOutput .setWasBroken (wasBroken );
578
631
String output = Utils .objectToJson (verifyFixOutput );
@@ -587,7 +640,7 @@ private boolean verifyFix(
587
640
e .printStackTrace ();
588
641
}
589
642
590
- return !wasExploited && !wasBroken ;
643
+ return !wasNotVerfiable && ! wasExploited && !wasBroken ;
591
644
}
592
645
593
646
private boolean verifyFixes (
@@ -638,12 +691,18 @@ protected void processCommandLineArgs(String[] args) {
638
691
Options options = new Options ();
639
692
options .addOption (
640
693
Option .builder ("b" )
641
- .longOpt ("beforeFixOutputDirectory" )
642
- .desc ("output directory of a previous crawl before fixes" )
694
+ .longOpt ("unfixedSrcDirectory" )
695
+ .desc ("source directory before fixes" )
696
+ .hasArg ()
697
+ .build ());
698
+ options .addOption (
699
+ Option .builder ("a" )
700
+ .longOpt ("fixedSrcDirectory" )
701
+ .desc ("source directory after fixes" )
643
702
.hasArg ()
644
703
.build ());
645
704
options .addOption (
646
- Option .builder ("d " )
705
+ Option .builder ("o " )
647
706
.longOpt ("outputDirectory" )
648
707
.desc ("output directory" )
649
708
.hasArg ()
@@ -658,7 +717,7 @@ protected void processCommandLineArgs(String[] args) {
658
717
options .addOption (Option .builder ("h" ).longOpt ("help" ).desc ("Usage" ).build ());
659
718
options .addOption (
660
719
Option .builder ("j" )
661
- .longOpt ("json " )
720
+ .longOpt ("generateJSONResults " )
662
721
.desc ("generate json version of verification results" )
663
722
.build ());
664
723
// options.addOption("m", "verifyFixed", false, "verify fixed test suite");
@@ -682,16 +741,19 @@ protected void processCommandLineArgs(String[] args) {
682
741
// Parse the command line arguments
683
742
CommandLine line = parser .parse (options , args );
684
743
685
- if (line .hasOption ("b" )) {
686
- beforeFixOutputDirectory = line .getOptionValue ("b" );
687
- } else {
688
- beforeFixOutputDirectory = defaultBeforeFixOutputDirectory ;
689
- }
690
- if (line .hasOption ("d" )) {
691
- outputDirectory = line .getOptionValue ("d" );
744
+ if (line .hasOption ("o" )) {
745
+ outputDirectory = line .getOptionValue ("o" );
692
746
} else {
693
747
outputDirectory = defaultOutputDirectory ;
694
748
}
749
+ // Required if in verifyFix mode
750
+ if (line .hasOption ("b" )) {
751
+ unfixedSourceDirectory = line .getOptionValue ("b" );
752
+ }
753
+ // Required if in verifyFix mode
754
+ if (line .hasOption ("a" )) {
755
+ fixedSourceDirectory = line .getOptionValue ("a" );
756
+ }
695
757
if (line .hasOption ("f" )) {
696
758
this .crawlerFile = line .getOptionValue ("f" );
697
759
File targetFile = new File (this .crawlerFile );
@@ -720,6 +782,11 @@ protected void processCommandLineArgs(String[] args) {
720
782
if (line .hasOption ("t" )) {
721
783
maxTimeInSeconds = (Integer ) line .getParsedOptionValue ("t" );
722
784
}
785
+
786
+ // The default is different if we are in verifyFix mode
787
+ if (Boolean .parseBoolean (this .verifyFixed )) {
788
+ outputDirectory = Paths .get (Utils .DATA_DIR , "fixstatus" ).toString ();
789
+ }
723
790
} catch (ParseException e ) {
724
791
formatter .printHelp ("BenchmarkCrawlerVerification" , options );
725
792
throw new RuntimeException ("Error parsing arguments: " , e );
@@ -740,12 +807,16 @@ public void execute() throws MojoExecutionException, MojoFailureException {
740
807
mainArgs .add ("-f" );
741
808
mainArgs .add (this .pluginFilenameParam );
742
809
if (this .outputDirectory != null ) {
743
- mainArgs .add ("-d " );
810
+ mainArgs .add ("-o " );
744
811
mainArgs .add (this .outputDirectory );
745
812
}
746
- if (this .beforeFixOutputDirectory != null ) {
813
+ if (this .unfixedSourceDirectory != null ) {
747
814
mainArgs .add ("-b" );
748
- mainArgs .add (this .beforeFixOutputDirectory );
815
+ mainArgs .add (this .unfixedSourceDirectory );
816
+ }
817
+ if (this .fixedSourceDirectory != null ) {
818
+ mainArgs .add ("-a" );
819
+ mainArgs .add (this .fixedSourceDirectory );
749
820
}
750
821
if (this .pluginTestCaseNameParam != null ) {
751
822
mainArgs .add ("-n" );
0 commit comments