php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74590 Heap corruption in mb_ereg_replace()
Submitted: 2017-05-14 07:44 UTC Modified: 2020-03-05 09:15 UTC
From: l dot wei at ntu dot edu dot sg Assigned: cmb (profile)
Status: Closed Package: mbstring related
PHP Version: 7.1.5 OS: *
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: l dot wei at ntu dot edu dot sg
New email:
PHP Version: OS:

 

 [2017-05-14 07:44 UTC] l dot wei at ntu dot edu dot sg
Description:
------------
The multi-byte regex engine oniguruma, when handling malformed regular expressions, would write out-of-bound, usually leading to a heap corruption. When the regex is from network, this potentially would lead to a remote RCE.

Tested on both 5.6.30 and 7.1.5, on 32-bit and 64-bit builds in Ubuntu Linux.

The following are shown on bin/php 64-bit build with -fsanitize=address, --enable-mbstring

Some of the repros are attached.

Test script:
---------------
$ cat regex.php 

<?php

$argc = $_SERVER['argc'];
$argv = $_SERVER['argv'];
$dir_str = dirname(__FILE__);
$file_str = ($dir_str)."/".$argv[1];
echo "Input file: ".$file_str."\n";
if (!extension_loaded('mbstring')) print "mbstring not loaded.\n";
if (!function_exists('mb_ereg_replace')) print "mb_ereg_replace() is not available\n";
$mb_str = file_get_contents($file_str);
print strlen($mb_str) . " bytes read.\n";

echo "*** Testing mb_ereg_replace() ***\n";
echo mb_ereg_replace($mb_str, "\\1", "a\\2bxc");

?>

Expected result:
----------------
No crash.

Actual result:
--------------
A minimal repro that gives a SEGV in next_state_val() by corrupting 1-bit with a large index, on Ubuntu x86_64:

regparse.c:4087	      BITSET_SET_BIT(cc->bs, (int )(*vs));

