#!/usr/bin/perl 
#  _____ _
# |  ___| | _____      __
# | |_  | |/ _ \ \ /\ / /
# |  _| | | (_) \ V  V /
# |_|   |_|\___/ \_/\_/
#        Security group.
# 
# fl0w-s33ker.pl v1.4
#
# Description: Simple tool for tracking overflow.
#              It uses GDB calls to get 
#              regiters addresses at overflow time.
#
#              I wrote no README or Changelog just
#              becouse i have no patience at all.
#              In doubt make me questions
#              on irc.flowsecurity.org at #flowsecurity.
#
#              Try: ./fl0w-s33ker.pl -h
#
# 1: Simple test. Ex. ./vulnerable "$buffer"
# 2: Adjacent mem test. Ex. ./vulnerable 512 "$buffer"
# 3: Environment test. Ex. export HACK="AAAA" ; ./vulnerable
# 4: Lame Integer test. Ex. ./vulnerable slot-number integer
#
# 	Enjoy
# 	
# Author: nuTshell  -=nutshell@flowsecurity.org=-
#
# Greetz:   
#           Friends from irc.flowsecurity.org
#           and friends from everywhere.
#
use strict;
use Switch;
use Devel::GDB;
use Term::ANSIColor;

my $version = "fl0w-s33ker.pl v1.4";
my $string = "\x41";
my $space = "\x20";
my $sigsegv = 35584;
my $barloop =0;
my $bar = 0;
my $simple = 0;
my $counter = 1;
my $debugeipcounter = 0;
my $buff = "$string";
my $intcounter = -1073746000;
my $intcounterend = 1073746000;
my $inteip = "0xbfffff*";
my $logfile2 = "LOG-s33ker.txt";

my $ret = "";
my $firstsigsegv = "";
my $gdb = "";
my $blimit = "";
my $bugfile = "";
my $logfile = "";
my $logname = "";
my $status = "";
my $adjstring = "";
my $adjlength = "";
my $output = "";
my $option = "";
my $errlog = "";
my $HACK = "";
my $CMD = "";
my $execargs = "";
my $debug = "";
my $debugeip = "";
my $debugeipcounterlmt = "";
my $debugeipinput = "";
my $counterlmt = "";
my $date = "";

sub info1() {
printf <<EOF
       Limit is set: $blimit bytes
       Filling up $bugfile`s buffer with 0x41 (A`s)
       until we get SIGSEGV, if progress bar stop try ctrl+c. 
       Wait...
EOF
}

sub info2() {
printf <<EOF
       Lame integer overflow test.
       Starting from $intcounter to $intcounterend.
       We must have $inteip as \$eip address.
       Wait...Go get a coffee :]
EOF
}

sub log1 () {
       open(LOGCOMOM, ">>$logfile2") or die "$!\n";
       printf(LOGCOMOM "\n              -= $date =- \n");
       printf(LOGCOMOM "                   Tested file: $bugfile\n");
       printf(LOGCOMOM "First SIGSEGV occurs at $firstsigsegv bytes.\n");
       printf(LOGCOMOM "At $ret bytes:\n");
       printf(LOGCOMOM "$output\n");
       close(LOGCOMOM);
       printf("Log saved!\n");
       exit(0);

}
sub log2() {
        open(LOGCOMOM, ">>$logfile2") or die "$!\n";
        printf(LOGCOMOM "\n              -= $date =- \n");
        printf(LOGCOMOM "                   Tested file: $bugfile\n");
        printf(LOGCOMOM "$debugeip");
        printf(LOGCOMOM "Got \$esp address at value $intcounter\n");
        close(LOGCOMOM);
        printf("Log saved!\n");
        exit(0);

}
sub log3() {
	open(LOGCOMOM, ">>$logfile2") or die "$!\n";
	printf(LOGCOMOM "\n             -= $date =-\n");
	printf(LOGCOMOM "                  Tested file: $bugfile\n");
	printf(LOGCOMOM "SIGSEGV occurs at $ret bytes.\n");
	close(LOGCOMOM);
	printf("Log saved!\n");
}

sub menu () {
printf <<EOF
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-  fl0w-s33ker  +-+-+-+-+-+-+-+-+-+-+-+-+-+
         Coded by nuTshell  -=  nuTshell\@flowsecurity.org =-           
   
   Usage: $0 [-h|-v|-lwo|-lo|-lall]   
   -h                      [This menu]
   -v			   [Version]
   -lw			   [Log WeIrD output]
   -lo                     [Log results output] 
   -lall		   [Log WeIrD & results]

   Usage: $0 <ENTER>   
   Filename 		   [Vulnerable filename]
   Options:
   [1] simple test
   [2] adjacent test
   [3] environment test (no dubugging)
   [4] integer overflow test 

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
EOF
}


sub printbar() {
$bar = $barloop + 1;
$barloop++;
if ($bar == 20) {printf("-") ; $bar = 0 ; $barloop = 0};
}

