#!/usr/bin/perl
#
#
#---[ file: fscan.pl / localtime: Wed Nov  8 15:19:09 2000  -0.956806 seconds ]--  
#---
#---[ Anti-IDS CGI scanning implementation ]--
#
#---[ Usage ]--
#
# fscan.pl [..options..] [method] -h/-f <host/hostfile>
#
# -h : specifies host
# -F : specifies hostfile
# -l : enables logging (logs to either <host>.log or <hostfile>.log)
#
# -options-
#
# -e : URL encoding
# -d : dot insertion
# -r : random long url insertion
# -f : fake parameter insertion
#
# -methods-
#
# -p : premature http request closure
# -s : sequenced fragmentation attack
#

%RxNames = ("0", "index.html", "1", "index.htm", "2", "main.htm", "3", "main.html", "4", "home.html", "5", "home.htm", "6", "default.htm", "7",
            "default.html", "8", "welcome.htm", "9", "welcome.html");

use IO::Socket;
use Getopt::Std;
require "scan.file";

getopts("e p s d f F h r l",\%opt); # our options:)

if ($#ARGV < 0) {
    &usage;
    exit(0);
}


# useful variables
######################
my($hostnum) = 0;
my($logging) = 0;
my($date) = `date`;
my($RxTime1) = time();
my($foundCount) = 0;
my($option) = "0";
my($RxDetails) = "0";
my($scanScriptIDS) = "0";
######################


if(defined($opt{'l'})){$logging=1;} # logging option

if (defined($opt{'h'})) { # single host scan
   $host = $ARGV[0];
   &fscan_head;
   &rxbuffgen;
   if ($logging == "1"){open("LOG", ">>logs/$host.log"); print LOG "\nFSCAN :: Report :: Generated on $date\n\n";}
   &host_scan;
   if ($logging == "1"){ print LOG "\n-- ::(info):: -- ";
      if ($foundCount == "0") {print LOG "no vulnerabilities were found.\n\n\n";} 
      else {print LOG "found a total of $foundCount possible vulnerabilities.\n\n\n";}
   }
   close(LOG);
   &fscan_trail;
   exit(0);
}

if (defined($opt{'F'})) { # multi host scan
   $hostfile = $ARGV[0];
   &fscan_head;
   &rxbuffgen;
   if ($logging == "1") {open("LOG", ">>logs/$hostfile.log"); print LOG "\nFSCAN :: Report :: Generated on $date\n\n";}
   &hf_scan;
   &fscan_hf_trail;
   exit(0);
}


if(!$opt) {
   &usage;
   exit(0);
}



#############################################
# These are the uri formatting strings that
# handle the anti-ids techniques relating 
# only to the scanscript formatting.  

sub encodeUri { #hex encoding of the uri
    $scanScriptIDS =~ s/([-a-zA-Z0-9.])/sprintf("%%%x",ord($1))/ge;
}

sub insertDot { #dot insertion
    $scanScriptIDS =~ s/\//\/.\//g;
}

sub randChar { #random chargen for long url
    my $rchr, $Xgen;
    $RxGen = (rand() * 10) % 10;
    for ($RxXGen=0;$RxXGen<10+$RxGen;$RxXGen++){ $rchr.=chr(((rand() * 26) % 26) + 97); }
    $scanScriptIDS = "/$rchr/..$scanScript"; 
}    
    
sub fakeParam { #random chargen for fake params
    $RxGen2 = (rand() * 5) % 5;
    for ($RxXGen2=0;$RxXGen2<10+$RxGen2;$RxXGen2++){ $RxRchr.=chr(((rand() * 26) % 26) + 97); } 
    $RxValue=(rand() * 10) % 10;$RxIndex=$RxNames{$RxValue};
    $scanScriptIDS = "/$RxIndex%3f$RxRchr=/..$scanScriptIDS";
}

   
##############################################
# Single host scan

