作者:1ight@星盟
首先通过composer安装thinkphp6框架
Mac OS
curl -sS getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
国内镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
安装ThinkPHP
composer create-project topthink/think think6
安装以后默认是最新版本,编辑根目录下的composer.json
然后执行composer update
成功降级
ThinkPHP6默认不开启session,我们需要修改app\middleware.php文件
<?php // 全局中间件定义文件 return [ // 全局请求缓存 // \think\middleware\CheckRequestCache::class, // 多语言加载 // \think\middleware\LoadLangPack::class, // Session初始化 \think\middleware\SessionInit::class ];
最后执行php think run
即可
影响版本:ThinkPHP6.0.0-6.0.1
利用方式:网站使用到了session
测试环境:PHP7.4.1
macOS Catalina
首先修改_app_controller/index.php
<?php namespace app\controller; use app\BaseController; class Index extends BaseController { public function index() { $a = isset($_GET['a']) && !empty($_GET['a']) ? $_GET['a'] : ''; $b = isset($_GET['b']) && !empty($_GET['b']) ? $_GET['b'] : ''; session($a,$b); return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V6<br/><span style="font-size:30px">13载初心不改 - 你值得信赖的PHP框架</span></p></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="eab4b9f840753f8e7"></think>'; } public function hello($name = 'ThinkPHP6') { return 'hello,' . $name; } }
构造payload:
访问aaaaaaaaaaa.php
可以看到成功写入/public目录
官方给出的修复方式修正sessionid检查的一处隐患 · top-think/framework@1bbe750 · GitHub
漏洞位于_vendor_topthink_framework_src_think_session/Store.php,修复方法,仅仅是增加了ctype_alnum()函数对$id值进行检测,如果$id全部的字符为字母或者数字返回TRUE否则返回FALSE。
漏洞一定和setId()函数有关,我们可以先找一下哪里调用了setId()函数,要找到$id参数是从哪里来的。
这边看上去有些不同,跟进分析一下
可以发现这里的session.var_session_id默认为空,else里执行$sessionId = $request->cookie($cookieName),$cookieName是由getName()函数设置的。查一下$cookieName是什么,在_vendor_topthink_framework_src_think_session/Store.php发现$cookieName的值是”PHPSESSID”,而这个值是我们可以控制的。
好像没有什么思路了,回到官方补丁的位置再看看还有什么没有想到的点。回去后我们发现,在setId()函数下面_vendor_topthink_framework_src_think_session/Store.php129行还有一个getId()函数,该函数用于返回$id值,查看调用后发现了文件写入的位置。
看一下write()函数
_vendor_topthink_framework_src_think_session_driver_File.php
看一下这两个函数
首先发现最终$filename被拼接成了sess_$name
从之前的分析中,我们知道getFileName中传进的$sessID是getId()函数获得的$id的值,而这个$id实际上来自于cookie中的PHPSESSID。同时,当setId()函数中$id长度为32时,不会进行md5操作,于是只要把输入PHPSESSID内容控制在32位,我们就可以控制最终的session文件名。
最终在_vendor_topthink_framework_src_think_session_driver_File.php
写入文件,但是想要控制文件内容,还是需要控制好储存session变量键名或者键值,具体还要根据具体情况进行判断。
Referer
https://paper.seebug.org/1114/