freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

thinkphp5.0.23变量覆盖导致的RCE分析与复现
z3 2021-12-06 13:43:04 220171
所属地 辽宁省

thinkphp5.0.23变量覆盖导致的RCE分析与复现

复现

payload
http://tptest.cc/?XDEBUG_SESSION_START=17774&s=captcha
POST:_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami

漏洞分析

根据上一篇 invokefunction 的复现,了解了thinkphp加载module,controller,action的过程了
先看看是如何解析s=captcha的
还是在App.php的run方法中,routeCheck这里加断点,发现已经将captcha解析了(注意到,这次的type是method,上一篇 invokefunction 的复现中,type是module)

继续跟进routeCheck
最后跟进了Route.php
路由是个全局静态变量

调试跟进来的时候captcha的路由已经存在了,应该是之前加载配置文件,读取路由配置的时候加载的

全局搜索CaptchaController,找到了,在/vendor/topthink/think-captcha/src/helper.php里注册了路由

好吧,现在知道了captcha路由的解析过程

现在看下\think\captcha\CaptchaController的index方法

加断点,断不到,说明命令执行和这个函数无关
调试发现这里出现了异常

第三句Log抛出异常,而且这个rce看起来和header无关,所以重点看param方法

调试时发现REQUEST_METHOD已经被改了,正常应该是get或post

再重新来一遍,发现了问题,


如果传入_method参数,就会调用把_method当做函数执行,POST参数作为函数参数
payload传入的是_method=__construct
看一下__construct是怎么命令执行的

看这个foreach,,,做了一波变量覆盖
一波操作后,
filter = ['system'],method='get',server['REQUEST_METHOD']=whoami

Request.php中搜索REQUEST_METHOD,
发现这个函数会导致命令执行

接着跟进server->input
这里getFilter拿到的是假过滤器system

接着跟进filterValue,豁然开朗

总结

解析路由时一定会调用method方法,就一定可以造成变量覆盖
命令执行需要调用server方法,调用server方法前提是调用method(true)
而使用method(true)的只有param方法,
所以总结,只要可以调用param方法就可以构造命令执行payload

思考

为什么要这样构造payload?
get请求的s=captcha,,去掉后同样可以执行,有回显,,,不知道网上的payload为什么要加s=captcha

为什么_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami
_method是为了调用__construct函数
对filter进行变量覆盖,而server[REQUEST_METHOD]是filter的参数,(猜测thinkphp本意是用_method参数设置一个自定义的请求类型,通过REQUEST_METHOD对请求类型过滤)
那method=get有什么用呢,
去掉试一下,
实践证明method=get没用

这个漏洞使用有什么限制吗?
调试时发现漏洞在这里触发,所以需要开启debug?

关闭debug试一下
果然,关闭debug复现失败,为什么?理论上只要调用了Request的param方法就可以实现rce啊

所以全局搜索一下param函数,搜索到4个,一个在debug中,两个在exec函数中,另一个在jsonp
看下exec函数
可惜$dispatch['type']值为module,

为了证明猜想,加上一句

RCE成功,看来推理正确

controller和method都用了Request::instance()->param(),只要想办法触发,就可以实现rce
突然想起来,之前调试时,captcha解析时的类型好像是method,,现在是module,,不会是因为我去掉了那俩参数吧,,,,
这个类型由什么控制?
在parseRule中发现

如图:如果$route有\,类型就为method,有@就是controller

解析时,result有两条路,第二条路是写死的module类型,只能走第一条路,才有希望到达上图的parseRule函数

而走第一条路,需要匹配到一条路由,,但是thinkphp默认只有两条如图

传参s=captcha试一下


可以看见路由规则需要根据method筛选,由于我们需要post传参,实现变量覆盖,而captcha/[:id]又是get类型路由,所以匹配不到
但是!注意看,根据method筛选路由语句的上面,调用了method,,,回一下上面的总结"解析路由时一定会调用method方法,就一定可以造成变量覆盖",
所以post参数加个method=get
就可以完美匹配captcha路由了,也就可以调用param方法,造成rce了

所以:这里另一条利用链,不需要开启debug

还有一个jsonp的,有rce希望,,,太累了,明天再看

再总结

通过变量覆盖实现rce有两种方法

  1. 需要开启debug模式
    直接post下面这条
    _method=__construct&filter[]=system&server[REQUEST_METHOD]=whoami

  2. 不需要开启debug模式,但是需要完整版,
    http://tptest.cc?s=captcha
    [POST]
    _method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami

thinkphp5系列大概就这两个rce了,在这两个基础上,知道了原理,可以用一些绕过方法,进一步攻击利用等

感悟

调试完debug模式rce后,,还很不解captcha,method=get,,多此一举?
是我矮了,目光狭隘了

如何修复

看5.0.24如何修复

和5.0.23不同的是,这里routeCheck返回的type是module
想一下之前的总结,命令执行<-调用server<-调用method(true)<-调用param(),而调用param条件有:1. 开启debug 2. type是method或controller 3. jsonp
之前我们通过captcha路由,构造出了payload使type为method,满足第二个条件,但5.0.24中使用相同payload,type还是module

调试一下看问题出在哪了
再回一下之前的总结
漏洞利用第一步,method函数导致变量覆盖,第二步,调用param导致命令执行
先看下method函数有没有变动

果然,,method这里做了白名单过滤,这就没法绕了

# web安全 # 漏洞分析 # 代码审计 # 漏洞复现 # ThinkPHP5
本文为 z3 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
thinkphp系列代码审计
z3 LV.4
  • 27 文章数
  • 89 关注者
Java 反序列化回显链研究:漏洞检测工程化
2022-04-01
Z3专栏 | CommonsCollections3分析
2022-03-19
MeterSphere未授权导致的rce漏洞分析、复现、exp编写
2022-02-11
文章目录