Sec Bug->Bug #81711 [Opn]: Private properties data leak by casting object to array

From: Date: Wed, 23 Feb 2022 18:15:33 +0000
Subject: Sec Bug->Bug #81711 [Opn]: Private properties data leak by casting object to array
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-239998@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=81711&edit=1 ID: 81711 Updated by: stas@php.net Reported by: black at scene-si dot org Summary: Private properties data leak by casting object to array Status: Open -Type: Security +Type: Bug Package: Class/Object related Operating System: Linux, web PHP Version: 8.1.3 Block user comment: N Private report: Y New Comment: Visibility is not a security feature. Previous Comments: ------------------------------------------------------------------------ [2022-02-23 11:09:08] black at scene-si dot org Description: ------------ In order to access private variables, one needs to reach the variable either with the scope (an instance of the class and it's descendants, bound variables, etc.), or specific functions like var_dump, reflection, zvar. These things can be disabled with the disable_function options for the paranoid among us, but the document behaviour of (array) casting cannot. [1] I started this with the wish to expand an object with each property corresponding to a named argument. My idea was that ...$obj or ...(array)$obj should work. Apparently, objects are not Traversable [2] Casting an object to (array) exposes private variables, prefixed with the class name. This is actually documented [here](https://www.php.net/manual/en/language.types.array.php#language.types.array.casting) [3] Case 3 is a successful output - ...get_object_vars($obj) behaves exactly as I would like ...$obj or ...(array)$obj to behave. [4] Just demonstrating that $a->b is unreachable from the current scope. I am forced to conclude: - casting objects to arrays with (array) is a data exfiltration vector, which can't be disabled with disable_functions or other php.ini settings, - it's a valid step in a digital hack: after gaining RCE, even with the strictest disable_function settings, it's possible to escalate the hack by reading values which would otherwise be protected by program scope, possibly exposing database connection details and other credentials for private and public services. My recommendation: 1. Support ...$obj for argument unpacking, don't expose private vars, 2. Modify behavior of (array)$obj, don't expose private vars, 3. Provide a std class for objects to implement Traversable over their properties (slightly related to 1. as a way to implement). Test script: --------------- <?php // Repro code: https://www.tehplayground.com/WL0AFQHHybPQI1St class A { public string $a = "hello world"; private string $b = "from hell"; } function PrintGreeting($a = "", $b = "from croatia") { echo "$a $b\n"; } $a = new A; foreach ($a as $k => $v) { echo "k=$k v=$v\n"; } echo "====\n"; var_dump((array)$a); try { PrintGreeting(...$a); } catch (\TypeError $e) { echo "[1] Caught TypeError: " . $e->getMessage() . "\n"; } try { PrintGreeting(...(array)$a); } catch (\Error $e) { echo "[2] Caught Error: " . $e->getMessage() . "\n"; } $a->a = "[3] hello world"; PrintGreeting(...get_object_vars($a)); try { echo $a->b; } catch (\Error $e) { echo "[4] " . $e->getMessage() . "\n"; } Expected result: ---------------- k=a v=hello world ==== array(2) { ["a"]=> string(11) "hello world" } [1] Caught TypeError: Only arrays and Traversables can be unpacked [2] Caught Error: Unknown named parameter $ hello world from croatia [4] Cannot access private property A::$b - (array) cast should be equal to get_object_vars() Actual result: -------------- k=a v=hello world ==== array(2) { ["a"]=> string(11) "hello world" ["Ab"]=> string(9) "from hell" } [1] Caught TypeError: Only arrays and Traversables can be unpacked [2] Caught Error: Unknown named parameter $ [3] hello world from croatia [4] Cannot access private property A::$b ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=81711&edit=1

« previous php.bugs (#239998) next »