$ xxd -g 1 fs5_id29_min 
00000000: 30 5b 0b 2d 30 2d 2d 30 2d 2d 30 2d fb fb fb 30  0[.-0--0--0-...0

$ bin/php regex.php fs5_id29_min 
Input file: /home/xie/php_fuzz/fs5_id29_min
16 bytes read.
*** Testing mb_ereg_replace() ***
ASAN:SIGSEGV
=================================================================
==15778==ERROR: AddressSanitizer: SEGV on unknown address 0x606000028504 (pc 0x00000084562a bp 0x7ffdb84cffb0 sp 0x7ffdb84cfe80 T0)
    #0 0x845629 in next_state_val /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4087
    #1 0x84b97f in parse_char_class /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4304
    #2 0x85511b in parse_exp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5270
    #3 0x8589a5 in parse_branch /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5445
    #4 0x858c2d in parse_subexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5472
    #5 0x8593ef in parse_regexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5516
    #6 0x8593ef in onig_parse_make_tree /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5543
    #7 0x82de6e in onig_compile /home/xie/php-7.1.5/ext/mbstring/oniguruma/regcomp.c:5300
    #8 0x82f8e5 in onig_new /home/xie/php-7.1.5/ext/mbstring/oniguruma/regcomp.c:5545
    #9 0x8c50a0 in php_mbregex_compile_pattern /home/xie/php-7.1.5/ext/mbstring/php_mbregex.c:456
    #10 0x8c637b in _php_mb_regex_ereg_replace_exec /home/xie/php-7.1.5/ext/mbstring/php_mbregex.c:901
    #11 0xda5c21 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/xie/php-7.1.5/Zend/zend_vm_execute.h:675
    #12 0xd5f93d in execute_ex /home/xie/php-7.1.5/Zend/zend_vm_execute.h:429
    #13 0xec5c91 in zend_execute /home/xie/php-7.1.5/Zend/zend_vm_execute.h:474
    #14 0xc7dd12 in zend_execute_scripts /home/xie/php-7.1.5/Zend/zend.c:1476
    #15 0xb8044f in php_execute_script /home/xie/php-7.1.5/main/main.c:2537
    #16 0xeca7d0 in do_cli /home/xie/php-7.1.5/sapi/cli/php_cli.c:993
    #17 0x43ef86 in main /home/xie/php-7.1.5/sapi/cli/php_cli.c:1381
    #18 0x7f7a9755082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #19 0x43f228 in _start (/home/xie/php7_asan/bin/php+0x43f228)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4087 next_state_val
==15778==ABORTING

A few other variations:

$ xxd -g 1 fs6_id33_min 
00000000: 5b 30 2d fc 30 30 30 30 30 2d c4 30              [0-.00000-.0

$ bin/php regex.php fs6_id33_min 
Input file: /home/xie/php_fuzz/fs6_id33_min
12 bytes read.
*** Testing mb_ereg_replace() ***
ASAN:SIGSEGV
=================================================================
==15781==ERROR: AddressSanitizer: SEGV on unknown address 0x2c047fff97a2 (pc 0x0000008446e0 bp 0x00000130e0e4 sp 0x7ffe308b8920 T0)
    #0 0x8446df in bbuf_free /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:104
    #1 0x84ae9a in onig_node_free /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:1048
    #2 0x84b3bf in parse_char_class /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4497
    #3 0x85511b in parse_exp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5270
    #4 0x85890d in parse_branch /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5435
    #5 0x858c2d in parse_subexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5472
    #6 0x8593ef in parse_regexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5516
    #7 0x8593ef in onig_parse_make_tree /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5543
    #8 0x82de6e in onig_compile /home/xie/php-7.1.5/ext/mbstring/oniguruma/regcomp.c:5300
    #9 0x82f8e5 in onig_new /home/xie/php-7.1.5/ext/mbstring/oniguruma/regcomp.c:5545
    #10 0x8c50a0 in php_mbregex_compile_pattern /home/xie/php-7.1.5/ext/mbstring/php_mbregex.c:456
    #11 0x8c637b in _php_mb_regex_ereg_replace_exec /home/xie/php-7.1.5/ext/mbstring/php_mbregex.c:901
    #12 0xda5c21 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/xie/php-7.1.5/Zend/zend_vm_execute.h:675
    #13 0xd5f93d in execute_ex /home/xie/php-7.1.5/Zend/zend_vm_execute.h:429
    #14 0xec5c91 in zend_execute /home/xie/php-7.1.5/Zend/zend_vm_execute.h:474
    #15 0xc7dd12 in zend_execute_scripts /home/xie/php-7.1.5/Zend/zend.c:1476
    #16 0xb8044f in php_execute_script /home/xie/php-7.1.5/main/main.c:2537
    #17 0xeca7d0 in do_cli /home/xie/php-7.1.5/sapi/cli/php_cli.c:993
    #18 0x43ef86 in main /home/xie/php-7.1.5/sapi/cli/php_cli.c:1381
    #19 0x7fcfe9c5582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #20 0x43f228 in _start (/home/xie/php7_asan/bin/php+0x43f228)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:104 bbuf_free
==15781==ABORTING

Other variations (repros can be uploaded on request).

$ bin/php regex.php fs5_id29
Input file: /home/xie/php_fuzz/fs5_id29
1245 bytes read.
*** Testing mb_ereg_replace() ***
=================================================================
==15901==ERROR: AddressSanitizer: heap-use-after-free on address 0x60600000bc30 at pc 0x00000084533a bp 0x7fff88fbfef0 sp 0x7fff88fbfee0
READ of size 8 at 0x60600000bc30 thread T0
    #0 0x845339 in add_code_range_to_buf /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:1716
    #1 0x84566d in add_code_range /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:1781
    #2 0x84566d in next_state_val /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4089
    #3 0x84b97f in parse_char_class /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4304
    #4 0x84b480 in parse_char_class /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4402
    #5 0x84b480 in parse_char_class /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4402
    #6 0x85511b in parse_exp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5270
    #7 0x85890d in parse_branch /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5435
    #8 0x858c2d in parse_subexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5472
    #9 0x855f90 in parse_enclose /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:4730
    #10 0x855f90 in parse_exp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5057
    #11 0x85890d in parse_branch /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5435
    #12 0x858c2d in parse_subexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5472
    #13 0x8593ef in parse_regexp /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5516
    #14 0x8593ef in onig_parse_make_tree /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:5543
    #15 0x82de6e in onig_compile /home/xie/php-7.1.5/ext/mbstring/oniguruma/regcomp.c:5300
    #16 0x82f8e5 in onig_new /home/xie/php-7.1.5/ext/mbstring/oniguruma/regcomp.c:5545
    #17 0x8c50a0 in php_mbregex_compile_pattern /home/xie/php-7.1.5/ext/mbstring/php_mbregex.c:456
    #18 0x8c637b in _php_mb_regex_ereg_replace_exec /home/xie/php-7.1.5/ext/mbstring/php_mbregex.c:901
    #19 0xda5c21 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/xie/php-7.1.5/Zend/zend_vm_execute.h:675
    #20 0xd5f93d in execute_ex /home/xie/php-7.1.5/Zend/zend_vm_execute.h:429
    #21 0xec5c91 in zend_execute /home/xie/php-7.1.5/Zend/zend_vm_execute.h:474
    #22 0xc7dd12 in zend_execute_scripts /home/xie/php-7.1.5/Zend/zend.c:1476
    #23 0xb8044f in php_execute_script /home/xie/php-7.1.5/main/main.c:2537
    #24 0xeca7d0 in do_cli /home/xie/php-7.1.5/sapi/cli/php_cli.c:993
    #25 0x43ef86 in main /home/xie/php-7.1.5/sapi/cli/php_cli.c:1381
    #26 0x7ff18d2a682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #27 0x43f228 in _start (/home/xie/php7_asan/bin/php+0x43f228)

0x60600000bc30 is located 48 bytes inside of 56-byte region [0x60600000bc00,0x60600000bc38)
freed by thread T0 here:
    #0 0x7ff18e1ca2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
    #1 0xcfd166 in zend_string_release /home/xie/php-7.1.5/Zend/zend_string.h:272
    #2 0xcfd166 in zend_new_interned_string_int /home/xie/php-7.1.5/Zend/zend_string.c:148

previously allocated by thread T0 here:
    #0 0x7ff18e1ca602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0xc05d88 in __zend_malloc /home/xie/php-7.1.5/Zend/zend_alloc.c:2820
    #2 0x1a3b9df  (/home/xie/php7_asan/bin/php+0x1a3b9df)

SUMMARY: AddressSanitizer: heap-use-after-free /home/xie/php-7.1.5/ext/mbstring/oniguruma/regparse.c:1716 add_code_range_to_buf
Shadow bytes around the buggy address:
  0x0c0c7fff9730: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fa
  0x0c0c7fff9740: fa fa fa fa 00 00 00 00 00 00 00 fa fa fa fa fa
  0x0c0c7fff9750: fd fd fd fd fd fd fd fa fa fa fa fa 00 00 00 00
  0x0c0c7fff9760: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fa
  0x0c0c7fff9770: fa fa fa fa 00 00 00 00 00 00 00 fa fa fa fa fa
=>0x0c0c7fff9780: fd fd fd fd fd fd[fd]fa fa fa fa fa 00 00 00 00
  0x0c0c7fff9790: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fa
  0x0c0c7fff97a0: fa fa fa fa 00 00 00 00 00 00 00 fa fa fa fa fa
  0x0c0c7fff97b0: fd fd fd fd fd fd fd fa fa fa fa fa 00 00 00 00
  0x0c0c7fff97c0: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fa
  0x0c0c7fff97d0: fa fa fa fa 00 00 00 00 00 00 00 fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==15901==ABORTING





Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-05-18 02:50 UTC] l dot wei at ntu dot edu dot sg
There are two issues in this report, which seems already fixed in the Oniguruma library, but not in the PHP stable releases:

1) Incorrect handling of single byte char goto in parse_char_class() leads to heap corruption. Addressed upstream by "fix invalid goto in parse_char_class() #21": 

