Home / exploitsPDF  

PunBB-1.2.13.txt

Posted on 31 October 2006

-----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-----

 

TOP

Malware :