前言

国庆旅游回来,发现tp反序列化链很流行,试着学习一下,打算用三篇文章来目前最新的三个反序列化漏洞,继上两篇tp5.1.x反序列化,tp5.2.-dev的反序列化,现在分析tp6.0.-dev的反序列化漏洞。

环境搭建

composer create-project topthink/think=6.0.*-dev v6.0

poc演示截图

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0e7aef97-8907-41e9-be0d-e7c13a725bc4/rId23.png

调用链

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/01f4c88d-5d4e-474a-80a5-8350c6afd2d2/rId25.png

单步调试

//vendor\\topthink\\think-orm\\src\\Model.php
public function __destruct()
{
    if ($this->lazySave) {  //$this->lazySave可控
        $this->save();
    }
}
//vendor\\topthink\\think-orm\\src\\Model.php
public function save(array $data = [], string $sequence = null): bool
{
    // 数据对象赋值
    $this->setAttrs($data);

    if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {
        return false;
    }

    $result = $this->exists ? $this->updateData() : $this->insertData($sequence); //this->exists可控

    if (false === $result) {
        return false;
    }
//vendor\\topthink\\think-orm\\src\\Model.php
public function isEmpty(): bool
{
    return empty($this->data);    //可控
}
protected function trigger(string $event): bool
{
    if (!$this->withEvent) {        //可控
        return true;
    }
    ...
}
protected function updateData(): bool
{
    // 事件回调
    if (false === $this->trigger('BeforeUpdate')) {   //可控
        return false;
    }

    $this->checkData();

    // 获取有更新的数据
    $data = $this->getChangedData();  

    if (empty($data)) {         //$data可控
        // 关联更新
        if (!empty($this->relationWrite)) {
            $this->autoRelationUpdate();
        }

        return true;
    }

    if ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
        // 自动写入更新时间
        $data[$this->updateTime]       = $this->autoWriteTimestamp($this->updateTime);
        $this->data[$this->updateTime] = $data[$this->updateTime];
    }

    // 检查允许字段
    $allowFields = $this->checkAllowFields();
public function getChangedData(): array
{
    $data = $this->force ? $this->data : array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
        if ((empty($a) || empty($b)) && $a !== $b) {
            return 1;
        }
    //$this->force可控
        return is_object($a) || $a != $b ? 1 : 0;
    });

    // 只读字段不允许更新
    foreach ($this->readonly as $key => $field) {
        if (isset($data[$field])) {
            unset($data[$field]);
        }
    }

    return $data;
}
protected function checkAllowFields(): array
{
    // 检测字段
    if (empty($this->field)) {   //$this->field可控
        if (!empty($this->schema)) {    //$this->schema可控
            $this->field = array_keys(array_merge($this->schema, $this->jsonType));
        } else {
            $query = $this->db();
            $table = $this->table ? $this->table . $this->suffix : $query->getTable();
public function db($scope = []): Query
{
    /** @var Query $query */
    $query = self::$db->connect($this->connection)   //$this->connection可控
        ->name($this->name . $this->suffix)   //$this->suffix可控,采用拼接,调用_toString
        ->pk($this->pk);

后面的链跟之前的一样,这里就不分析了

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/63aa24c3-c2e8-4c24-8a7a-028b0773fa25/rId27.png

poc这里就不放了,公网已经大范围公开。

所有tp版本:https://packagist.org/packages/topthink/framework