COMMAND
vBulletin
SYSTEMS AFFECTED
vBulletin
PROBLEM
Jouko Pynnonen found following. vBulletin is a commonly used web
forum system written in PHP. One of its key features is use of
templates, which allow the board administrator to dynamically
modify the look of the board.
vBulletin templates are parsed with the eval() function. This
could be somewhat safe as long as the parameters to eval() are
under strict control. Unfortunately this is where vBulletin
fails. With an URL crafted in a certain way, a remote user may
control the eval() parameters and inject arbitrary PHP code to be
executed.
A remote user may thus execute any PHP code and programs as the
web server user, typically "nobody", start an interactive shell
and try to elevate their privilege. The configuration files are
accessible for the web server so the user can in any case access
the MySQL database containing the forums and user information.
According to the authors the vulnerability exist in all versions
of vBulletin up to 1.1.5 and 2.0 beta 2. The bug does not involve
buffer overrun or other platform-dependant issues, so it's
presumably exploitable under any OS or platform.
vBulletin templates are implemented in the following way: the
gettemplate() function in global.php is used to fetch a template
from database. The code is then passed to eval(). If we take
index.php for an example, there's this code:
if ($action=="faq") {
eval("echo dovars(\"".gettemplate("faq")."\");");
}
The dovars() function does some variable replacing, such as
replace <largefont> with <font size="10">. The gettemplate()
function is defined in global.php:
function gettemplate($templatename,$escape=1) {
// gets a template from the db or from the local cache
global $templatecache,$DB_site;
if ($templatecache[$templatename]!="") {
$template=$templatecache[$templatename];
} else {
$gettemp=$DB_site->query_first("SELECT template FROM template WHERE title='". addslashes($templatename)."'");
$template=$gettemp[template];
$templatecache[$templatename]=$template;
}
if ($escape==1) {
$template=str_replace("\"","\\\"",$template);
}
return $template;
}
For effectiveness the function implements a simple cache for
template strings. After fetching them from the database they're
stored in the templatecache[] array. This array is checked for
the template before doing the SQL query. Unfortunately the array
is never initialized, so a user can pass array contents in the
URL, e.g. (for simplicity not %-escaped)
http://www.site.url/index.php?action=faq&templatecache[faq]=hello+world
With this URL, you won't get the FAQ page, but just a blank page
with the words "hello world".
The eval() call above will execute
echo dovars("hello world");
As if this wouldn't be bad enough, a remote user may as well pass
a value containing quotation marks and other symbols. Quotation
marks aren't always escaped as seen in the code above, in which
case index.php could end up executing code like
echo dovars("hello"world");
This would produce a PHP error message due to unbalanced quotes.
It doesn't take a rocket scientist to figure out how a remote user
could execute arbitrary code from here, so further details about
exploitation aren't necessary. If your vBulletin board produces
an error message with an URL like the one above prefixed with a
single quotation mark, it's definitely vulnerable.
The above example works with the "Lite" version. The commercial
versions are vulnerable too, but details may differ. After a
little experimenting on the Jelsoft's test site we found some of
the commercial versions also have an eval() problem with URL
redirecting, e.g.
http://www.site.url/member.php?action=login&username=myuser&password=mypass&url=hello"world
and a similar one in the Lite version:
http://www.site.url/search.php?action=simplesearch&query=searchthis&templatecache[standardredirect]=hello"world
SOLUTION
The vendor (Jelsoft Enterprises Ltd) was contacted March 2nd, and
has released fixed commercial versions 1.1.6 and 2.0 beta 3.
The vendor hasn't fixed the free "Lite" version of the software so
far and hasn't replied query concerning it, so here is a quick fix
$templatecache=array();
Add that line to the beginning of global.php after the "<?php"
line. It will initialize the template cache and override any
values a remote user may have tried to pass in the URL.
Fix for the redirect problem: replace global.php line 99
$url=$redirectloc;
with this line:
$url=addslashes($redirectloc);