Advisory 03/2009: Piwik Cookie unserialize() Vulnerability

December 9th, 2009 by Stefan Esser

I released an important advisory about a remotely exploitable unserialize() vulnerability in Piwik today.

                         SektionEins GmbH
                        www.sektioneins.de

                     -= Security  Advisory =-

     Advisory: Piwik Cookie Unserialize() Vulnerability
 Release Date: 2009/12/09
Last Modified: 2009/12/09
       Author: Stefan Esser [stefan.esser[at]sektioneins.de]

  Application: Piwik <= 0.4.5
     Severity: Piwik unserializes() user input which allows an attacker
               to send a carefully crafted cookie that when unserialized
               utilizes Piwik's classes to upload arbitrary files or
               execute arbitrary PHP code
         Risk: Critical
Vendor Status: Piwik 0.5.0 was released which fixes this vulnerability
    Reference: advisory-032009-piwik-cookie-unserialize-vulnerability
               RSS09-WebApplicationFirewallBypassesAndPHPExploits.pdf
               POC2009-ShockingNewsInPHPExploitation.pdf           

Overview:

  Quote from http://www.piwik.org
  "Piwik is a downloadable, open source (GPL licensed) web analytics
   software program. It provides you with detailed real time reports
   on your website visitors: the search engines and keywords they
   used, the language they speak, your popular pages… and so much more.

   Piwik aims to be an open source alternative to Google Analytics."

  Piwik recently became sourceforge project of the month and won the
  Infoworld Bossie Award for best open source enterprise software which
  made it quite popular. Therefore Piwik is nowadays installed on many
  high profile websites like: banking websites, political party websites,
  gaming websites, blogs and even security company websites.

  During our research in unserialize() vulnerabilities it was discovered
  that Piwik unserializes data from the user supplied cookie. By
  unserializing some of Piwik's objects it is possible to write
  arbitrary files to writable locations on the webserver which
  can be used to upload e.g. PHP files to writable directories
  within the webserver's document root which usually exist in a
  standard Piwik installation. In newer versions of Piwik it is
  also possible to execute arbitrary PHP code directly.

  Combined with the interruption vulnerability exploits demonstrated
  by SektionEins at Syscan and Blackhat it is possible to disable
  all internal PHP security protections and execute arbitrary code
  e.g. local kernel exploits to become root.

