<<< Date Index >>>     <<< Thread Index >>>

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