php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76145 Data corruption reading from APCu while unserializing
Submitted: 2018-03-24 20:37 UTC Modified: 2018-04-08 14:38 UTC
From: d dot takken at xs4all dot nl Assigned: nikic (profile)
Status: Closed Package: APC (PECL)
PHP Version: 7.2.3 OS: Linux
Private report: No CVE-ID: None
 [2018-03-24 20:37 UTC] d dot takken at xs4all dot nl
Description:
------------
Under very specific conditions storing and subsequently fetching an array or object in APCu can result in values moving to different locations in the data structure. Provided test script demonstrates APCu mixing up booleans resulting in a user's status changing from non-authenticated to authenticated. The test script is entirely fictitious and is intended to illustrate how the bug may result in a vulnerability.

The specific conditions that trigger the problem require reading APCu data from inside the PHP unserialize() function. Also, the array or object stored in APCu must contain references among elements in the array or object.

In my case, APCu reads triggered by a unserialize() call are extremely rare. In most cases, the data is read from APCu before the unserialize() call and does not need to be read during the unserialize() call. This resulted in equally rare errors. In theory, similar scenarios may exist in applications which store security related data in APCu. This may result in a latent vulnerability that is very difficult to identify.

I tested the supplied script on APCu 5.1.10 and 5.1.11.

When switching the serializer from the native PHP serializer to the igbinary serializer version 2.0.5 the problem disappears. This may suggest that recursive calls to the native PHP serializer triggers a bug related to references. However, replacing APCu with memcached also makes the problem disappear. Memcached also uses the native PHP serializer, so something APCu specific may be involved here as well.

Test script:
---------------
<?php

class Session implements \Serializable
{
  public $session;
  public function unserialize($serialized) { $this -> session = apcu_fetch('session'); }
  public function serialize() { return ''; }
}

// Create array representing a session associated with a user
// account that is enabled but has not been authenticated.
$session = ['user' => ['enabled' => True], 'authenticated' => False];
$session['user']['authenticated'] = &$session['authenticated'];

apcu_store('session', $session);

// After serializing / deserializing, session checks out as authenticated.
print unserialize(serialize(new Session())) -> session['authenticated'] === True ? 'Authenticated.' : 'Not Authenticated.';

Expected result:
----------------
Script prints "Not Authenticated."

Actual result:
--------------
Script prints "Authenticated."

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-03-28 04:05 UTC] stas@php.net
-Assigned To: +Assigned To: krakjoe
 [2018-03-28 04:07 UTC] stas@php.net
-Status: Assigned +Status: Feedback -Type: Security +Type: Bug
 [2018-03-28 04:07 UTC] stas@php.net
Doesn't look like a security issue, looks like a regular bug.
 [2018-03-28 04:08 UTC] stas@php.net
-Status: Feedback +Status: Assigned
 [2018-04-07 18:43 UTC] d dot takken at xs4all dot nl
I initially reported this one as a security issue, just to be sure. Whether it is treated as one is up to you guys. :)
 [2018-04-08 14:38 UTC] nikic@php.net
-Status: Assigned +Status: Closed -Assigned To: krakjoe +Assigned To: nikic
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Thu Apr 15 11:01:24 2021 UTC