热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

thinkphpv6.0.x反序列化利用链挖掘

 0x00 前言上一篇分析了tp 5.2.x的反序列化利用链挖掘,顺着思路,把tp6.0.x也挖了。有类似的地方,也有需要重新挖掘的地方。 0x01 环境准备采用composer安装6.0.*-dev

 

0x00 前言

上一篇分析了tp 5.2.x的反序列化利用链挖掘,顺着思路,把tp6.0.x也挖了。有类似的地方,也有需要重新挖掘的地方。

 

0x01 环境准备

采用composer安装6.0.*-dev版本

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

 

0x02 利用链分析



背景回顾

拿到v6.0.x版本,简单的看了一下,有一个好消息和一个坏消息。

好消息是5.2.x版本函数动态调用的反序列化链后半部分,还可以利用。

坏消息是前面5.1.x,5.2.x版本都基于触发点Windows类的__destruct,好巧不巧的是6.0.x版本取消了Windows类。这意味着我们得重新找一个合适的起始触发点,才能继续使用上面的好消息。


vendor/topthink/think-orm/src/Model.php 新起始触发点

为了节省篇幅,后文不再重复介绍触发__toString函数后的利用链,这部分同5.2.x版本相同(不过wonderkun师傅的利用链已失效,动态函数调用的利用链还能用)。

通常最好的反序列化起始点为__destruct、__wakeup,因为这两个函数的调用在反序列化过程中都会自动调用,所以我们先来找此类函数。这里我找了vendor/topthink/think-orm/src/Model.php的__destruct函数。

public function __destruct()
{
    if ($this->lazySave) {// 构造lazySave为true,进入save函数
        $this->save();
    }
}
public function save(array $data = [], string $sequence = null): bool
{
  // ...
  if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {
    return false;
  }
 
  $result = $this->exists ? $this->updateData() : $this->insertData($sequence);
  // ...
}

首先构造lazySave的值为true,从而进入save函数。

这次触发点位于updateData函数内,为了防止前面的条件符合,而直接return,我们首先需要构造相关参数

public function isEmpty(): bool
{
    return empty($this->data);
}
protected function trigger(string $event): bool
{
  if (!$this->withEvent) {
    return true;
  }
  // ...

其中需保证isEmpty返回false,以及$this->trigger(‘BeforeWrite’)返回true


  1. 构造$this->data为非空数组

  2. 构造$this->withEvent为false

  3. 构造$this->exists为true

从而进入我们需要的updateData函数,来看一下该函数内容

protected function updateData(): bool
{
    // 事件回调
    if (false === $this->trigger('BeforeUpdate')) {// 此处前面已符合条件
        return false;
    }
    // ...
    // 获取有更新的数据
    $data = $this->getChangedData();
    if (empty($data)) {
        // 关联更新
        if (!empty($this->relationWrite)) {
            $this->autoRelationUpdate();
        }
        return true;
    }
       // ...
    // 检查允许字段
    $allowFields = $this->checkAllowFields(); // 触发__toString

同样的,为了防止提前return,需要符合$data非空,来看一下getChangedData

public function getChangedData(): array
{
    $data = $this->force ? $this->data : array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
        if ((empty($a) || empty($b)) && $a !== $b) {
            return 1;
        }
        return is_object($a) || $a != $b ? 1 : 0;
    });
    // ...
    return $data;
}

这里我们可以强行置$this->force为true,直接返回我们前面构造的非空$this->data

这样,我们就成功到了调用checkAllowFields的位置

protected function checkAllowFields(): array
{
    // 检测字段
    if (empty($this->field)) {
        if (!empty($this->schema)) {
            $this->field = array_keys(array_merge($this->schema, $this->jsonType));
        } else {
            $query = $this->db();// 最终的触发__toString的函数
            $table = $this->table ? $this->table . $this->suffix : $query->getTable();
            $this->field = $query->getConnection()->getTableFields($table);
        }
        return $this->field;
    }
       // ...
}

同样,为了到$this->db()函数的调用,需要


  1. 构造$this->field为空

  2. 构造$this->schema为空

其实这两个地方不需要构造,默认都为空

最终,我们终于到了可以触发__toString的位置

public function db($scope = []): Query
{
    /** @var Query $query */
    $query = self::$db->connect($this->connection)
        ->name($this->name . $this->suffix)// toString
        ->pk($this->pk);

看到熟悉的字符串拼接了嘛!!!

不过为了达到该出拼接,我们还是得首先满足connect函数的调用。此处代码就不说了,置$this->connection为mysql即可。接下来,不管是设$this->name还是$this->suffix为最终的触发__toString的对象,都会有同样的效果。

后续的思路,就是原来vendor/topthink/think-orm/src/model/concern/Conversion.php的__toString开始的利用链,不在叙述。

我把exp集成到了phpggc上,使用如下命令即可生成

./phpggc -u ThinkPHP/RCE2 'phpinfo();'

这里由于用到了SerializableClosure,需要使用编码器编码,不可直接输出拷贝利用。


推荐阅读
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • MySQL语句大全:创建、授权、查询、修改等【MySQL】的使用方法详解
    本文详细介绍了MySQL语句的使用方法,包括创建用户、授权、查询、修改等操作。通过连接MySQL数据库,可以使用命令创建用户,并指定该用户在哪个主机上可以登录。同时,还可以设置用户的登录密码。通过本文,您可以全面了解MySQL语句的使用方法。 ... [详细]
author-avatar
手机用户2502927451
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有