php判断版本根据版本调用不同,ThinkPHP5.1.x代码执行漏洞

前言

出题好几天没审计代码了,今天趁体育课来审一下ThinkPHP5.1.x代码执行漏洞。

一开始想做一个大总结来着,看了网上的文章已经有总结的很好的了,我就不再搬砖了。

这个文章仅仅是用来锻炼,哪怕是ThinkPHP5.1.x,他们因为版本的不同,debug是否开启导致payload也会不同。而且现在RCE基本不存在了,找找思路就行了。。

0x01

这里随便写写小总结,只是提一下。

先来明确一下

rce有两个大版本的分别

ThinkPHP 5.0-5.0.24

ThinkPHP 5.1.0-5.1.30

继续根据payload细分:

一种是因为Request类的method和__construct方法造成的,另一种是因为Request类在兼容模式下获取的控制器没有进行合法校验:

继续细分:

1:thinkphp5 method任意调用方法导致rce

上个文章就是分析的这个:

$this->method可控导致可以调用__contruct()覆盖Request类的filter字段,然后App::run()执行判断debug来决定是否执行$request->param(),并且还有$dispatch['type'] 等于controller或者 method 时也会执行$request->param(),而$request->param()会进入到input()方法,在这个方法中将被覆盖的filter回调call_user_func(),造成rce。

2:method __contruct导致的rce

思路基本一致,但是细节不同。此外1和2必须开启debug才能RCE。有captcha路由时无需debug=true。

3:未开启强制路由导致rce

版本和DEBUG选项的关系

有时候你会发现即使版本一样依旧无法RCE

5.0.13版本之后需要开启debug才能rce

但是呢

在thinkphp5完整版中官网揉进去了一个验证码的路由,可以通过这个路由触发rce

在上个文章中也已经验证过了

318fa5d9239a0b7163df5472f7593ba9.png

0x02

今天我们要分析的主题就是未开启强制路由导致rce

环境:

"require": {

"php": ">=5.6.0",

"topthink/framework": "5.1.29"

},

漏洞成因:

690064cfe6bf7bdd95da0bd47b914586.png

thinkphp默认没有开启强制路由

说明我们可以使用路由兼容模式 s 参数,而框架对控制器名没有进行足够的检测,说明可能可以调用任意的控制器任意方法来执行,

eg: http://site/?s=模块/控制器/方法

访问:

76ccf77fb4761931d8ff7993432c4464.png

看payload分析:

首先我们要知道

所有用户参数都会经过 Request 类的 input 方法处理,该方法会调用 filterValue 方法,而 filterValue 方法中使用了 call_user_func。这个在前面文章分析也提过了。

找request方法

跟进到thinkphp/library/think/App.php:402

64fbb30715ac2a2d231d6a5c06f804ef.png

跟进

routeCheck()

就在这个页面中。这个方法最后

return $dispatch

通过打断点

a42004b87d25931274d41f22924f4b57.png

我们看到这个方法把我们的/替换成了|

继续回去看init()

d91bbfc00686040356bfdd35531df11d.png

进入Url.php

eeb77241038afa73d803206d8e1400de.png

进入parseUrl

007ee51c3ad741079e92e510801f60da.png

进入

156ea9e58d1dc40be4c424cd945845b1.png

进入parseUrlPath()

b21de8508f9fa4203c08547bb3777a42.png

这里从URL处获取了

[模块/控制器/操作],导致parseUrl()返回的route为

index think\Request input

为什么呢?我们回到parseUrl()找route

d9f7b830d3ff07703a689400e37a433d.png

导致thinkphp/library/think/App.php:406的$dispatch为

7afc73b7ff273e0b99f2bae7fe0cbc67.png

直接调用了input()函数,然后会执行到 App 类的 run 方法

这里也显示了

caf6d1182ae7a4dfcc53f6347da0d3fa.png

进而调用 Dispatch 类的 run 方法

该方法会调用关键数 exec thinkphp/library/think/route/dispatch/Module.php:84,进而调用反射类

我们跟进

d127b861db55e9cdf816101c2b47105e.png

在 exec 函数中,程序利用反射机制,调用类的方法。这里的类、方法、参数均是我们可以控制的。而且整个过程,并没有看到程序对控制器名的合法性进行检测,这也是导致 远程代码执行漏洞 的直接原因

da745ee91d9f2b14194f872ec4e1ab57.png

cf5eddf1a905f14beb3b86825811fe55.png

所有参数可控,我们让他调用input方法

891d4b8c7f52ed34230701c132e3fbf1.png

input方法已经说过很多次了

进入input()之后继续进入$this->filterValue()

459efa53747832fdd43261e7f57c94dc.png

实现rce

漏洞修复

官方的修复方法是:增加正则表达式

// 获取控制器名

$controller = strip_tags($result[1] ?: $config['default_controller']);

if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {

throw new HttpException(404, 'controller not exists:' . $controller);

}

最后用七月火师傅的一张图

ece42591f1b11896ea5178fb25b58394.png

A-Za-z ↩︎

标签:控制器,调用,input,漏洞,代码执行,rce,ThinkPHP5.1,方法,路由

来源: https://www.cnblogs.com/wangtanzhi/p/12715255.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值