Punbb <= 1.2.13 Multiple Vulnerabilities
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
- -= PunBB <= 1.2.13 Multiple Vulnerabilities =-
Written on : 2006/10/10
Released on : 2006/10/29
Author : Nms < nms (at) wargan (dot) org >
Affected application : PunBB <= 1.2.13
Type of vulnerability : SQL Injection and Local File Inclusion
Required PHP Configuration : Register_globals enabled, PHP <= 4.4.2
or PHP <= 5.1.3 for the SQL Injection,
none for the Local File Inclusion
Evaluated Risk : Critical
Solution Status : A new version (PunBB 1.2.14) has been
released which fixes these vulnerabilities
References :
http://www.wargan.org/index.php/2006/10/29/4-punbb-1213-multiple-vulnerabilities
[0] Application description
From punbb.org :
"PunBB is a fast and lightweight PHP powered discussion board.
It is released under the GNU Public License. Its primary goal
is to be a faster, smaller and less graphic alternative to
otherwise excellent discussion boards such as phpBB, Invision
Power Board or vBulletin. PunBB has fewer features than many
other discussion boards, but is generally faster and outputs
smaller pages."
[I] SQL Injection Vulnerability
1) Overview
PunBB is prone to an SQL injection in the search module,
because of an unitialized variable which is undirectly passed
into an SQL query without any check. Using this vulnerability,
a visitor can perform blind SQL injections, which can lead to
the content disclosure of any data stored in the database. The
exploitation of this flaw uses the PHP Zend_Hash_Del_Key_Or_Index
vulnerability, and thus requires register_globals enabled and
PHP <= 4.4.2 or PHP <= 5.1.3 on the server where PunBB is
installed.
2) Explanations
This vulnerability is grounded on both a mistake in PunBB code
with an unitialized variable, and PHP Zend_Hash_Del_Key_Or_Index
vulnerability which allows to bypass the globals deregistration
process that comes with PunBB. First of all, have a look at the
unregister_globals() function in "include/functions.php" :
************************ BEGIN OF CODE ************************
function unregister_globals()
{
// Prevent script.php?GLOBALS[foo]=bar
if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))
exit('I\'ll have a steak sandwich and... a steak
sandwich.');
// Variables that shouldn't be unset
$no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE',
'_REQUEST', '_SERVER', '_ENV', '_FILES');
// Remove elements in $GLOBALS that are present in any of the
// superglobals
$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER,
$_ENV, $_FILES, isset($_SESSION) &&
is_array($_SESSION) ? $_SESSION : array());
foreach ($input as $k => $v)
{
if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))
unset($GLOBALS[$k]);
}
}
************************* END OF CODE ***************************
Using Zend_Hash_Del_Key_Or_Index vulnerability, it is possible
to bypass this globals deregistration process. All the details
on this vulnerability - discovered by Stefan Esser - can be
found in this article :
http://www.hardened-php.net/hphp/zend_hash_del_key_or_index_vulnerability.html
To sum up, as long as PHP meets the required configuration
for this vulnerability, an attacker is able to set any global
variable he wants in PunBB. Now, have a look at the file
"search.php", at the following lines :
************************ BEGIN OF CODE ************************
$row = array();
while ($temp = $db->fetch_row($result))
{
$row[$temp[0]] = 1;
if (!$word_count)
$result_list[$temp[0]] = 1;
else if ($match_type == 'or')
$result_list[$temp[0]] = 1;
else if ($match_type == 'not')
$result_list[$temp[0]] = 0;
}
[...]
@reset($result_list);
while (list($post_id, $matches) = @each($result_list))
{
if ($matches)
$keyword_results[] = $post_id;
}
[...]
if ($author && $keywords)
{
// If we searched for both keywords and author name we want
// the intersection between the results
$search_ids = array_intersect($keyword_results,
$author_results);
unset($keyword_results, $author_results);
}
else if ($keywords)
$search_ids = $keyword_results;
else
$search_ids = $author_results;
[...]
if ($show_as == 'topics')
{
$result = $db->query('SELECT t.id FROM '.$db->prefix.'posts
AS p INNER JOIN '.$db->prefix.'topics AS t ON
t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON
f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp
ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')
WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND p.id
IN('.implode(',',$search_ids).')'.$forum_sql.' GROUP BY
t.id', true) or error[...]
$search_ids = array();
while ($row = $db->fetch_row($result))
$search_ids[] = $row[0];
$db->free_result($result);
$num_hits = count($search_ids);
}
************************* END OF CODE *************************
In this piece of code, the $result_list array is obviously not
initialized. Using the Zend_Hash_Del_Key_Or_Index vulnerability,
we are thus able to populate this array with any possible
content. Consequently, if you perform a search request with only
a keyword and no author f.e., an attacker is thus able to
populate $keyword_results and then $search_ids indexes with any
possible content coming from $result_list. Finally, the
$search_ids array is imploded and put in the SQL query without
any protection. In a word, there is an SQL injection here.
3) Exploitation
With an adequate UNION query in the $result_list array, an
attacker is able to perform blind SQL injections and f.e.
retrieve the entire hash of any user just by looking if the
script returned some results for his malicious search. For
example, you can send the following request :
search.php?action=search&keywords=hello&author=&forum=-1
&search_in=all&sort_by=0&sort_dir=DESC&show_as=topics&search=1
&result_list[< UNION SQL QUERY >/*]&1763905137=1&1121320991=1
With such a request, you can disclose each character of the
admin hash for example. You don't even need to be registered to
perform this blind SQL injection : all you need is the userid of
an admin (or any user), and the correct $punbb_db_prefix (very
often easily guessable if it's not the default one "punbb_").
Actually, it is possible to go a little bit further and forge
quite easily an admin cookie. Indeed, the $cookie_seed variable
which is used to forge more secure cookies, is created during
the installation in install.php :
$cookie_seed = substr(md5(time()), -8)
If you are able to know the past time() of the forum creation,
you are able to forge an admin cookie using the cookie_seed and
the admin hash. A very simple way to know this past time() is to
retrieve the admin value of the "registered" field in the users
table, seing that the admin account is registered during the
install, a few lines above the $cookie_seed line in install.php.
Thus, using the previous SQL injection, an attacker can retrieve
this "registered" field for the superadmin account and hence
deduce the time() of the install, then the $cookie_seed value,
and finally forge an admin cookie.
II] Local File Inclusion / Remote Code Execution Vulnerability
**********************************************************
1) Overview
PunBB is prone to a local file inclusion in common.php through
the $pun_user['language'] variable, which can lead to remote
PHP code execution on servers where PunBB is installed. The
exploitation of this flaw does not require any special
configuration of PHP.
2) Explanations
PunBB comes with a lot of langage files inclusions in all
scripts. Among these inclusion, let's focus on the one which is
systematically performed whatever punbb script is called, in
include/common.php :
************************ BEGIN OF CODE ************************
@include PUN_ROOT.'lang/'.$pun_user['language'].'/common.php';
************************* END OF CODE *************************
For each user, the $pun_user['language'] variable takes the
corresponding value of the user 'langage' field in the users
table. There are only two ways for a user to set or modify this
value. The first one is in profile.php, but the following
instruction on line 723 :
************************ BEGIN OF CODE ************************
$form['language'] = preg_replace('#[\.\\\/]#', '',
$form['language']);
************************* END OF CODE *************************
prevents to put any malicious content in the langage field. The
second way is in register.php at the following lines :
************************ BEGIN OF CODE ************************
$language = isset($_POST['language']) ? $_POST['language'] :
$pun_config['o_default_lang'];
[...]
// Add the user
$db->query('INSERT INTO '.$db->prefix.'users (username,group_id,
password, email, email_setting, save_pass, timezone,
language, style, registered, registration_ip, last_visit)
VALUES(\''.$db->escape($username).'\', '.$intial_group_id.',
\''.$password_hash.'\', \''.$email1.'\', '.$email_setting.',
'.$save_pass.', '.$timezone.' , \''.$db->escape($language).'\',
\''.$pun_config['o_default_style'].'\', '.$now.',
\''.get_remote_address().'\','.$now.')') or error(...)
************************* END OF CODE *************************
The $langage variable is filled with the value of the user-input
'langage' without any security check, and is then passed through
the INSERT query, which allows a newly registered user to put
any malicious content in his 'langage' field in the users table.
This obviously leads to a local file inclusion possibility in
include/common.php .
3) Exploitation
In order to get rid of the suffix '/common.php' in the include
instruction, an attacker can use the classical NULL Byte trick.
No matter if PunBB addslashes this NULL Byte, because MySQL
stripslashes it before storing it in the database.
At this point, it is very classical (and quite simple) to
execute PHP code using this local inclusion. For example, if
avatars are enabled, all an attacker has to do is upload a valid
GIF file with a malicious PHP content with a previous account,
then register as a new user and post a 'language' value
containing the relative path to the malicious image : this way
he finally gets a shell on the server just by logging in with
his new account. Besides, he can also, depending on the server
configuration, disclose the content of server files.
III] Recommandations / Thanks
************************
The vendor has released a new version which fixes these
vulnerabilities. It is strongly recommended to upgrade to
PunBB 1.2.14 which can be found at :
http://www.punbb.org/downloads.php
Special thanks to John and Roman0 for their help in testing
these vulnerabilities.
Contact : Nms < nms (at) wargan (dot) org >
GPG Key : http://www.wargan.org/Nms_0x44A0274A_public_key.asc
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)
iD8DBQFFRVyDGMRtwkSgJ0oRAn+RAJ9tuI/BEuwDhQvOqjCh4PXhTcFbLACeLNPD
T3EdstyyVbPTmtcO2+270IQ=
=5Za5
-----END PGP SIGNATURE-----