sub cmdarg () {
printf("Enter as many arguments as needed.\n");
printf("Each arg must be followed by <ENTER>\n");
printf("To finish just type \"quit\":\n");
$CMD = <STDIN> ; chop($CMD);
$CMD .= $space;
	while ($CMD !~ /quit/) {
               $CMD .= <STDIN> ;chop($CMD);
               $CMD .= $space;
	}
$CMD =~ s/quit//g;
}

if ("$ARGV[0]" eq "-h") {&menu and exit(0)}
if ("$ARGV[0]" eq "-v") {printf "$version\n" and exit(0)}
if ("$ARGV[0]" eq "-lw" || "$ARGV[0]" eq "-lall") {
      $logfile = ">> LOG-s33ker.weird.txt 2>&1";
      $logname = $logfile;
      $logname =~ s/2>&1//g;
      printf color("bold");
      printf("\nWARNING");
      printf color("reset");
      printf(": \"-lw and -lall\" flags can be dangerous..well what isn`t??\n");
      printf("Logging stderr can get big files depending on your test.\n");
      printf("Ctrl+c...? \"Warned were you\" -yoda :)\n");
      printf("Logname $logname\n");
} else {$logfile = ">/dev/null 2>&1"}
			
	
printf("\n-= $version =-\n-= Coded by nuTshell =-\n");
printf("\nFilename:\n");
printf("option> ");

$bugfile = <STDIN> ; chop($bugfile);

if (! -f $bugfile) {die "$bugfile $!\n"}

printf("Options:\n");
printf("[1] simple test\n");
printf("[2] adjacent test\n");
printf("[3] environment test (no dubugging)\n");
printf("[4] integer overflow test\n");
printf("option> ");

$option = <STDIN> ; chop($option);

if ($option <= 0 || $option >= 5) { die "Invalid option\n" }

switch($option) {

	case "1"  { printf("Command arguments? [y/N]:\n");
		    printf("option> ");
		    $execargs = <STDIN> ; chop($execargs);
		    if ("$execargs" eq "y") {&cmdarg}
	    }
	
	case "2" { printf("Command arguments? [y/N]:\n");
		   printf("option> ");
		   $execargs = <STDIN> ; chop($execargs);
		   if ("$execargs" eq "y") {&cmdarg}
		   printf("Adjacent fixed buffer length:\n");
		   printf("option> ");
		   $adjlength = <STDIN> ; chop($adjlength);

		   if(!$adjlength) {printf("Adjacent fixed buffer length REQUIRED! Try again.\n") ; exit(1)}
                   
		   $adjstring = "$string"x$adjlength;
	    } 

	case "3" { printf("Command arguments? [y/N]:\n");
		   printf("option> ");
		   $execargs = <STDIN> ; chop($execargs);

		   if ("$execargs" eq "y") {&cmdarg}

		   printf("Variable name:\n"); 
		   printf("option> ");
		   $HACK = <STDIN> ; chop($HACK);
            }
        case "4" { printf("Command arguments? [y/N]:\n");
		   printf("option> ");
		   $execargs = <STDIN> ; chop($execargs);

		   if ("$execargs" eq "y") {&cmdarg}
	    }
}

if ("$option" ne "4") {
	printf("Buffer limit [1500]:\n");
	printf("option> ");
	$blimit = <STDIN> ; chop($blimit);
	if (!$blimit) {$blimit = 1500}
} else {
	printf("\nBegin: $intcounter\n");
	printf("End:     $intcounterend\n\n");
}

if (!$bugfile || !$option) {&menu and exit(1)}
if ("$option" eq "3") {if (!$HACK) {&menu and exit(0)}}

sub exec() {

if ("$option" eq "-h") {&menu and exit(0)}

if ("$option" eq "1") {$status = system("$bugfile $CMD $buff $logfile")}

if ("$option" eq "2") {$status = system("$bugfile $CMD $adjstring $buff $logfile")}

if ("$option" eq "3") {local($ENV{"$HACK"}) = $buff ; 
		       $status = system("$bugfile $CMD $logfile")}

}


sub run1 () {
&info1 ;
printf("[");
while ($counter <= $blimit) {

&exec;
&printbar;

$status != $sigsegv or $ret = $counter + 4 and printf("> Done!\n$bugfile is vulnerable at $counter bytes!\n") and last;

  $buff .= "$string";
  $counter++;
}
if ($counter > $blimit) {
  printf(" Done!\n$bugfile is not vulnerable at least until $blimit bytes\n");
}
}
if ("$option" eq "1" || "$option" eq "2" || "$option" eq "3" ) { &run1 }

