#!/usr/bin/perl

########################################################################
# (c) Filip Maertens/CISSP, .HTR Heap Overflow checker.
# 
# DISCLAIMER: This tool is only to be used for legitimate purposes only.
# This is considered as an intrusive, so  please adhere to the laws  and
# regulations applicable in your country.  Oh, and honey, there is pizza
# in the fridge...  
#
# CREDITS: @stake/KPMG for the advisory
#          Thor Larholm for the patch identification remark
#
########################################################################


use Socket;

print "iischeck.pl | Microsoft .HTR Heap Overflow Checker | <filip\@securax.be>\n-----------------------------------------------------------------------\n";

$host= @ARGV[ 0 ];
$method= @ARGV[ 2 ];
my $target = inet_aton($host);
$port = 80;

$requestmethod[0] = "GET";
$requestmethod[1] = "HEAD";
$requestmethod[2] = "POST";


# Initializing strings & vars

$patchedstring    = "InsertElementAnchor";
$nonpatchedstring = "document.write";
$bogusurl         = "/xxxiischeckxxx";


# Main loop of rotten code

if ($host ne "") {

  print " -- Checking hostname: $host\n";
  
  $rawrequest = "$requestmethod[$method] $bogusurl HTTP/1.1\nClient-Agent:iischeck.pl\nHost:$host\r\n\r\n";    
  @results = sendrequestandgetanswer($rawrequest);

  $criticalline = $results[49];   # 49, since HTTP headers are included

  if ($results[2] =~ "IIS") {
  
    SWITCH: {
                if ($criticalline =~ $nonpatchedstring) { $patched = " -- Status: System vulnerable."; last SWITCH; }
                if ($criticalline =~ $patchedstring) { $patched = " -- Status: System MS02-18 patched."; last SWITCH; }
                $patched = " -- Status: Cannot identify patch level";
            }  

  print "$patched\n\n";
  
  } else {
  
    print " -- Error: System is not a Windows/IIS host.\n\n";
  
  }

} else {

  showusage();
  
}


exit(0);


#######: Functions used by iischeck.pl :#######

sub showusage
    {
     print "Usage: iischeck [hostname] -method [method]\n";
    }

sub sendrequestandgetanswer
	{
 	my ($rawrequest)= @_;
	@lines = sendrawandgetanswer ($rawrequest);
	return @lines;
	}

sub sendrawandgetanswer 
	{
 	my ($pstr)=@_;
 	socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp') || 0) || die(" -- Error in creating socket\n");
 	if (connect(S,pack "SnA4x8",2,$port,$target))
		{
  		my @in="";
  		select(S); 
		$|=1; 
		print $pstr;
		while(<S>) 
			{
			push @in,$_; 
			last if ($line=~ /^[\r\n]+$/ );
			}
  		select(STDOUT); 

		return @in;
 		} 
	else 
		{ 
		die(" -- Error connecting to: $host\n"); 
		}
	}


sub sendraw
	{
 	my ($pstr)=@_;
 	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;

 		} 
	else 
		{ 
		die("connect problems\n"); 
		}
	}