sub host_scan {
    print "\n[fscan/(output)] - scanning results on ($host)\n\n";
    if($logging=="1") { print LOG "-- [ $host ] --\n--\n-- ::(scanning results):: --\n\n";}
    foreach $scanScript (@scan) {
       $scanScriptIDS = $scanScript;     
       $sS = $scanScript;
       $sock_connect = IO::Socket::INET->new(Proto => "tcp", PeerAddr => "$host", PeerPort => "80") 
       || die "[fscan] -- error: connect() :: couldn't connect to $host\n\n"; # opening tcp socket connection to host
       if (defined($opt{'r'})){&randChar;$option="1";}
       if (defined($opt{'f'})){&fakeParam;$option="1";}
       if (defined($opt{'d'})){&insertDot;$option="1";}
       if (defined($opt{'e'})){&encodeUri;$option="1";}
       if (defined($opt{'p'})){&phttp;&verifyscan;}
       if (defined($opt{'s'})){&shttp;&verifyscan;}
       if ((!defined($opt{'p'})) && (!defined($opt{'s'}))){ &nscan; &verifyscan; }
       $sock_connect->autoflush(1); # flushing the buffers. should speed up the scan a little:)
       close($sock_connect);
    }
    print "\n";
}

##############################################
# Multiple hosts scan

sub hf_scan {
    open(HOSTFILE, "$hostfile");
    while (<HOSTFILE>) {
        $host = $_;$host =~ /(\S*)/;
        chomp $host;$hostnum++;
        &host_scan;
        if($logging == "1"){print LOG "\n\n";}
    }
}

##############################################
# Generating Random RxBuffer

sub rxbuffgen { # Just wanted to make sure im choosing mad random numbers:)
    $RxDepth=(rand() * 10) % 10; #calling rand() on rand()
    if($RxDepth=="0"){$RxDepth=1;} #preventing mod 0
    $RxBuffie=(rand() * $RxDepth) % $RxDepth; #calling rand() for bufferlength
    for($RxB=0;$RxB<10+$RxBuffie;$RxB++){
    $RxBuffStr.=chr(((rand() * 26) % 26) + 97);} #the actual buffer
    $RxBuffStr=~s/([-a-zA-Z0-9.])/sprintf("%%%x",ord($1))/ge; #the hex buffer
    $RxBuffer.="%00$RxBuffStr"; #just adding a null to it 
}

##############################################
# The oh-so-default scan :)


sub nscan {
    if($option == "1") {
    send($sock_connect, "HEAD $scanScriptIDS HTTP/1.0\n\r\n\r", 0);
    } else {
    send($sock_connect, "HEAD $scanScript HTTP/1.0\n\r\n\r", 0); 
    }
}

###############################################
# Premature http request closure

sub phttp {
    $RxStart = "/%20";
    $RxHead = "HTTP/1.0%0d%0a";
    $RxTrail = "HTTP/1.0\n\r\n\r";
    $RxHeader = "Header:%20/../";
    $RxTrailer = "..";   
        
    send($sock_connect, "HEAD ", 0);                 #injecting method (GET)
    send($sock_connect, "$RxStart", 0);       #injecting XXBufferStart (request variables)
    send($sock_connect, "$RxHead", 0);    #injecting XXBufferHTTP header (first http terminator)
    send($sock_connect, "$RxHeader", 0);      #injecting XXBufferHeader (http header information)
    send($sock_connect, "$RxTrailer", 0);     #injecting XXBufferTrailer (generating new request buf)
    if($option == "1") {
    send($sock_connect, "$scanScriptIDS ", 0);         #injecting scanScript scripts (script to scan for)
    } else {
    send($sock_connect, "$scanScript ", 0);         #injecting scanScript scripts (script to scan for)
    }
    send($sock_connect, "$RxTrail", 0);   #injecting XXBufferHTTP trailer (second http terminator)
    send($sock_connect, "$RxBuffer", 15);        #injecting XXBuffer (decoy buffer)
}

###############################################
# Sequenced Fragmentation Attack 

