Monday, June 23, 2014

Multiple vulnerabilities in bugs.php.net, pecl.php.net, master.php.net and gtk.php.net

Another "sprint code review" resulted in many vulnerabilities in *.php.net sites.

Short summary:
  • bugs.php.net: SQLi, XSS
  • pecl.php.net: SQLi, XSS
  • master.php.net: SQLi, XSS, possible server-side command execution
  • gtk.php.net: SQLi, XSS, auth bypass

Reported: 03.05.2014
Fixed: 11.06.2014

Details:

bugs.php.net

  • SQL Injection in get_resolve_reasons() function from functions.php (project variable)
    function get_resolve_reasons($project = false)
    {
     global $dbh;
    
     $where = '';
    
     if ($project !== false)
      $where.= "WHERE (project = '{$project}' OR project = '')";
    
     $resolves = $variations = array();
     $res = $dbh->prepare("SELECT * FROM bugdb_resolves $where")->execute(array());
     ...
    

  • 2. XSS in bug.php ($_POST['in']['email'])
    ...
    <input type="text" size="40" maxlength="40" name="in[email]" value="<?php echo isset($_POST['in']) && isset($_POST['in']['email']) ? $_POST['in']['email'] : ''; ?>" />
    ...
    

pecl.php.net

  • XSS in account-edit.php (handle parameter), because of bad regexp validation
    ...
    if ($handle && !preg_match('@[0-9A-Za-z_]{2,20}$@', $handle)) {
        response_header('Error:');
        report_error("No valid handle given!");
        response_footer();
        exit();
    }
    ...
    
    Regular expression used in preg_match is checking only string ending, not the beggining. Possible example: account-edit.php?handle=<script>alert('XSS')</script>AAAA

  • SQL injection in package-delete.php (id parameter)
    ...
        $query = "SELECT p.name, r.version FROM packages p, releases r
                    WHERE p.id = r.package AND r.package = '" . $_GET['id'] . "'";
    
        $row = $dbh->getAll($query);
    ...
    

  • XSS in package-delete.php (id parameter)

  • Some other minor issues I've noticed:
    • Small typo (should be $_GET instead of $GET) in package-new.php:
      ...
      if(isset($_GET[$arg])) $_GET[$arg] = htmlspecialchars($GET[$arg], ENT_QUOTES);
      ...
      
    • User with password that match /^[a-z0-9]{32}$/ is unable to log in.
      ...
      function auth_verify($user, $passwd)
      ...
         // Check if the passwd is already md5()ed
         if (preg_match('/^[a-z0-9]{32}$/', $passwd)) {
          $crypted = $passwd;
         } else {
          $crypted = md5($passwd);
         }
      ...
      

master.php.net

  • Possible serveside command execution in network/api.php
    ...
    $res = db_query("SELECT * FROM mirrors LEFT JOIN country ON mirrors.cc = country.id WHERE mirrors.hostname='".mysql_real_escape_string($_GET['host'])."' LIMIT 0,1");
    $row = mysql_fetch_assoc($res);
    ...
    $cname = $row['cname'];
    $ip_info = str_replace(PHP_EOL,'; ',trim(`host $cname | grep -i address`));
    $ping_stats = nl2br(trim(`ping -c1 -i1 -w1 $cname | grep -v PING | grep -v "ping statistics"`));
    $ip_addr = gethostbyname($_GET['host']);
    ...
    
    Although cname variable comes from database it's not properly sanitized by escapeshell* function(s).

  • Many SQL injections in forgot.php, entry/svn-account.php, manage/event.php, manage/mirrors.php. However they're not exploitable because of magic_quotes_gpc enabled in production environment (but in other places user input is sanitized anyway)

  • SQL injection in manage/user-notes.php (id parameter)
    ...
    $sql = 'DELETE FROM votes WHERE votes.note_id = ' . real_clean($id);
    ...
    
    include/functions.inc:
    ...
    function real_clean($var)      { return mysql_real_escape_string($var); }
    ...
    
    Neither magic_quotes_gpc nor real_clean() protect from specific injection (like: '1 or 1=1').

  • XSS in manage/event.php (action parameter)
  • ...
    $valid_vars = array('id', 'action','in','begin','max','search','order','full','unapproved');
    foreach($valid_vars as $k) {
        $$k = isset($_REQUEST[$k]) ? $_REQUEST[$k] : false;
    }
    ...
    if ($id && $action) {
      switch ($action) {
     ...
      default:
        warn("that action ('$action') is not understood.");
      }
    }
    ...
    
    functions.inc:
    ...
    function format_warn($message) { return "

    $message

    "; } function warn($message) { echo format_warn($message); } ...

gtk.php.net

Note: First of all the whole site in production environment seems to be deprecated and many things don't work.
  • Authorization bypass:

    In most places authorization is done by:
    ...
    if ($user = get_user()) {
    ...
    

    cvs-auth.inc:
    ...
    function get_user() {
    
     if (isset($_COOKIE['PHP-GTK'])) {
      list($user, $pass) = explode(':', base64_decode($_COOKIE['PHP-GTK']));
      $stored = file_get_contents(DB_DIR."/$user.txt");
      if ($pass == $stored) {
       return $user;
      }
     }
     return false;
    }
    ...
    

    Setting cookie to base64_encode("user_that_do_not_exists:") will bypass authorization because of used "==" operator ('' == false -> true).

  • Multiple SQL injections in manual/browse-notes.php, manual/browse.php

  • XSS in manual/browse-notes.php, params: $_GET['let'] and $_GET['y']

  • manual1/* and apps/* vulnerabilities but it seems they're broken/disabled in production environment (propably because of mysql_connect timeout)


Commits with fixes:

http://git.php.net/?p=web/bugs.git;a=commit;h=e353f1f83f51adb95a5fc981e0ee37d2374602d5
http://git.php.net/?p=web/bugs.git;a=commit;h=46a74d234c026fea0928764e940a729801d604b5
http://git.php.net/?p=web/gtk.git;a=commit;h=7a62171c7ed46085d3d1244abea28e7a3e65ad11
http://git.php.net/?p=web/gtk.git;a=commit;h=7230b03244974298af17507a36f34d10a9d777a0
http://git.php.net/?p=web/gtk.git;a=commit;h=723496f654da0b63c128d46a67c3952aed195a83
http://git.php.net/?p=web/pecl.git;a=commit;h=219bbdfce56c8cfca91189fa8a9bb2df6158d02c
http://git.php.net/?p=web/pecl.git;a=commit;h=0a30bab1c4763ebf5a36120afd4039b23da5a427
http://git.php.net/?p=web/pecl.git;a=commit;h=5251a3f8518a600a07d3ceacc2606c167dd0fba8
http://git.php.net/?p=web/pecl.git;a=commit;h=2a1f91d8016ddc4be5156743f49e922a2ab6a937
http://git.php.net/?p=web/master.git;a=commit;h=e024ef1a36b36785955816a1ee95c9c498ad0550
http://git.php.net/?p=web/master.git;a=commit;h=9404bdc83562397e78c35e6daf2c91bf8a886f60
http://git.php.net/?p=web/master.git;a=commit;h=efa8fa543bd8ebb808407be4f2dcc7c3204a615b
http://git.php.net/?p=web/master.git;a=commit;h=41e4d4aff29ccbf0ab3ac756e344d73ba1f4e0c2
http://git.php.net/?p=web/master.git;a=commit;h=1b0dac3d83739242e2cca66ea533bc03e5553ada
http://git.php.net/?p=web/master.git;a=commit;h=0ac39f3249b9c06cea6e50fa985f447cba92a309
http://git.php.net/?p=web/master.git;a=commit;h=e7dca7e9d57a29cf93c2a5673c0d8acd275e4c1e
http://git.php.net/?p=web/master.git;a=commit;h=b75fa9c0ebdcf7da01c2d68500c2de13a5ea2d83
http://git.php.net/?p=web/master.git;a=commit;h=f1ba778df22b8e54a3e71d728ad7cf06be3c502d

Tuesday, June 10, 2014

MPOS (cryptocurrencies mining portal) XSS

During another "sprint code review" session I found a simple XSS in MPOS JSONP handling. MPOS is a web based mining portal for various crypto currencies written in PHP.



Vulnerable is callback parameter introduced in this commit. (note: Content-Type response header is text/html)

Attacker needs a valid api key. Usually he can get it by just signing up to a pool.

Example:
https://pool/index.php?callback=XSS&page=api&action=getuserstatus&api_key=VALID_API_KEY

Found and reported: 25.05.2014
Fixed: 10.06.2014

Ps. It was introduced after more or less security-related discussion here.