@@ -81,6 +81,7 @@ public class PathTraversalScanRule extends AbstractAppParamPlugin
81
81
*/
82
82
private static final ContentsMatcher WIN_PATTERN =
83
83
new PatternContentsMatcher (Pattern .compile ("\\ [drivers\\ ]" ));
84
+ private static final String WIN_DIR_EVIDENCE = "Windows" ;
84
85
private static final String [] WIN_LOCAL_FILE_TARGETS = {
85
86
// Absolute Windows file retrieval (we suppose C:\\)
86
87
"c:/Windows/system.ini" ,
@@ -130,6 +131,7 @@ public class PathTraversalScanRule extends AbstractAppParamPlugin
130
131
// Dot used to match 'x' or '!' (used in AIX)
131
132
private static final ContentsMatcher NIX_PATTERN =
132
133
new PatternContentsMatcher (Pattern .compile ("root:.:0:0" ));
134
+ private static final String NIX_DIR_EVIDENCE = "etc" ;
133
135
private static final String [] NIX_LOCAL_FILE_TARGETS = {
134
136
// Absolute file retrieval
135
137
"/etc/passwd" ,
@@ -159,7 +161,8 @@ public class PathTraversalScanRule extends AbstractAppParamPlugin
159
161
* Windows/Unix/Linux/etc. local directory targets and detection pattern
160
162
*/
161
163
private static final ContentsMatcher DIR_PATTERN = new DirNamesContentsMatcher ();
162
- private static final String [] WIN_LOCAL_DIR_TARGETS = {
164
+ /* Increased visibility purely for testing purposes */
165
+ public static final String [] WIN_LOCAL_DIR_TARGETS = {
163
166
"c:/" ,
164
167
"c:\\ " ,
165
168
"..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ ..\\ " ,
@@ -176,7 +179,7 @@ public class PathTraversalScanRule extends AbstractAppParamPlugin
176
179
"file:\\ \\ \\ d:\\ " ,
177
180
"file:\\ \\ \\ d:/"
178
181
};
179
- private static final String [] NIX_LOCAL_DIR_TARGETS = {
182
+ public static final String [] NIX_LOCAL_DIR_TARGETS = {
180
183
"/" ,
181
184
"../../../../../../../../../../../../../../../../" ,
182
185
"/../../../../../../../../../../../../../../../../" ,
@@ -191,6 +194,8 @@ public class PathTraversalScanRule extends AbstractAppParamPlugin
191
194
*/
192
195
private static final String [] LOCAL_FILE_RELATIVE_PREFIXES = {"" , "/" , "\\ " };
193
196
197
+ private static final List <String > DIR_EVIDENCE_LIST =
198
+ List .of (NIX_DIR_EVIDENCE , WIN_DIR_EVIDENCE );
194
199
/*
195
200
* details of the vulnerability which we are attempting to find
196
201
*/
@@ -341,7 +346,6 @@ public void scan(HttpMessage msg, String param, String value) {
341
346
342
347
// Check 2: Start detection for *NIX patterns
343
348
if (inScope (Tech .Linux ) || inScope (Tech .MacOS )) {
344
-
345
349
for (int h = 0 ; h < nixCount ; h ++) {
346
350
347
351
// Check if a there was a finding or the scan has been stopped
@@ -381,9 +385,13 @@ public void scan(HttpMessage msg, String param, String value) {
381
385
}
382
386
383
387
// Check 3: Detect if this page is a directory browsing component
384
- if (inScope (Tech .Linux ) || inScope (Tech .MacOS )) {
388
+ // System.out.println(
389
+ // "Not Linux evidence? " + !isEvidenceInResponse(getBaseMsg(),
390
+ // Tech.Linux));
391
+ // System.out.println("Base: " + getBaseMsg().getResponseBody().toString());
392
+ if (inScope (Tech .Linux )
393
+ || inScope (Tech .MacOS ) && !isEvidenceInResponse (getBaseMsg (), Tech .Linux )) {
385
394
for (int h = 0 ; h < nixDirCount ; h ++) {
386
-
387
395
// Check if a there was a finding or the scan has been stopped
388
396
// if yes dispose resources and exit
389
397
if (sendAndCheckPayload (param , NIX_LOCAL_DIR_TARGETS [h ], DIR_PATTERN , 3 )
@@ -394,7 +402,11 @@ public void scan(HttpMessage msg, String param, String value) {
394
402
}
395
403
}
396
404
}
397
- if (inScope (Tech .Windows )) {
405
+ // System.out.println(
406
+ // "Not Windows evidence? " + !isEvidenceInResponse(getBaseMsg(),
407
+ // Tech.Windows));
408
+ // System.out.println("Base: " + getBaseMsg().getResponseBody().toString());
409
+ if (inScope (Tech .Windows ) && !isEvidenceInResponse (getBaseMsg (), Tech .Windows )) {
398
410
for (int h = 0 ; h < winDirCount ; h ++) {
399
411
if (sendAndCheckPayload (param , WIN_LOCAL_DIR_TARGETS [h ], DIR_PATTERN , 3 )
400
412
|| isStop ()) {
@@ -569,6 +581,19 @@ public void scan(HttpMessage msg, String param, String value) {
569
581
}
570
582
}
571
583
584
+ private static boolean isEvidenceInResponse (HttpMessage msg , Tech targetTech ) {
585
+ // It is a good candidate if it doesn't have evidence to start with
586
+ if (targetTech == Tech .Windows ) {
587
+ return DirNamesContentsMatcher .matchWinDirectories (msg .getResponseBody ().toString ())
588
+ != null ;
589
+ }
590
+ if (targetTech == Tech .Linux ) {
591
+ return DirNamesContentsMatcher .matchNixDirectories (msg .getResponseBody ().toString ())
592
+ != null ;
593
+ }
594
+ return false ;
595
+ }
596
+
572
597
private boolean sendAndCheckPayload (
573
598
String param , String newValue , ContentsMatcher contentsMatcher , int check )
574
599
throws IOException {
@@ -607,6 +632,7 @@ private boolean sendAndCheckPayload(
607
632
return false ; // Something went wrong, no point continuing
608
633
}
609
634
635
+ // System.out.println("Tested body: " + msg.getResponseBody().toString());
610
636
// does it match the pattern specified for that file name?
611
637
String match = contentsMatcher .match (getContentsToMatch (msg ));
612
638
@@ -658,12 +684,23 @@ private AlertBuilder createUnmatchedAlert(String param, String attack) {
658
684
659
685
private AlertBuilder createMatchedAlert (
660
686
String param , String attack , String evidence , int check ) {
661
- return newAlert ()
662
- .setConfidence (Alert .CONFIDENCE_MEDIUM )
663
- .setParam (param )
664
- .setAttack (attack )
665
- .setEvidence (evidence )
666
- .setAlertRef (getId () + "-" + check );
687
+ AlertBuilder builder =
688
+ newAlert ()
689
+ .setConfidence (Alert .CONFIDENCE_MEDIUM )
690
+ .setParam (param )
691
+ .setAttack (attack )
692
+ .setEvidence (evidence )
693
+ .setAlertRef (getId () + "-" + check );
694
+ if (DIR_EVIDENCE_LIST .contains (evidence )) {
695
+ builder .setOtherInfo (
696
+ Constant .messages .getString (
697
+ MESSAGE_PREFIX + "info" ,
698
+ evidence ,
699
+ evidence .equals (WIN_DIR_EVIDENCE )
700
+ ? DirNamesContentsMatcher .WIN_MATCHES
701
+ : DirNamesContentsMatcher .NIX_MATCHES ));
702
+ }
703
+ return builder ;
667
704
}
668
705
669
706
@ Override
@@ -705,6 +742,26 @@ public String match(String contents) {
705
742
706
743
private static class DirNamesContentsMatcher implements ContentsMatcher {
707
744
745
+ private static final String NIX_MATCHES =
746
+ String .join (", " , List .of ("proc" , NIX_DIR_EVIDENCE , "boot" , "tmp" , "home" ));
747
+ private static final String WIN_MATCHES =
748
+ String .join (", " , List .of (WIN_DIR_EVIDENCE , "Program Files" ));
749
+ private static final Pattern PROC_PATT =
750
+ Pattern .compile (
751
+ "(?:^|\\ W)proc(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
752
+ private static final Pattern ETC_PATT =
753
+ Pattern .compile (
754
+ "(?:^|\\ W)etc(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
755
+ private static final Pattern BOOT_PATT =
756
+ Pattern .compile (
757
+ "(?:^|\\ W)boot(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
758
+ private static final Pattern TMP_PATT =
759
+ Pattern .compile (
760
+ "(?:^|\\ W)tmp(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
761
+ private static final Pattern HOME_PATT =
762
+ Pattern .compile (
763
+ "(?:^|\\ W)home(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
764
+
708
765
@ Override
709
766
public String match (String contents ) {
710
767
String result = matchNixDirectories (contents );
@@ -715,36 +772,23 @@ public String match(String contents) {
715
772
}
716
773
717
774
private static String matchNixDirectories (String contents ) {
718
- Pattern procPattern =
719
- Pattern .compile ("(?:^|\\ W)proc(?:\\ W|$)" , Pattern .CASE_INSENSITIVE );
720
- Pattern etcPattern = Pattern .compile ("(?:^|\\ W)etc(?:\\ W|$)" , Pattern .CASE_INSENSITIVE );
721
- Pattern bootPattern =
722
- Pattern .compile ("(?:^|\\ W)boot(?:\\ W|$)" , Pattern .CASE_INSENSITIVE );
723
- Pattern tmpPattern = Pattern .compile ("(?:^|\\ W)tmp(?:\\ W|$)" , Pattern .CASE_INSENSITIVE );
724
- Pattern homePattern =
725
- Pattern .compile ("(?:^|\\ W)home(?:\\ W|$)" , Pattern .CASE_INSENSITIVE );
726
-
727
- Matcher procMatcher = procPattern .matcher (contents );
728
- Matcher etcMatcher = etcPattern .matcher (contents );
729
- Matcher bootMatcher = bootPattern .matcher (contents );
730
- Matcher tmpMatcher = tmpPattern .matcher (contents );
731
- Matcher homeMatcher = homePattern .matcher (contents );
732
-
733
- if (procMatcher .find ()
734
- && etcMatcher .find ()
735
- && bootMatcher .find ()
736
- && tmpMatcher .find ()
737
- && homeMatcher .find ()) {
738
- return "etc" ;
775
+ if (PROC_PATT .matcher (contents ).find ()
776
+ && ETC_PATT .matcher (contents ).find ()
777
+ && BOOT_PATT .matcher (contents ).find ()
778
+ && TMP_PATT .matcher (contents ).find ()
779
+ && HOME_PATT .matcher (contents ).find ()) {
780
+ return NIX_DIR_EVIDENCE ;
739
781
}
740
782
741
783
return null ;
742
784
}
743
785
744
786
private static String matchWinDirectories (String contents ) {
745
- if (contents .contains ("Windows" )
746
- && Pattern .compile ("Program\\ sFiles" ).matcher (contents ).find ()) {
747
- return "Windows" ;
787
+ if (contents .contains (WIN_DIR_EVIDENCE )
788
+ && Pattern .compile ("Program\\ sFiles" , Pattern .CASE_INSENSITIVE )
789
+ .matcher (contents )
790
+ .find ()) {
791
+ return WIN_DIR_EVIDENCE ;
748
792
}
749
793
750
794
return null ;
0 commit comments