Thinkphp6.0任意文件写入漏洞复现
2020-11-23 10:41:55 Author: xz.aliyun.com(查看原文) 阅读量:307 收藏

作者:1ight@星盟

环境搭建

首先通过composer安装thinkphp6框架
Mac OS

curl -sS getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

国内镜像

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

安装ThinkPHP

composer create-project topthink/think think6

安装以后默认是最新版本,编辑根目录下的composer.json

然后执行composer update
成功降级

ThinkPHP6默认不开启session,我们需要修改app\middleware.php文件

<?php
// 全局中间件定义文件
return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
    // \think\middleware\LoadLangPack::class,
    // Session初始化
     \think\middleware\SessionInit::class
];

最后执行php think run即可

漏洞利用

影响版本:ThinkPHP6.0.0-6.0.1
利用方式:网站使用到了session

任意文件写入

测试环境:PHP7.4.1
macOS Catalina

首先修改_app_controller/index.php

<?php
namespace app\controller;

use app\BaseController;


class Index extends BaseController
{
    public function index()
    {
        $a = isset($_GET['a']) && !empty($_GET['a']) ? $_GET['a'] : '';
        $b = isset($_GET['b']) && !empty($_GET['b']) ? $_GET['b'] : '';
        session($a,$b);
        return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V6<br/><span style="font-size:30px">13载初心不改 - 你值得信赖的PHP框架</span></p></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="eab4b9f840753f8e7"></think>';
    }

    public function hello($name = 'ThinkPHP6')
    {
        return 'hello,' . $name;
    }
}

构造payload:

访问aaaaaaaaaaa.php

可以看到成功写入/public目录

漏洞分析

官方给出的修复方式修正sessionid检查的一处隐患 · top-think/framework@1bbe750 · GitHub


漏洞位于_vendor_topthink_framework_src_think_session/Store.php,修复方法,仅仅是增加了ctype_alnum()函数对$id值进行检测,如果$id全部的字符为字母或者数字返回TRUE否则返回FALSE。

漏洞一定和setId()函数有关,我们可以先找一下哪里调用了setId()函数,要找到$id参数是从哪里来的。

这边看上去有些不同,跟进分析一下

可以发现这里的session.var_session_id默认为空,else里执行$sessionId = $request->cookie($cookieName),$cookieName是由getName()函数设置的。查一下$cookieName是什么,在_vendor_topthink_framework_src_think_session/Store.php发现$cookieName的值是”PHPSESSID”,而这个值是我们可以控制的。

好像没有什么思路了,回到官方补丁的位置再看看还有什么没有想到的点。回去后我们发现,在setId()函数下面_vendor_topthink_framework_src_think_session/Store.php129行还有一个getId()函数,该函数用于返回$id值,查看调用后发现了文件写入的位置。

看一下write()函数
_vendor_topthink_framework_src_think_session_driver_File.php

看一下这两个函数

首先发现最终$filename被拼接成了sess_$name



从之前的分析中,我们知道getFileName中传进的$sessID是getId()函数获得的$id的值,而这个$id实际上来自于cookie中的PHPSESSID。同时,当setId()函数中$id长度为32时,不会进行md5操作,于是只要把输入PHPSESSID内容控制在32位,我们就可以控制最终的session文件名。

最终在_vendor_topthink_framework_src_think_session_driver_File.php



写入文件,但是想要控制文件内容,还是需要控制好储存session变量键名或者键值,具体还要根据具体情况进行判断。

Referer
https://paper.seebug.org/1114/


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