ThinkPHP5.2.x反序列化利用链
2019-10-09 10:40:29 Author: xz.aliyun.com(查看原文) 阅读量:232 收藏

这个POP链来自 N1CTF2019 中的某道题目,不过和之前 ThinkPHP5.1.x反序列化POP链 差不多,只是当中替换了几个小 Gadget ,这里也记录一下。

环境搭建

➜ html composer create-project topthink/think=5.2.x-dev tp52x
➜ html cd tp52x
➜ tp52x ./think run

application/index/controller/Index.php 代码修改成如下:

<?php
namespace app\controller;

class Index
{
    public function index()
    {
        $u = unserialize($_GET['c']);
        return 'ThinkPHP V5.2';
    }
}

利用条件

  • 有一个内容完全可控的反序列化点,例如: unserialize(可控变量)

  • 存在文件上传、文件名完全可控、使用了文件操作函数,例如: file_exists('phar://恶意文件')

(满足以上任意一个条件即可)

POP链1

这个漏洞链个人认为比较有意思的是:通过 file_exists 函数触发类的 __toString 方法。下面,我们具体分析一下整个漏洞攻击链。

think\process\pipes\Windows 类的 __destruct 方法中,存在一个删除文件功能,而这里的文件名 $filename 变量是可控。如果我们将一个类赋值给 $filename 变量,那么在 file_exists($filename) 的时候,就会触发这个类的 __toString 方法。因为 file_exists 函数需要的是一个字符串类型的参数,如果传入一个对象,就会先调用该类 __toString 方法,获取其字符串返回值,然后再判断。(下图对应文件 vendor/topthink/framework/src/think/process/pipes/Windows.php)

接下来,我们就来寻找可利用的 __toString 方法。全局搜索到的 __toString 方法其实不多,这里有两处都可以利用。它们的区别在于利用 think\Collection 构造的链要多构造一步,我们这里只分析链较短的 think\model\concern\Conversion

如下图所示,原先 ThinkPHP5.1.x$relation->visible($name) 已经不见了,其实这段代码被移到了 第180行appendAttrToArray 方法中。这里,我们先关注 第172行getAttr 方法,这里传入的 $key 变量是来自第158行的可控变量 $data 。(下图对应文件 vendor/topthink/framework/src/think/model/concern/Conversion.php)

getAttr 方法中,程序先通过第451行的 getData 获取了 $value 变量。从下图右侧的获取过程中,可以看出最终获得的 $value 变量值可控。然后在第457调用 getValue 方法,传入该方法的前两个变量值均可控,最后一个 $relation 值为 false 。我们跟进 getValue 方法,看其具体代码。(下图对应文件 vendor/topthink/framework/src/think/model/concern/Attribute.php )

可以看到在 getValue 方法中,使用了动态调用(上图第481行),而且这里的 $closure、$value、$this->data 均可控。我们只要让 $closure='system' 并且 $value='要执行的命令' ,就可以触发命令执行。但是上面的 Attribute、Conversiontrait ,不能直接用来构造 EXP ,我们得找使用了这两个 trait 的类。

这里我们找到了符合条件的 Pivot 类,所以这条链的 EXP 如下(例如这里执行 curl 127.0.0.1:8888 ):

POP链2

第二条POP链其实不太好用,需要目标站点可以上传 route.php 文件,且知道上传后文件的存储路径,下面我们来看下具体POP链。

这个POP链的前半部分,和原先 ThinkPHP5.1.x 中的POP链是一样的。只不过在执行到下图第193行时, ThinkPHP5.1.x 中的POP链会去触发 Request 类的 __call 方法,而在 ThinkPHP5.2.x 中移除了 Request 类的 __call 方法,所以我们需要寻找新的可用 __call 方法。

这里,我们使用 Db 类的 __call 方法,因为该方法可以实例化任意类(下图第203行)。结合 Url 类的 __construct 方法,从而进行文件包含。如果攻击者可以上传 route.php 文件,并知道文件存储位置,即可 getshell

最终,这条链的 EXP 如下(这里我事先上传了 route.php/tmp/ 目录下):

PS:为了避免不必要的麻烦,文中EXP均已删除。

参考

N1CTF2019 sql_manage出题笔记

thinkphp v5.2.x 反序列化利用链挖掘


文章来源: http://xz.aliyun.com/t/6476
如有侵权请联系:admin#unsafe.sh