Advisory 01/2013: PHP openssl_x509_parse() Memory Corruption Vulnerability

Veröffentlicht:   |  Weitere Einträge über Advisories
                         SektionEins GmbH

                     -= Security  Advisory =-

     Advisory: PHP openssl_x509_parse() Memory Corruption Vulnerability
 Release Date: 2013/12/13
Last Modified: 2013/12/16
       Author: Stefan Esser [stefan.esser[at]]

  Application: PHP 4.0.6 - PHP 4.4.9
               PHP 5.0.x
               PHP 5.1.x
               PHP 5.2.x
               PHP 5.3.0 - PHP 5.3.27
               PHP 5.4.0 - PHP 5.4.22
               PHP 5.5.0 - PHP 5.5.6
     Severity: PHP applications using openssl_x509_parse() to parse a
               malicious x509 certificate might trigger a memory
               corruption that might result in arbitrary code execution
         Risk: Critical
Vendor Status: Vendor has released PHP 5.5.7, PHP 5.4.23 and PHP 5.3.28
               that contain a fix for this vulnerability


  Quote from
  "PHP is a widely-used general-purpose scripting language that
   is especially suited for Web development and can be embedded
   into HTML."

  The PHP function openssl_x509_parse() uses a helper function
  called asn1_time_to_time_t() to convert timestamps from ASN1
  string format into integer timestamp values. The parser within
  this helper function is not binary safe and can therefore be
  tricked to write up to five NUL bytes outside of an allocated

  This problem can be triggered by x509 certificates that contain
  NUL bytes in their notBefore and notAfter timestamp fields and
  leads to a memory corruption that might result in arbitrary
  code execution.

  Depending on how openssl_x509_parse() is used within a PHP
  application the attack requires either a malicious cert signed
  by a compromised/malicious CA or can be carried out with a
  self-signed cert.


  The PHP function openssl_x509_parse() is used by PHP applications
  to parse additional information out of x509 certificates, usually
  to harden SSL encrypted communication channels against MITM
  attacks. In the wild we have seen the following use cases for this

   * output certificate debugging information
   * webmail application with SMIME support
   * client certificate handling
   * certificate pinning
   * verification of other certificate properties
     (e.g. a default Wordpress install if ext/curl is not loaded)

  When we backported security fixes for some previous security
  vulnerabilities in PHP's openssl to PHP 4.4.9 as part of our
  PHP security backport services that we provide to customers,
  we performed a quick audit of openssl_x509_parse() and all the
  functions it calls, which led to the discovery of a memory
  corruption vulnerability.

  Within the function openssl_x509_parse() the helper function
  asn1_time_to_time_t() is called two times to parse the
  notBefore and notAfter ASN1 string timestamps from the cert
  into integer time_t values as you can see below:

     add_assoc_long(return_value, "validFrom_time_t", asn1_time_to_time_t(X509_get_notBefore(cert) TSRMLS_CC));
     add_assoc_long(return_value, "validTo_time_t", asn1_time_to_time_t(X509_get_notAfter(cert) TSRMLS_CC));

  When you take a look into this helper function you will see
  that it only contains a quickly hacked parser that was never
  really improved since its introduction in PHP 4.0.6. The author
  of this parser was even aware of its hackishness as you can see
  from the error message contained in the code:

  static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
     This is how the time string is formatted:
     snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,

     time_t ret;
     struct tm thetime;
     char * strbuf;
     char * thestr;
     long gmadjust = 0;

     if (timestr->length < 13) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "extension author too lazy to parse %s correctly", timestr->data);
        return (time_t)-1;

 However the actual problem of the code should become obvious when
 you read the rest of the parsing code that attempts to first
 duplicate the timestamp string and then parses the timestamp by
 going through the copy in reverse order and writing five NUL bytes
 into the duplicated string.

     strbuf = estrdup((char *)timestr->data);

     memset(&thetime, 0, sizeof(thetime));

     /* we work backwards so that we can use atoi more easily */

     thestr = strbuf + timestr->length - 3;

     thetime.tm_sec = atoi(thestr);
     *thestr = '\0';
     thestr -= 2;
     thetime.tm_min = atoi(thestr);
     *thestr = '\0';
     thestr -= 2;
     thetime.tm_hour = atoi(thestr);
     *thestr = '\0';
     thestr -= 2;
     thetime.tm_mday = atoi(thestr);
     *thestr = '\0';
     thestr -= 2;
     thetime.tm_mon = atoi(thestr)-1;
     *thestr = '\0';
     thestr -= 2;
     thetime.tm_year = atoi(thestr);

  The problem with this code is that ASN1 strings can contain NUL
  bytes, while the parser is not binary safe. This means if a
  timestamp string inside a x509 certificate contains a NUL byte
  at e.g. position 13 the estrdup() will only allocate 14 bytes
  for a copy of the string, but the parser will attempt to write
  five NUL bytes to memory addressed by the ASN1 length of the
  string. If the real string length is longer than 16 bytes this
  will result in writes of NUL bytes outside of the allocated

  Because of PHP's deterministic heap memory layout that can be
  controlled a lot by sending e.g. POST variables and using
  duplicate variable names to poke memory holes this vulnerability
  must be considered exploitable. However the actual exploit will
  depend a lot on how the PHP application uses openssl_x509_parse()
  and a lot of other factors.

  Depending on which of the actual use cases the function is used
  for by an application, an attacker can trigger the memory
  corruption with a self-signed certificate. An example for this
  is the public analyse.php x509 cert debugging script provided
  by CACert on their webserver.

  Other applications like Wordpress use openssl_x509_parse() to
  further verify SSL certificates whenever Wordpress connects to
  a HTTPS URL (in case ext/curl is not loaded which is the default
  for several linux distributions). Because the parsing only
  happens after the initial SSL connection is established this
  can only be abused by attackers controlling a malicious trusted
  cert. However recent disclosures of alleged NSA capabilities,
  the French incident and disclosures about fully compromised
  trusted CAs in the past years have shown that this capability
  might be in the reach of malicious attackers.

