thinkphp8反序列化分析

thinkphp8反序列化

前言

摆了一个暑假,正好看见周会有人分析了tp反序列化,想起这条链子的发现者就是我尊敬的nivia,这不得好好分析一下,而且师傅也是分析了这个,所以有了这个文章

链子一 __call触发

分析

相比于我们的6来说,原来我们都是通过save方法来作为入口的,但是8直接将整个类的destruct方法都被删除掉了

这里我们使用6的宁一个类

ResourceRegister#__destruct

我们的目的是触发call方法,所以可以寻找可能触发call的地方,并且参数可以控制

think\Validate#__call

public function __call($method, $args)
{
   
    if ('is' == strtolower(substr($method, 0, 2))) {
   
        $method = substr($method, 2);
    }

    array_push($args, lcfirst($method));

    return call_user_func_array([$this, 'is'], $args);
}

这里解释一下call_user_func_array([$this, ‘is’], $args);这个意思

  • [$this, 'is']:这部分表示回调是一个对象方法,$this 是当前对象的引用,'is' 是对象中名为 is 的方法。这相当于 $this->is()
  • $args:这是一个参数数组,它将被解包并传递给 is 方法。

我们看看is方法的重点部分

public function is($value, string $rule, array $data = []): bool
    {
   
        $call = function ($value, $rule) {
   
            if (isset($this->type[$rule])) {
   
                // 注册的验证规则
                $result = call_user_func_array($this->type[$rule], [$value]);

至于参数怎么控制的,分析完调用链再来研究

回到我们入口它调用了register方法

protected function register()
{
   
    $this->registered = true;
    
    $this->resource->parseGroupRule($this->resource->getRule());
}

可以看到其实这里就有触发

但是参数是不一样的,我们看到call是需要传入两个参数的

而getRule只是返回一个参数

public function getRule()
    {
   
        return $this->rule;
    }

继续往下来,进入parseGroupRule方法

image-20240812195052129

随便一看,是存在大量的字符串拼接的,是可以触发我们的Tostring的

因为传入参数都是tostring后该考虑的事,这里我们不需要过多关心参数对后面的影响,只需要能够触发tostring就好了

首先一眼看下去是

$rule = implode('/', $item) . '/' . $last;

这里控制last的值更好触发,但是last的来源是

$array = explode('.', $rule);
$last  = array_pop($array);
$item  = [];

注定了我们的last只能为一个字符串,因为是从我们的rule里面用点分割的,所以不能为一个实例化对象,我们使用

$item[] = $val . '/<' . ($option['var'][$val] ?? $val . '_id') . '>';

这个什么意思呢,问下gpt就懂了

  • foreach ($array as $val):这表示对于数组 $array 中的每个元素,将其值赋给变量 $val ,然后执行循环体中的代码。
  • $item[] = $val. '/<'. ($option['var'][$val]?? $val. '_id'). '>:在每次循环中,创建一个新的元素并添加到数组 $item 中。这个新元素是由当前的 $val 值,加上 /< ,再加上 $option['var'][$val] 的值(如果存在),如果 $option['var'][$val] 不存在,则使用 $val. '_id' ,最后加上 > 组成。

以下是一个示例:

<?php
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值