sub run2 () {
&info2;
$gdb = new Devel::GDB (-file => $bugfile ) ;

while ($intcounter <= $intcounterend) {
	
$gdb -> get ( "r $CMD $intcounter" );
$debugeip = $gdb -> get ( "i r eip" );

if($debugeip =~ /$inteip/) { 
	printf("...Done!\n");
        $debugeip = $gdb -> get ( "i r esp ebp esi edi eip");
	printf("$debugeip"); 
	printf("Got return address at value: $intcounter\n");
	last;
} 
$intcounter++;
if($intcounter == $intcounterend) {printf("Sorry, no results.\n") ; exit(0)}
 }	
}

switch($option) {

case "1"   { 

  if($status == $sigsegv) {printf("Debug? [n/Y]:\n"); printf("option> ");
  $debug = <STDIN> ; chop($debug);
  if("$debug" eq "n") {exit(0)}}

  $gdb = new Devel::GDB (-file => $bugfile ) ;
  $debugeip = $gdb -> get ( "i r eip" );
  if($status != $sigsegv) {exit(1)}
  if($debugeip =~ /0x42424242/) {
    printf("\n[!] Status at $ret bytes:\n\n");
  }
  $buff .= "\x42\x42\x42\x42";
  $firstsigsegv = (length($buff) - 4);
  $gdb -> get ( "r $CMD $buff" );
  $debugeip = $gdb -> get ( "i r eip" );
  if($debugeip !~ /0x42424242/) {
        printf("\$eip wasn`t overwritten.");
        printf("\n[!] Status at $ret bytes:\n\n");
        printf("$debugeip\n");
        printf("Shall i use brute force to get correct addresses? [n/Y]:\n");
        printf("option> ");
        $debugeipinput = <STDIN> ; chop($debugeipinput);
        if("$debugeipinput" ne "n") {
             printf("Max bytes number to increase on buffer [20]:\n");
             printf("option> ");
             $debugeipcounterlmt = <STDIN> ; chop($debugeipcounterlmt);
             if(!$debugeipcounterlmt) {$counterlmt = 20} else {$counterlmt = $debugeipcounterlmt}
             while($debugeipcounter <= $counterlmt) {
		     $buff .= "\x42";
                     $gdb -> get ( "r $CMD $buff" );
                     $debugeip = $gdb -> get ( "i r eip" );
                     $ret++;
		     $debugeipcounter++;
                     $debugeip !~ /0x42424242/ or last ;
                     }
               }
        printf("\n[!] Status at $ret bytes:\n\n");
   }
 
  $output = $gdb -> get ( "i r esp ebp esi edi eip" );
  printf("$output\n");
	}

case "2"  {

   if($status == $sigsegv) {printf("Debug? [n/Y]:\n"); printf("> ");
   $debug = <STDIN> ; chop($debug);
   if("$debug" eq "n") {exit(0)}}
   $gdb = new Devel::GDB (-file => $bugfile ) ;
   $debugeip = $gdb -> get ( "i r eip" );
   if($status != $sigsegv) {exit(1)}
   if($debugeip =~ /0x42424242/) {
      printf("\n[!] Status at $ret bytes:\n\n");
   }
   $buff .= "\x42\x42\x42\x42";
   $firstsigsegv = (length($buff) - 4);
   $gdb -> get ( "r $CMD $adjstring $buff" );
   $debugeip = $gdb -> get ( "i r eip" );
   if($debugeip !~ /0x42424242/) {
          printf("\$eip wasn`t overwritten.");
          printf("\n[!] Status at $ret bytes:\n\n");
          printf("$debugeip\n");
          printf("Shall i use brute force to get correct address? [n/Y]:\n");
          printf("option> ");
	  $debugeipinput = <STDIN> ; chop($debugeipinput);
	  if("$debugeipinput" ne "n") {
		printf("Max bytes number to increase on buffer [20]:\n");
		printf("option> ");
		$debugeipcounterlmt = <STDIN> ; chop($debugeipcounterlmt);
		if(!$debugeipcounterlmt) {$counterlmt = 19} else {$counterlmt = $debugeipcounterlmt}
		while($debugeipcounter <= $counterlmt) {
			$buff .= "\x42";
			$gdb -> get ( "r $CMD $adjstring $buff" );
			$debugeip = $gdb -> get ( "i r eip" );
			$ret++;
		        $debugeipcounter++;
			$debugeip !~ /0x42424242/ or last ;
                 }
            } 
	printf("\n[!] Status at $ret bytes:\n\n");
   }
   $output = $gdb -> get ( "i r esp ebp esi edi eip" );
   printf("$output\n");
	}

case "3" {

   printf("Warning: Gdb calling does not support env-method untill now.\n");
   if ($status == $sigsegv) {
   printf("With $ret bytes maybe is possible to control \$eip register.\n")
         }
     }

case "4" {
	&run2;	
 }

}

if("$ARGV[0]" eq "-lo" || "$ARGV[0]" eq "-lall") {

	$date = localtime();    

switch($option) {
       case "1" {&log1}
       case "2" {&log1}
       case "3" {&log3}
       case "4" {&log2}
	}
}
#eof (end of FUCK)