Proof of Concept:

  The following x509 certificate demonstrates the out of bounds write:


Disclosure Timeline:

  01. December 2013 - Notified
                      Provided description, POC cert, demo
                      valgrind output and patch
  02. December 2013 - acknowledges and
                      says thank you for report and patch
  02. December 2013 - announces that planned
                      release date is 12th December
  03. December 2013 - Notification from RedHat Security that
                      CVE-2013-6420 was assigned to this issue
  09. December 2013 - RedHat Security tells that they
                      should commit the fix silently and add
                      info about it only after release
                      They further tell to tell us to
                      not discuss the vulnerability in public
                      prior to patches being available
  10. December 2013 - fixes the vulnerability
                      openly and does not attempt to hide that
                      the commit is a security fix as RedHat
                      Security suggested
  11. December 2013 - RedHat Security Announces that they now
                      consider this vulnerability public and
                      sends out their own patches with big
                      announcement one day before is
                      ready to release their own fixes
  12. December 2013 - pushes PHP updates to
                      the PHP 5.3, PHP 5.4 and PHP 5.5 branches
                      to the mirros as was previously agreed upon
  13. December 2013 - New PHP releases are announce on
  13. December 2013 - Public Disclosure of this advisory


  It is recommended to upgrade to the latest version of PHP
  which also fixes additional non security problems reported
  by third parties.

  Grab your copy at:

CVE Information:

  The Common Vulnerabilities and Exposures project ( has
  assigned the name CVE-2013-6420 to this vulnerability.


  pub   4096R/D6A3FE46 2013-11-06 Stefan Esser
  Key fingerprint = 0A04 AB88 90D2 E67C 3D3D  86E1 AA39 B97F D6A3 FE46

Copyright 2013 SektionEins GmbH. All rights reserved.