https://github.com/kkos/oniguruma/commit/1ca27efa21d3a87993af1ee80bbad7500a51b2e7

2) Incorrect handling of return value from code_to_mbclen() leads to heap corruption. 3-byte short sequences like "\x5b\xfe\x30" or "\x5b\xff\x30" can both trigger the issue. The code_to_mbclen() function in ext/mbstring/oniguruma/enc/utf8.c returns 1 for '\xfe' and '\xff' as invalid code, while the return value is misinterpreted and single byte followed by sign extension, resulting in "\xfe\xff\xff\xff" on 32-bit or "\xfe\xff\xff\xff\xff\xff\xff\xff" on 64-bit. The 32-bit case results in heap corruption. Seems addressed upstream by "disable USE_INVALID_CODE_SCHEME for fix #18": 

https://github.com/kkos/oniguruma/commit/44ed4a8364eecdc220316a90013d2a25afea6b80

Please consider updating to the latest Oniguruma.
 [2017-06-20 06:21 UTC] stas@php.net
-Type: Security +Type: Bug -Assigned To: +Assigned To: hirokawa
 [2017-06-20 06:21 UTC] stas@php.net
Not a security issue, and no reason to keep it private since the patches are in public.
 [2017-10-24 07:00 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: hirokawa +Assigned To:
 [2020-03-05 09:15 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2020-03-05 09:15 UTC] cmb@php.net
Both commits are contained in Oniguruma 6.1.0, and PHP-7.2 (the
lowest supported release branch) has Oniguruma 6.1.2, so this
ticket can be closed.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 14 16:01:26 2024 UTC