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 buffer. 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.
Advisory: PHP openssl_x509_parse() Memory Corruption Vulnerability
Release Date: 2013/12/13
Last Modified: 2013/12/13
Author: Stefan Esser [stefan.esser[at]sektioneins.de]
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
Reference:
http://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html
Overview:
Quote from http://www.php.net
"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
buffer.
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.
Details:
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
function:
* output certificate debugging information
(e.g. cacert.org/analyse.php)
* 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,
ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
*/
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
buffer.
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.
# 0day.today [2018-02-06] #