This patch will add a new scan type to whisker: -M 5 This will help whisker avoid false positives in cases where a site has a 404 page that is delivered as a 200 instead of a 404 or 302. jwa@jammed.com 17 Dec 2000 --- whisker.pl Thu Aug 3 08:21:19 2000 +++ whisker-fp.pl Sat Dec 16 22:59:33 2000 @@ -103,7 +103,8 @@ -M 2 use GET method -M 3 use GET method w/ byte-range -M 4 use GET method w/ socket close - + -M 5 use GET method & attempt to ignore false positives + -A 1 alternate db format: Voideye exp.dat -A 2 alternate db format: cgichk*.r (in rebol) -A 3 alternate db format: cgichk.c/messala.c (not cgiexp.c) @@ -224,6 +225,10 @@ $D{'XXIntHeaders'}="Range: bytes=0-1\n";} elsif($args{M} eq 4){$D{'XXMeth'}="GET"; # get that closes socket $D{'XXNoContent'}=1;} + elsif ($args{M} eq 5) { + $D{'XXMeth'} = "GET"; + $fp_check = 1 + } else{wprint("! Unknown -M method"); exit;}} $D{'XXDMeth'}=$D{'XXMeth'}; # in case method gets clobbered @@ -283,6 +288,13 @@ wprint("= Host: $D{'XXTarget'} \\"); $vhosts ? wprint(" (virtual host)") : wprint('') ; +if ($fp_check) { + $str = rstr(); + # prep the cache w/ the 404-becomes-200-without-redirect page + debugprint("prepping false-positive cache for $D{XXTarget} with $str"); + sendhttp("/$str", $D{'XXTarget'}); +} + %checked=(); %dirs=(); %redirects=(); if(defined $args{U}){ $D{'XXAuthPasswordFile'}=$args{P}||'lists/userlist.txt'; @@ -738,7 +750,46 @@ sendraw("$D{'XXMeth'}$D{'XXMethExtra'}$D{'XXHTTPDelim'}$pstr". "$D{'XXHTTPDelim'}$D{'XXVer'}\n$hoststr\n"); - undef $hoststr; return;} + undef $hoststr; + + # some hosts will do pseudo-redirects for pages that + # don't exist; instead of doing a 302 they'll do a 200 + # and display the actual redirect page, which results + # in nearly every page being a "hit" + # To get around this, send a request for a bogus page + # and store a checksum of the response. If any subsequent + # pages match that response, assume that they are bogus. + + if ($fp_check) { # -M 5 + my (@response, $r, $pagedata, $site); + + @response = @DXX; + # shift off headers. fuggly. + $r = "Blah"; + while ($r ne "") { + $r = shift @response; + $r =~ s/\r|\n//g; + } + $pagedata = join("\n", @response); + $isfalse = 0; + + if (defined($fp_hash{$pagedata})) { + debugprint("Matched page of $fp_hash{$pagedata}"); + # shift off 200 message & make our own + shift @DXX; + unshift (@DXX, "HTTP/1.0 200 false positive [same as $fp_hash{$pagedata}]"); + $isfalse = 1; + return; + } + if (!$fp_loaded) { + $site = $tstr . $pstr; + $fp_hash{$pagedata} = $site; + wprint("= Loaded false positive page: $site (" . length($pagedata) . " bytes)"); + $fp_loaded = 1; # only do this once + } + } + + return; } sub debugprint { my ($line)=@_; @@ -757,6 +808,8 @@ {$BG='#cccccc'; sub wprint { + return if (($isfalse) && (!$D{XXVerbose})); # don't show false positives + my $line=shift; if($GLOBAL_HTMLOUTPUT>0){ return if($line eq ''); @@ -868,7 +921,16 @@ # this is based on an observed anomaly if($D{'XXRet'}==$D{'XXC200'} && $D{'XXCLen'}=='' && $D{'XXDirQuite'}){ $D{'XXIsIndex'}=1; - wprint("- Directory index: $D{'XXPageW'}") if $D{'XXInfo'}>0;} + if ($D{'XXInfo'} > 0) { + if ($isfalse) { + if ($D{'XXVerbose'}) { + wprint("- Directory index: $D{'XXPageW'} $D{'XXRetStr'}"); + } + } else { + wprint("- Directory index: $D{'XXPageW'}"); + } + } + } # only support for the first cookie given right now @rfp=grep(/^Set-Cookie/,@in);