Edit report at https://bugs.php.net/bug.php?id=72823&edit=1
ID: 72823
Updated by: cmb@php.net
Reported by: fernando at null-life dot com
Summary: strtr out-of-bound access
-Status: Open
+Status: Analyzed
Type: Bug
Package: Strings related
Operating System: *
PHP Version: 5.6.24
-Assigned To:
+Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
I can confirm this issue.
> p/d pos + d->m - d->B ==> -3
This happens in php_strtr_array_prepare()[1], because patnum is 0
in this case. Unfortunately, the assert doesn't catch this case.
Anyhow, the solution is to not call php_strtr_array_prepare()[2],
if patterns_len is 0, but to return the given str instead.
[1] <https://github.com/php/php-src/blob/PHP-5.6/ext/standard/string.c#L2986-L2992>
[2] <https://github.com/php/php-src/blob/PHP-5.6/ext/standard/string.c#L3134>
Previous Comments:
------------------------------------------------------------------------
[2016-08-12 18:45:36] fernando at null-life dot com
Description:
------------
php_strtr_hash will read out if bounds if the pattern length is bigger than the frist argument to
strtr, this can be seen easier when the first argument is casted to string instead of passed as a
regular string.
-----------------------------------------
Source code
https://github.com/php/php-src/blob/PHP-5.6.24/ext/standard/string.c#L2853
static inline HASH php_strtr_hash(const char *str, int len)
{
HASH res = 0;
int i;
for (i = 0; i < len; i++) {
res = res * 33 + (unsigned char)str[i]; // str[i] read out of bounds
}
return res;
}
GDB Output
-----------
USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 gdb -q --args /home/operac/build2-sinafl/bin/php -n
poc.php
Reading symbols from /home/operac/build2-sinafl/bin/php...done.
gdb-peda$ b string.c:3068
Breakpoint 2 at 0xcdf293: file /home/operac/build2-sinafl/php-src-56/ext/standard/string.c, line
3068.
gdb-peda$ r
...
Breakpoint 2, php_strtr_array_do_repl (text=0x7fffffffa210, d=0x606000001100,
return_value=0x60300004cd50) at /home/operac/build2-sinafl/php-src-56/ext/standard/string.c:3068
3068 HASH h = php_strtr_hash(&S(text)[pos + d->m -
d->B], d->B) & d->shift->table_mask;
gdb-peda$ p *text
$6 = {
s = 0x607000089af0 "11",
l = 0x2
}
gdb-peda$ p/d pos + d->m - d->B
$7 = -3 // text underflow
gdb-peda$ b string.c:2855
Breakpoint 3 at 0xcdd3ce: file /home/operac/build2-sinafl/php-src-56/ext/standard/string.c, line
2855.
gdb-peda$ c
Continuing.
...
Breakpoint 3, php_strtr_hash (str=0x607000089aed "", len=0x2) at
/home/operac/build2-sinafl/php-src-56/ext/standard/string.c:2855
2855 res = res * 33 + (unsigned char)str[i];
gdb-peda$ p str
$9 = 0x607000089aed ""
gdb-peda$ p str+3
$10 = 0x607000089af0 "11"
...
Test script:
---------------
<?php
$d = array("aaa" => "bbb");
strtr(11, $d);
Expected result:
----------------
No crash
Actual result:
--------------
ASan output:
USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 /home/operac/build2/bin/php -n poc.php
=================================================================
==30419==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000089b5d at pc
0x00000147f3e1 bp 0x7ffe4de13900 sp 0x7ffe4de138f0
READ of size 1 at 0x607000089b5d thread T0
#0 0x147f3e0 in php_strtr_hash /home/operac/build2/php-src-56/ext/standard/string.c:2855
#1 0x147f3e0 in php_strtr_array_do_repl
/home/operac/build2/php-src-56/ext/standard/string.c:3068
#2 0x147f3e0 in php_strtr_array /home/operac/build2/php-src-56/ext/standard/string.c:3136
#3 0x147f3e0 in zif_strtr /home/operac/build2/php-src-56/ext/standard/string.c:3167
#4 0x1d5c3e3 in zend_do_fcall_common_helper_SPEC
/home/operac/build2/php-src-56/Zend/zend_vm_execute.h:558
#5 0x1c0568c in execute_ex /home/operac/build2/php-src-56/Zend/zend_vm_execute.h:363
#6 0x194d3d2 in zend_execute_scripts /home/operac/build2/php-src-56/Zend/zend.c:1341
#7 0x169b32f in php_execute_script /home/operac/build2/php-src-56/main/main.c:2613
#8 0x1d653b6 in do_cli /home/operac/build2/php-src-56/sapi/cli/php_cli.c:994
#9 0x4550a0 in main /home/operac/build2/php-src-56/sapi/cli/php_cli.c:1378
#10 0x7fbefc95f82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#11 0x4556b8 in _start (/home/operac/build2/bin/php+0x4556b8)
0x607000089b5d is located 3 bytes to the left of 79-byte region [0x607000089b60,0x607000089baf)
allocated by thread T0 here:
#0 0x7fbefef29961 in realloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98961)
#1 0x16afa27 in xbuf_format_converter /home/operac/build2/php-src-56/main/spprintf.c:794
#2 0x16b7361 in vspprintf /home/operac/build2/php-src-56/main/spprintf.c:821
#3 0x1a0d2e9 in zend_spprintf /home/operac/build2/php-src-56/Zend/zend_exceptions.c:663
#4 0x18faf81 in _convert_to_string /home/operac/build2/php-src-56/Zend/zend_operators.c:625
#5 0x1980f2f in zend_parse_arg_impl /home/operac/build2/php-src-56/Zend/zend_API.c:442
#6 0x198881d in zend_parse_arg /home/operac/build2/php-src-56/Zend/zend_API.c:691
#7 0x198b035 in zend_parse_va_args /home/operac/build2/php-src-56/Zend/zend_API.c:873
#8 0x198b035 in zend_parse_parameters /home/operac/build2/php-src-56/Zend/zend_API.c:924
#9 0x1479b66 in zif_strtr /home/operac/build2/php-src-56/ext/standard/string.c:3152
#10 0x1d5c3e3 in zend_do_fcall_common_helper_SPEC
/home/operac/build2/php-src-56/Zend/zend_vm_execute.h:558
#11 0x1c0568c in execute_ex /home/operac/build2/php-src-56/Zend/zend_vm_execute.h:363
#12 0x194d3d2 in zend_execute_scripts /home/operac/build2/php-src-56/Zend/zend.c:1341
#13 0x169b32f in php_execute_script /home/operac/build2/php-src-56/main/main.c:2613
#14 0x1d653b6 in do_cli /home/operac/build2/php-src-56/sapi/cli/php_cli.c:994
#15 0x4550a0 in main /home/operac/build2/php-src-56/sapi/cli/php_cli.c:1378
#16 0x7fbefc95f82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
SUMMARY: AddressSanitizer: heap-buffer-overflow
/home/operac/build2/php-src-56/ext/standard/string.c:2855 php_strtr_hash
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=72823&edit=1