ThinkPHP V5.0.5漏洞_ThinkPHP5.0.*版本代码执行漏洞

ThinkPHP5.0.10版本代码执行漏洞

我们先看处理请求的Request类,在thinkphp/ library/think/Request.php。

151ee1cff09ada33a7521013ca006d09.png

Method方法来获取当前的请求类型。

c29fb434880fc53e72b0a92438395f5f.png

b0f6bade73dab17efff698d4011c47d3.png

isGet、isPOST、isPUT等方法都调用了method方法来做请求类型的判断。

而在默认情况下,是有表单伪装变量的

40b4019e16dc6195d018fbe294e99345.png

在默认情况下,该变量值为_method

004c5ed7651dfd1a58127ade15c23ea4.png

在Method方法中,将表单伪装变量对该方法的变量进行覆盖,可以实现对该类的所有函数进行调用。

f8eb6f7ae1ccf9d28f48a3587aa1a919.png

在Request类中,我们看一下__construct析构方法。

如果该类属性不存在,就会调用默认配置文件中的default_filter的值。

如果该类属性存在,就会对$option数组进行遍历,将该类属性赋值为$option数组中键对应的值 。

因此,我们可以构造一个Payload:

s=ipconfig&_mehthod=__construct$method=&filter[]=system

7dc9377d10378102cf297fcc8957d851.png

这个Payload只适用于thinkphp5.0.10版本,为什么?我们来看看thinkphp5.0.23版本的改进。

ThinkPHP5.0.23版本代码执行漏洞

在5.0.23版本中,App类 在thinkphp/ library/think/App.php中,module方法新增设置了filter属性值,初始化了filter属性值,也导致在5.0.10版本中被重新覆盖为配置文件中的默认值导致无法进行利用。

6b6747f6c428f5bfbce040d26cbf5df4.png

在返回到Request类中,Param方法也调用了method方法,它用于获取当前请求的参数,传入了默认值true。

581fbd28aadf59dcb0fac122bc076655.png

再看看method方法

83596a1cfae06499e042c83c4bcd4ef7.png

当传过来的值为true时,会执行下面的代码。

a0d357f3e86c2cf01932704ac64bc069.png

再去看看server方法

a4ff3e53ab84fab4769d643cbe05b51c.png

那么,在此时server方法中的name值为REQUEST_METHOD,然后会调用input方法。

再进行跟踪input方法

$filter = $this->getFilter($filter, $default);

看注释是解析过滤器

再跟踪getFilter方法

7e23e21d0b91457f8bae37ee6f960518.png

此时的$filter= ''和$default=null

因此,执行了$filter = $filter ?: $this->filter;这段代码。

$this->filter被赋值给了$filter,也就是请求中的filter参数。

e88de3dcb833aba8da24d6eddebc705c.png

056a062278bc916ad650e5cc74e2f083.png

再回到input方法中,在解析过滤器之后,判断了$data是否为数组,如果不是,则将每个值作为一个参数并且用filterValue方法进行过滤

3985ed7548a6df7665d28c9d892f097a.png

在server方法中,$this->server接受的是$_SERVER超全局变量。那么在调用析构方法的时候,我们也可以对$this->server的值进行覆盖。

2856556fdbac35cf316749a90ac89c3d.png

在filterValue方法中,调用call_user_func方法导致了代码执行。

再回到Param方法,哪个地方会调用Param方法呢?

用phpstorm搜索一下 

在App类中,找到一处调用了$request->param();

ef4c5634d58fb7458e7397756b551eac.png

如果开启了debug模式,就可以实现代码执行了。

74aa77730addef69410a0bdefac5ec09.png

在调用param方法之前,进行了未设置调度信息则进行 URL 路由检测的功能。用routeCheck方法来设置$dispatch。然后用exec方法

9eaf034d97536bae90cd73e24b72bcde.png

$config变量是通过initCommon方法中的init方法初始化的。

06e041b6a06016aff8b16bda82f2601c.png

184d6c94d826d48a4663b5fff8785cb3.png

再来看看routeCheck方法

01ad0a78f87de33f257799d745bcbcc5.png

3f3f0e35c87ed5c4809487ea969de491.png