sub shttp { 
     send($sock_connect, "HEAD ", 0);            #injecting method
     if($option == "1") {
     send($sock_connect, "$scanScriptIDS ", 0);    #injecting XXScan scripts
     }else{
     send($sock_connect, "$scanScript ", 0);    #injecting XXScan scripts
     }
     send($sock_connect, "HTTP/1.0\n\r\n\r", 0);    #injecting HTTP trailer
     send($sock_connect, "$RxBuffer", 15);   #injecting XXBuffer
}

###############################################
# Return Code Verification

sub verifyscan {
     while(<$sock_connect>) {
        chomp($VerifyScan = $_);
        if($RxDetails == "0") {
            if (($VerifyScan =~ /^HTTP\/1\.1\s500/i) && ($sS = "/scripts/samples/details.idc")) {
               print "-- found: $sS (but DSN not made)\n"; # checking for existance and return code of details.idc
               $RxDetails=1;$foundCount++;
            }
        } elsif($RxDetails == "1") {
            if (($VerifyScan =~ /^HTTP\/1\.1\s500/i) && ($sS = "/scripts/samples/ctguestb.idc")) {
               print "-- found: $sS (but DSN not made)\n"; # checking for existance and return code of ctguestb.idc
               $foundCount++;$RxDetails=2;           
            }
        }
        if ($VerifyScan =~ /^HTTP\/1\.1\s200\sOK/i) {
           print "-- found: $sS\n";
           if ($logging=="1"){print LOG "\t-- found: $sS\n";}
           $foundCount++;
        }
     }
}

###############################################
# fscan header

sub fscan_head {
    print "\n[fscan/(header)] -- Anti-IDS cgi scanning implementation\n";
    print "[fscan/(header)] -- by f0bic -- [lowlevel]\n\n";
    if (defined($opt{'l'})){print "[fscan/(logging)] -- enabled -- [/logs]\n\n";}
    if (defined($opt{'e'})){print "[fscan/(option)] -- using hex uri encoding\n";}
    if (defined($opt{'d'})){print "[fscan/(option)] -- using dot insertion\n";}
    if (defined($opt{'r'})){print "[fscan/(option)] -- using random long url insertion\n";}
    if (defined($opt{'f'})){print "[fscan/(option)] -- using fake parameter insertion\n";}
    if (defined($opt{'p'})){print "[fscan/(method)] -- using premature http request closure\n";}
    if (defined($opt{'s'})){print "[fscan/(method)] -- using sequenced fragmentation attack\n";}
}

###############################################
# fscan single host trailer

sub fscan_trail {
    my($RxTime2) = time();
    printf "[fscan/(status)] -- ($host) -- completed in %.2f seconds\n", $RxTime2 - $RxTime1;
    if ($foundCount == "0"){print "[fscan/(status)] -- no reported vulnerabilities found.\n\n";} 
    else{print "[fscan/(status)] -- found a total of $foundCount possible vulnerabilities\n\n";}
}

###############################################
# fscan multi host trailer

sub fscan_hf_trail {
    my($RxTime2) = time();
    printf "[fscan/(status)] -- scanned a total of %s hosts in %.2f seconds\n\n", $hostnum, $RxTime2 - $RxTime1; 
}

###############################################
# usage

sub usage {
   print "\n[fscan] -- Anti-IDS cgi scanning implementation\n";
   print "[fscan] -- by f0bic -- [lowlevel]\n\n";
   print "[fscan] -- Usage:\n\n";
   print "fscan.pl [..options..] [method] -h/-f <host/hostfile>\n\n";
   print "-h : specifies host\n";
   print "-F : specifies hostfile\n";
   print "-l : enables logging (logs to either <host>.log or <hostfile>.log)\n\n";
   print "-options-\n\n";
   print "-e : URL encoding\n";
   print "-d : dot insertion\n";
   print "-r : random long url insertion\n";
   print "-f : fake parameter insertion\n"; 
   print "\n-methods-\n\n";
   print "-p : premature http request closure (slow)\n";
   print "-s : sequenced fragmentation attack\n";
   print "none: fscan defaults to a regular http request\n";
   print "\n";
}