Details:

  SektionEins recently demonstrated how it is sometimes possible
  to execute arbitrary PHP code in an application using unserialize()
  on user supplied data. In detail various exploits were shown that
  work against all Zend Framework based applications that unserialize()
  user input. Part of this research was to find popular PHP open
  source applications that are vulnerable to this.

  During our search it was discovered that Piwik does unserialize()
  data from the cookie and uses parts of the Zend Framework:

  protected function loadContentFromCookie()
  {
    $cookieStr = $_COOKIE[$this->name];
    $values = explode( self::VALUE_SEPARATOR, $cookieStr);
    foreach($values as $nameValue)
    {
      $equalPos = strpos($nameValue, '=');
      $varName = substr($nameValue,0,$equalPos);
      $varValue = substr($nameValue,$equalPos+1);

      // no numeric value are base64 encoded so we need to decode them
      if(!is_numeric($varValue))
      {
        $varValue = base64_decode($varValue);

        // some of the values may be serialized array so we try to...
        if( ($arrayValue = @unserialize($varValue)) !== false
            // we set the unserialized version only for arrays...
            && is_array($arrayValue)
            )
        {
          $varValue = $arrayValue;
        }
      }
      $this->set($varName, $varValue);
    }
  }

  While this allows to unserialize() user input the previously
  demonstrated exploits will not work on Piwik because only parts of
  the Zend Framework are shipped with the Piwik source code. Because
  of this we had to evaluate if Piwik's own classes can be utilized
  in exploits.

  When trying to exploit an unserialize() vulnerability in a PHP
  application the first step is to enumerate the objects that contain
  __wakeup() or __destruct() methods and read their code to analyze if
  these methods are doing something interesting.

  When looking at the Piwik source code one particular class can be
  found that allows writing arbitrary configuration files to the
  webserver. This class is called Piwik_Config and contains the
  following code.

  function __destruct()
  {
    if($this->configFileUpdated === true
        && $this->doWriteFileWhenUpdated === true)
    {
      $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
      $configFile .= "; file automatically generated or modified by "
                     "Piwik; you can manually override the default "
                     "values in global.ini.php by redefining them "
                     "in this file.\n";

      foreach($this->userConfig as $section => $arraySection)
      {
        $arraySection = $arraySection->toArray();
        $configFile .= "[$section]\n";
        foreach($arraySection as $name => $value)
        {
          ...
          $configFile .= $name.' = '.$value."\n";
          ...
        }
        $configFile .= "\n";
      }
      chdir($this->correctCwd);
      file_put_contents($this->pathIniFileUserConfig, $configFile );
    }
  }

  It should be obvious that when unserializing a Piwik_Config object
  it is possible to write arbitrary configurations to arbitrary
  locations by just setting the properties of the object correctly.
  However it should also be obvious that executing arbitrary PHP code
  is not that simple because the authors of Piwik add a show stopper
  to the beginning of every configuration file "; <?php exit; ...".
  Because of this it is not possible to just write PHP code into a
  file and execute it.

  There is however a lesser known and nearly never used feature of PHP5
  that allows exploiting this situation. By using the PHP5 filter
  stream wrapper through the php://filter URI scheme it is possible to
  write arbitrary files to the server. By crafting a configuration
  filename like
  php://filter/write=convert.base64-decode/resource=/var/www/x.php it
  is possible to channel all writes to the file through a base64
  decoder. Because PHP does ignore invalid characters during base64
  decoding it is possible to destroy the show stopper by a single
  base64 decoding. By calculating how many base64 compatible characters
  are contained in the show stopper it is possible to find out how
  many padding bytes are necessary so that base64 injected PHP payload
  ends up correctly decoded in the written configuration file.

  Because the filter wrapper can be stacked several times before data
  is written to the actual file it is possible to construct payloads
  that do not only destroy the show stopper but also get rid of all the
  bytes. In current Piwik versions 5 times base64 decode is required
  for this. In earlier versions of Piwik there have been 3 different
  show stoppers strings. Therefore in order to exploit older Piwik
  versions different exploits are required.

  In order to execute arbitrary code it is possible to overwrite one
  of Piwik cache files and triggering a tracking event. Alternatively
  it is possible to first write a .htaccess file to one of the
  directories within Piwik's tmp directory that allows accessing its
  content and then dropping a PHP file in there.

  In the most recent Piwik version the Zend Framework components were
  upgraded which allows executing arbitrary PHP code directly. To
  achieve this the Zend_Log destructor is utilized.

  public function __destruct()
  {
    foreach($this->_writers as $writer) {
      $writer->shutdown();
    }
  }

  The Zend_Log destructor iterates through an array which it expects
  inside the _writers property. Each element of this array is then
  expected to have a method called shutdown() which is then executed.
  The next step in creating an exploit is to find classes that contain
  a shutdown() method. The best fitting class is Zend_Log_Writer_Mail.
  It is the same class that is also utilized in the generic Zend
  Framework exploit.

  public function shutdown()
  {
    // If there are events to mail, use them as message body.  Otherwise,
    // there is no mail to be sent.
    if (empty($this->_eventsToMail)) {
      return;
    }

    if ($this->_subjectPrependText !== null) {
      // Tack on the summary of entries per-priority to the subject
      // line and set it on the Zend_Mail object.
      $numEntries = $this->_getFormattedNumEntriesPerPriority();
      $this->_mail->setSubject(
      "{$this->_subjectPrependText} ({$numEntries})");
    }

    // Always provide events to mail as plaintext.
    $this->_mail->setBodyText(implode('', $this->_eventsToMail));

    // If a Zend_Layout instance is being used, set its "events"
    // value to the lines formatted for use with the layout.
    if ($this->_layout) {
      // Set the required "messages" value for the layout.  Here we
      // are assuming that the layout is for use with HTML.
      $this->_layout->events = implode('', $this->_layoutEventsToMail);

      // If an exception occurs during rendering, convert it to a notice
      // so we can avoid an exception thrown without a stack frame.
      try {
        $this->_mail->setBodyHtml($this->_layout->render());
      } catch (Exception $e) {
        ...
      }

      // Finally, send the mail.  If an exception occurs, convert ...
      // warning-level message so we can avoid an exception thrown ...
      // stack frame.
      try {
          $this->_mail->send();
      } catch (Exception $e) {
          ...
      }
  }

  This shutdown method will check if there are events not yet mailed
  and if there are, it will mail them to the address specified in the
  Zend_Mail object which has to be within the _mail property. This
  allows anyone to send out arbitrary spam to arbitrary mail addresses.
  However there is a more interesting exploiting path hidden here that
  once again utilizes the HTML rendering. Therefore an attacker has to
  find a class that contains a render method. The most promising class
  in case of Piwik is Piwik_View. Its render method will do a lot of
  things that can be ignored and finally call smarty to render the
  template.

  public function render()
  {
    try {
      ...
    } catch(Exception $e) {
      // can fail, for example at installation (no plugin loaded yet)
    }

    ...

    @header('Content-Type: text/html; charset=utf-8');
    @header("Pragma: ");
    @header("Cache-Control: no-store, must-revalidate");

    return $this->smarty->fetch($this->template);
  }

  Because most of the code in the render method is within a try and
  catch block it can be ignored. The only interesting part of the
  method is the fetch method called on the smarty property. Because
  smarty templates can execute PHP code the smarty class is the first
  one should look at and indeed smarty can be used to execute PHP
  code.

  function fetch($resource_name, $cache_id = null, ...)
  {
    ...
    if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) {
      if ($this->_is_compiled($resource_name, $_smarty_compile_path)
          || $this->_compile_resource($resource_name, $_smarty_compile_path))
      {
        include($_smarty_compile_path);
      }
    } else {
    ...

  The supplied template name is then given to the _compile_resource
  method to compile the resource.

  function _compile_resource($resource_name, $compile_path)
  {

    $_params = array('resource_name' => $resource_name);
    if (!$this->_fetch_resource_info($_params)) {
      return false;
    }
    ...

  Before the resource is being compiled the _fetch_resource_info
  method is called to determine more information about the resource.

  function _fetch_resource_info(&$params)
  {
    ...
    $_params = array('resource_name' => $params['resource_name']) ;
    ...

    if ($this->_parse_resource_name($_params)) {
      $_resource_type = $_params['resource_type'];
      $_resource_name = $_params['resource_name'];
      switch ($_resource_type) {
        case 'file':
          ...
          break;

        default:
          // call resource functions to fetch the template source and timestamp
          if ($params['get_source']) {
            $_source_return = isset($this->_plugins['resource'][$_resource_type]) &&
            call_user_func_array($this->_plugins['resource'][$_resource_type][0][0],
             array($_resource_name, &$params['source_content'], &$this));
          } else {
            $_source_return = true;
          }
          ...
        }

  The _fetch_resource_info method first calls _parse_resource_name to
  determine the type and name of resource. The expected format is
  resource_type:resource_name. For non file resources a function will
  be determined by a lookup in the _plugins[resource] lookup table
  that will be called to retrieve the resource data. Because all
  properties are attacker supplied an exploit can freely choose what
  function should be called.

  Because the called function is called with three parameters and only
  the first one is user supplied it gets a bit tricky to execute
  arbitrary PHP code. Calling eval() is not possible because it is a
  language construct and not a function and calling assert() instead
  will also fail, because it only accepts one parameter. The trick
  here is to use one of the methods inside the smarty class which is
  a wrapper around eval().

  function _eval($code, $params=null)
  {
    return eval($code);
  }

  While this function does only define two parameters in its signature
  it is possible to call this function with more than two parameters.
  The reason for this is that unlike internal functions that usually
  bail out when too many parameters are supplied internal functions
  will not do this because otherwise it would not be possible to have
  functions with an arbitrary number of parameters.

  So to summarize the attack: By carefully crafting a user supplied
  cookie it is possible to utilize Piwik's own objects and execute
  arbitrary PHP code by supplying the argument to an eval() statement.

Proof of Concept:

  SektionEins GmbH is not going to release a proof of concept
  exploit for this vulnerability.

Disclosure Timeline:

  28. November 2009 - Notified hello@piwik.org
  09. December 2009 - Piwik developers released Piwik 0.5.0
  09. December 2009 - Public Disclosure

Recommendation:

  It is recommended to upgrade to the latest version of Piwik.

  Grab your copy at:
  http://piwik.org/latest.zip

CVE Information:

  The Common Vulnerabilities and Exposures project (cve.mitre.org) has
  not assigned a name to this vulnerability.

GPG-Key:

  pub  1024D/15ABDA78 2004-10-17 Stefan Esser
  Key fingerprint = 7806 58C8 CFA8 CE4A 1C2C  57DD 4AE1 795E 15AB DA78

Copyright 2009 SektionEins GmbH. All rights reserved.

SektionEins PHP Security Poster

November 28th, 2009 by Stefan Esser

My company SektionEins that is specialised in web application security audits, consulting and trainings has finished the english translation of the PHP Security Poster. This poster is send out for free to interested PHP programmers (until out of stock). The poster is of DIN A0 size and details the most important aspects of configuring PHP securely and writing secure PHP code.

SektionEins PHP Security Poster

SektionEins PHP Security Poster

The poster contains the following topics:

* Vulnerabilities & Concepts
* Security Related PHP Funktionen
* Secure Programming
* Hardening the PHP Configuration
* Server Protection with Suhosin

The order form for the poster is available here.

RSS09: Web Application Firewall Bypasses and PHP Exploits

November 28th, 2009 by Stefan Esser

At yesterday’s RSS09 conference I gave a slightly different version of my “Shocking News in PHP Exploitation” talk. This time I disclosed for the first time how unserializing user input in Zend Framework based applications can result in direct remote PHP code execution.

The topics of my talk were

  • easy ways to bypass modsecurity and f5 big ip
  • executing PHP code on Zend Framework based applications that unerialize user input
  • how to still exploit PHP interruption vulnerabilities after recent fixes in PHP

You can grab my new slides here.

Shocking News in PHP Exploitation

November 28th, 2009 by Stefan Esser

On 5th of November I gave a talk titled “Shocking News in PHP Exploitation” at the Powerofcommunity hacking/security conference in Seoul, South Korea. Afterwards I uploaded my slides to this server but only distributed the link through twitter. I totally forgot about announcing the slides in my blog.

The topics of my talk were

  • easy ways to bypass modsecurity and f5 big ip asm
  • exploiting unserialize vulnerabilities in Zend Framework applications
  • exploiting PHP interruption vulnerabilities after recent fixes in PHP

The slides are available here.

CGNSec October 2009

October 7th, 2009 by Stefan Esser

I am pleased to announce that Thursday 22th of October 2009 at 19:30 there will be the 10th CGNSec meetup in Cologne/Germany. The meeting takes place at Hallmackenreuther, Brüsseler Platz 9, 50674 Köln (Google Maps).

Everyone working in the field of information security is invited to attend. If you are attending the first time it is best to send me an email beforehand to ensure that you find us. Otherwise search for the table that has the most fun.

Speaking at POC 2009

September 24th, 2009 by Stefan Esser

This year I will return to Power of Community in Seoul and present a session about state of the art exploitation of PHP applications and servers. Unlike my Syscan and Blackhat talk I will also demonstrate how to find unusual code execution vulnerabilities and how to tunnel attacks through web application firewalls.

Session: Shocking News in PHP Exploitation

Remote code execution vulnerabilities in modern PHP applications have become more difficult to find and exploit due to better education of developers and the wide adoption of Suhosin, web application firewalls and other PHP environment hardening. E.g. the class of remote file inclusion vulnerabilities is practically dead in modern PHP installations.

This talk will demonstrate how a well known class of PHP application vulnerabilities that is widely believed to be a DoS vulnerability only, can result in arbitrary PHP code being executed. Furthermore it will be demonstrated how attacks on PHP applications can be tunneled through web application firewalls like mod_security with ease, bypassing the whole rule engine. And last but not least we will take a look at the recently introduced protections against interruption vulnerabilities in PHP and how it is still possible to perform post exploitation tricks as presented at Syscan and Blackhat.

See you in Seoul between 5th and 6th November.

서울에서 11월 5일에서 6일에 만나요!

CGNSec September 2009

September 21st, 2009 by Stefan Esser

I just wanted to announce that this wednesday (23th of September 2009) at 19:30 there will be the next CGNSec meetup in Cologne/Germany. The meeting takes place at Hallmackenreuther, Brüsseler Platz 9, 50674 Köln (Google Maps).

Everyone working in the field of information security is invited to attend. If you are attending the first time it is best to send me an email beforehand to ensure that you find us. Otherwise search for the table that has the most fun.

Suhosin Patch 0.9.8 for PHP 5.3.0 *BETA* - Please Test

August 13th, 2009 by Stefan Esser

It has been several weeks between the release of PHP 5.3.0 and now and I haven’t released a stable Suhosin Patch for PHP 5.3.0 yet. The reason for this was that I was away from my development machine with a half ready new generation of Suhosin Patch waiting to be fixed.

With PHP 5.3.0 the need for a realpath() protection is gone, because PHP 5.3.0 has a far better implementation by default now. Therefore the code for the realpath() protection was completely removed from Suhosin 0.9.8. Another problem people often ran into was that Suhosin’s memory manager canary protection was alerting them of memory corruptions that did no visible harm to PHP installations without the Suhosin Patch. Because of this I decided to add support for environment variables that will be evaluated when PHP starts and allow to configure how Suhosin Patch works. To protect the settings they are stored in a memory page that is set to read-only after it has been initialized.

The following environment variables are supported by now:

  • SUHOSIN_MM_USE_CANARY_PROTECTION
    • default: 1
    • Set to 0 to disable canary protection. A copy of the MM will be used that does not have canaries. This is nearly the same as the MM of vanilla PHP.
  • SUHOSIN_MM_DESTROY_FREE_MEMORY
    • default: 0
    • Set to 1 to enable free memory destruction. Every piece of free memory will be overwritten. This allows debugging e.g. use after free memory corruption bugs easier without using a debug PHP.
  • SUHOSIN_MM_IGNORE_CANARY_VIOLATION
    • default: 0
    • Set to 1 stops Suhosin from aborting the process when it detects canary violations. The violations will be logged and the canary restored. It is strongly recommended to NOT use this feature. But it is more secure to use this feature instead of disabling Suhosin completely which happend in the past when people saw canary violation error messages
  • SUHOSIN_HT_IGNORE_INVALID_DESTRUCTOR
    • default: 0
    • Set to 1 stops Suhosin from aborting the process when it detects an invalid Hashtable destructor. It is strongly recommended to NOT use this feature.
  • SUHOSIN_LL_IGNORE_INVALID_DESTRUCTOR
    • default: 0
    • Set to 1 stops Suhosin from aborting the process when it detects an invalid LinkedList destructor. It is strongly recommended to NOT use this feature.

Because the new features of Suhosin Patch contains new code and some hacks I release the BETA version of the new Suhosin Patch to the public and hope people will test it in different OS/CPU/… and mail me the results to <stefan.esser@sektioneins.de>.

The patch can be downloaded here.

State of the Art Post Exploitation in Hardened PHP Environments

August 12th, 2009 by Stefan Esser

I am finally back in germany after several weeks in foreign countries like singapore, taiwan and the USA. In all three countries I gave a presentation titled “State of the Art Post Exploitation in Hardened PHP Environments” that discusses a certain flaw in the design of the Zend Engine that allows the development of very stable local exploits against PHP. Within the presentation two (no longer) 0 day exploits are discussed and it is demonstrated how they can be used to get arbitrary read and write access to the memory of PHP, which enables a PHP script to break out of some of the common protections you will see on hardened PHP installations. Find below the slides and the whitepaper sent to Blackhat.


  

 

Dutch PHP Conference: The Slides

June 16th, 2009 by Stefan Esser


At this years Dutch PHP Conference I presented a PHP Security Crash Course for beginners and a session about secure programming with the Zend Framework. You can download all the slides from here.

PHP Security Crash Course for beginners

Secure Programming with the Zend Framework

Enjoy the slides and shoot any questions or improvement ideas my way…