@@ -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
@@ -382,8 +386,11 @@ public void scan(HttpMessage msg, String param, String value) {
382
386
383
387
// Check 3: Detect if this page is a directory browsing component
384
388
if (inScope (Tech .Linux ) || inScope (Tech .MacOS )) {
385
- for (int h = 0 ; h < nixDirCount ; h ++) {
386
-
389
+ int h = 0 ;
390
+ if (!isGoodCandidate (getBaseMsg (), Tech .Linux )) {
391
+ h = nixDirCount ;
392
+ }
393
+ for (; h < nixDirCount ; h ++) {
387
394
// Check if a there was a finding or the scan has been stopped
388
395
// if yes dispose resources and exit
389
396
if (sendAndCheckPayload (param , NIX_LOCAL_DIR_TARGETS [h ], DIR_PATTERN , 3 )
@@ -395,7 +402,11 @@ public void scan(HttpMessage msg, String param, String value) {
395
402
}
396
403
}
397
404
if (inScope (Tech .Windows )) {
398
- for (int h = 0 ; h < winDirCount ; h ++) {
405
+ int h = 0 ;
406
+ if (!isGoodCandidate (getBaseMsg (), Tech .Windows )) {
407
+ h = winDirCount ;
408
+ }
409
+ for (; h < winDirCount ; h ++) {
399
410
if (sendAndCheckPayload (param , WIN_LOCAL_DIR_TARGETS [h ], DIR_PATTERN , 3 )
400
411
|| isStop ()) {
401
412
// Dispose all resources
@@ -569,6 +580,19 @@ public void scan(HttpMessage msg, String param, String value) {
569
580
}
570
581
}
571
582
583
+ private static boolean isGoodCandidate (HttpMessage msg , Tech targetTech ) {
584
+ // It is a good candidate if it doesn't have evidence to start with
585
+ if (targetTech == Tech .Windows ) {
586
+ return DirNamesContentsMatcher .matchWinDirectories (msg .getResponseBody ().toString ())
587
+ == null ;
588
+ }
589
+ if (targetTech == Tech .Linux ) {
590
+ return DirNamesContentsMatcher .matchNixDirectories (msg .getResponseBody ().toString ())
591
+ == null ;
592
+ }
593
+ return false ;
594
+ }
595
+
572
596
private boolean sendAndCheckPayload (
573
597
String param , String newValue , ContentsMatcher contentsMatcher , int check )
574
598
throws IOException {
@@ -658,12 +682,23 @@ private AlertBuilder createUnmatchedAlert(String param, String attack) {
658
682
659
683
private AlertBuilder createMatchedAlert (
660
684
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 );
685
+ AlertBuilder builder =
686
+ newAlert ()
687
+ .setConfidence (Alert .CONFIDENCE_MEDIUM )
688
+ .setParam (param )
689
+ .setAttack (attack )
690
+ .setEvidence (evidence )
691
+ .setAlertRef (getId () + "-" + check );
692
+ if (DIR_EVIDENCE_LIST .contains (evidence )) {
693
+ builder .setOtherInfo (
694
+ Constant .messages .getString (
695
+ MESSAGE_PREFIX + "info" ,
696
+ evidence ,
697
+ evidence .equals (WIN_DIR_EVIDENCE )
698
+ ? DirNamesContentsMatcher .WIN_MATCHES
699
+ : DirNamesContentsMatcher .NIX_MATCHES ));
700
+ }
701
+ return builder ;
667
702
}
668
703
669
704
@ Override
@@ -705,6 +740,26 @@ public String match(String contents) {
705
740
706
741
private static class DirNamesContentsMatcher implements ContentsMatcher {
707
742
743
+ private static final String NIX_MATCHES =
744
+ String .join (", " , List .of ("proc" , NIX_DIR_EVIDENCE , "boot" , "tmp" , "home" ));
745
+ private static final String WIN_MATCHES =
746
+ String .join (", " , List .of (WIN_DIR_EVIDENCE , "Program Files" ));
747
+ private static final Pattern PROC_PATT =
748
+ Pattern .compile (
749
+ "(?:^|\\ W)proc(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
750
+ private static final Pattern ETC_PATT =
751
+ Pattern .compile (
752
+ "(?:^|\\ W)etc(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
753
+ private static final Pattern BOOT_PATT =
754
+ Pattern .compile (
755
+ "(?:^|\\ W)boot(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
756
+ private static final Pattern TMP_PATT =
757
+ Pattern .compile (
758
+ "(?:^|\\ W)tmp(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
759
+ private static final Pattern HOME_PATT =
760
+ Pattern .compile (
761
+ "(?:^|\\ W)home(?:\\ W|$)" , Pattern .CASE_INSENSITIVE | Pattern .MULTILINE );
762
+
708
763
@ Override
709
764
public String match (String contents ) {
710
765
String result = matchNixDirectories (contents );
@@ -715,36 +770,23 @@ public String match(String contents) {
715
770
}
716
771
717
772
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" ;
773
+ if (PROC_PATT .matcher (contents ).find ()
774
+ && ETC_PATT .matcher (contents ).find ()
775
+ && BOOT_PATT .matcher (contents ).find ()
776
+ && TMP_PATT .matcher (contents ).find ()
777
+ && HOME_PATT .matcher (contents ).find ()) {
778
+ return NIX_DIR_EVIDENCE ;
739
779
}
740
780
741
781
return null ;
742
782
}
743
783
744
784
private static String matchWinDirectories (String contents ) {
745
- if (contents .contains ("Windows" )
746
- && Pattern .compile ("Program\\ sFiles" ).matcher (contents ).find ()) {
747
- return "Windows" ;
785
+ if (contents .contains (WIN_DIR_EVIDENCE )
786
+ && Pattern .compile ("Program\\ sFiles" , Pattern .CASE_INSENSITIVE )
787
+ .matcher (contents )
788
+ .find ()) {
789
+ return WIN_DIR_EVIDENCE ;
748
790
}
749
791
750
792
return null ;
0 commit comments