php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73900 Use After Free in unserialize() SplFixedArray
Submitted: 2017-01-09 21:42 UTC Modified: 2017-04-04 19:50 UTC
From: rossa dot milan at gmail dot com Assigned: nikic (profile)
Status: Closed Package: SPL related
PHP Version: 7.* OS: ALL
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: rossa dot milan at gmail dot com
New email:
PHP Version: OS:

 

 [2017-01-09 21:42 UTC] rossa dot milan at gmail dot com
Description:
------------
Use After Free in unserialize() with SplFixedArray. It is possible to leak memory and create gadgets to gain full memory read/write access. Demo of memory leak in script bellow.


Test script:
---------------
<?php
for ($i=0; $i<1000; $i++)
$z[$i] = str_repeat('A', 10);

$s = 'O:13:"SplFixedArray":2:{i:0;s:10:"1234567890";i:1;r:2;}';
$o = unserialize($s);
$b = &$o[1];
$o[1] = 0xbaad;

for ($i=0; $i<4000; $i++) {
  echo(bin2hex($o[0][$i]));
}
echo("\n");

Expected result:
----------------
31323334353637383930

Actual result:
--------------
31743d5554462d3800300061790000000100000006000000000000000a00000031323334353637383930006179000000001147b50d0000000614000000000000adba00001ab9ffbf0400000000000000801147b5000000...0000000000000000000000000201f47b500000000000000000000000000000000000000000000000000000000401f47b500000000000000000000000000000000000000000000000000000000601f47b500000000000000000000000000000000000000000000000000000000801f47b500000000000000000000000000000000000000000000000000000000a01f47b500000000000000000000000000000000000000000000000000000000c01f47b500000000000000000000000000000000000000000000000000000000e01f47b50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000006000000000000000a000000414141414141414141410000000000000100000006000000000000000a000000414141414141414141410000000000000100000006000000000000000a000000414141414141414141410000000000000100000006000000000000000a000000414141414141414141410000000000000100000006000000000000000a000000414141414141414141410000000000000100000006000000000000000a000000

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-01-12 12:01 UTC] rossa dot milan at gmail dot com
-PHP Version: 7.1.0 +PHP Version: 7.*
 [2017-01-12 12:01 UTC] rossa dot milan at gmail dot com
Also tested on 7.0.14 with success.
 [2017-01-16 07:54 UTC] stas@php.net
-Assigned To: +Assigned To: nikic
 [2017-01-16 07:54 UTC] stas@php.net
Nikita, could you take a look? Looks like both elements of SplFixedArray point to the same str, but it is freed prematurely instead of being separated when assignment is made. The refcount is correct 2 when leaving unserialize but then is decreased to 1 in ZEND_FETCH_DIM_W_SPEC_CV_CONST_HANDLER.
 [2017-03-30 20:29 UTC] nikic@php.net
The use of unserialize() here is a red herring -- what is actually causing the memory errors is the attempt to acquire a reference into the SplFixedArray. A reduced reproduce script is the following (run under valgrind):

<?php
$a = new stdClass;
$b = new SplFixedArray(1);
$b[0] = $a;
$c = &$b[0];

As such, I do not believe this qualifies as a security issue under https://wiki.php.net/security: The issue cannot be triggered through user input. Instead, what triggers the issue is specific and atypical local code, namely the "$c = &$b[0]" line (it is atypical because ArrayAccess objects do not support references).

I believe the cause of this issue is the code at https://github.com/php/php-src/blob/f07e4c033cf4edda8dcbf14c5a964e4d283fa8a8/Zend/zend_execute.c#L1637, which seems to assume that result is already in retval (which happens to be the case for non-internal implementations of offsetGet()).
 [2017-03-30 20:42 UTC] nikic@php.net
Here is a patch against master which fixes the issue: https://gist.github.com/nikic/79b9b55d325373d4b39903a82027064e
 [2017-03-31 23:57 UTC] stas@php.net
If it's not related to unserialize I assume it's not a security issue?
 [2017-04-02 11:56 UTC] zeev@php.net
Stas - the reverse is actually true :)
(if it's related to unserialize, then it's not a security issue!)
 [2017-04-03 21:11 UTC] stas@php.net
Well, in both cases it requires specially crafted code, so unless I hear objections soon I will reclassify it.
 [2017-04-04 19:50 UTC] stas@php.net
-Type: Security +Type: Bug
 [2017-06-25 17:49 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=2fddc4a7f1588239939a509781706c084939e09f
Log: Fixed bug #73900
 [2017-06-25 17:49 UTC] nikic@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 12:01:29 2024 UTC