Thinkphp 6 任意文件写入漏洞

Posted by kuron3k0 on December 5, 2020

环境搭建

直接用composer安装

D:\tools\xampp\htdocs\thinkphp>php composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
D:\tools\xampp\htdocs\thinkphp>php composer create-project topthink/think think6

下下来是最新的6.0.5版本,在comoposer.json改成有漏洞的版本然后update

D:\tools\xampp\htdocs\thinkphp\think6>php ../composer update

打开session

修改一下控制器

漏洞利用

其实就是session名没有校验,直接拼接到文件名中导致的跨目录写文件

漏洞分析

配vscode+xdebug调试环境整了好久,最后用了这个配置才行(本地调试)

在index.php的最后下断点

调用中间件的end函数

SessionInit中间件调用session的save函数

但是session其实没有save函数,触发__call魔术方法,调用驱动的save函数

一直追溯到Store类

Store->save中调用了write,sessionId通过getId获取,data是类属性

跟进write看看是怎么做的,调用了getFilename,然后writeFile写文件

很明显就是这里实现了路径穿越,还帮忙建目录了

很直接的调用了file_put_contents

然后再来看看路径(sessionId)和数据(data)是怎么传进来的,首先setId方法会对$this->id赋值,注意sessionId需要长度为32,不然会被md5处理

这次从index.php的开头下断点,进入到runWithRequest,这里调用中间件的pipeline,类似servlet的filter一样,链式调用每个中间件的handle函数

SessionInit的handle函数中,从cookie里取出了我们的PHPSESSID值,调用了上面的Store类中的setId方法

然后data就是在控制器中调用session("demo",$_GET['c']);的时候,进入Store类的set方法,即$this->data[$name] = $value;

Arr::set的第一个参数,传的是实参

参考

https://xz.aliyun.com/t/8546