加载config文件导入路由配置

然后通过Route::import加载路由。

197cff9583e7e8f27ccd0e2316eb6c6c.png

在入口文件 public/index.php中加载了/thinkphp/start.php文件

1008ccd60c7e50bd8ca701886d92d280.png

在start.php文件中加载了基础文件base.php

52194fc43745b3220c7455e5440dac97.png

在base.php中有注册自动加载功能

跟踪register方法

2b08e1fc8a24a95b6bfd825069c89b20.png

对vendor下的php文件注册系统自动加载

ee30b764c6f5b8422f163b4fc8ae1f26.png

在vendor/topthink/think-captcha/src/helper.php中加载了验证码路由类。

上面执行了Route::import方法之后,此时,我们打印一下Route::rules的值看看。

de99e97bf1902ba034a16aacb2842996.png

14b730fdeb359e27f6f82c32cde66013.png

然后我们再返回到Route::check路由检测(根据路由定义返回不同的URL调度)跟踪check方法

14c03114bc8c953cd5255cd71154f701.png

Check方法调用了Request类中的method方法,把method方法执行的结果小写赋值给$method变量。

在Request类中method方法判断了如果$this->method存在的话,那么就直接返回。

8c9d5748254ba3b208155fea791d850c.png

那么我们在调用析构函数覆盖变量的时候,可以直接将method覆盖掉。$method是可控的了

0a85fa8b756608d2a151d595d28efafe.png

将$method变量的值传入$rules的方法中获取对应的路由信息,赋值给$rules这个变量。

7d7831117cf135be0f0a1ef1089ccea3.png

返回路由规则检测,$method给的值不同返回的结果也会不同。$method=get的时候

0137c449498a41b6a1af2b82b2e5b462.png

3d87183650b004cad17e58560dd53c83.png

$rules的值是不一样的。

e36d703f6a13ffca0d8c15c56163fba1.png

$url = str_replace($depr, '|', $url);

$item = str_replace('|', '/', $url);

$url在check方法中为参数,在App类中routeCheck方法调用

4ae65ac382790ff0377f00d520b71680.png

8ff22ba3fced6c36464f181171c9f2fb.png

$path是经过$request->path();调用Request类中的path方法得到的。

e26b0a6c762eb9d037807a066879fa09.png

如果is_null($this->path)为真的时候,会调用pathinfo函数来获取。

3a23370999f11c0a28c6ac811233c9cd.png

$_SERVER['PATH_INFO']的值为Config配置文件中

默认的值's'

0ed3ecd24c5e4ba72ce68c51bbfc0613.png

url中的s参数可以设置App类中的routeCheck方法中的$path参数。

Router类中的check方法控制了check函数中的$item变量也就控制了check方法最终返回的值,同时也控制了App类中的调度信息$dispath

0aee11729523ea18df719aebc70a6de6.png

$dispath在App类中的run方法中被exec方法调用。

跟踪exec方法

b539f9983780316679d57e3810de5d12.png

6ac87c26494c3e691cf96ad7b1cd4f73.png

这里使用了switch语句判断$dispath['type']来执行相应的代码。

之前,我们需要调用Request类中的param方法来对filter变量的覆盖。

如果$dispath['type']是controller或者是method的时候可以直接调用param方法。

当我们让$dispath['type']=function的时候,调用了invokeFunction方法, invokeFunction方法调用了bindParams方法也对param方法进行了调用。

我们控制了url中的s参数的值可以设置不同的$method,让routeCheck返回$dispath。

我们将控制的url参数s的设置为captcha,并且设置post数据_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ipconfig

68ae531338f56dd5766f579b7e4dd109.png

此时,调用了check方法后会进入checkRoute方法。

145fa5428cd858857861fa11d2101413.png

再调用了CheckRule方法

9bf1acf71471e322ea5f29d49d6d9df1.png

又调用了parseRule方法 

d59f0b0d8e96040315a6cc0d520c7958.png

最后经过路由处理后,返回$result

在调用exec方法以后,触发调用了Request类中的param方法,将Request类中的server变量覆盖,再经过Request类中的input方法的调用导致了代码执行漏洞。

2424ddf18550dba125b7a261d9b068b5.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值