持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情
影响版本
5.0.0<=ThinkPHP5<=5.0.18 、5.1.0<=ThinkPHP<=5.1.10
环境
我这里有之前安好的5.0.12就直接用了
\application\index\controller\index.php
<?php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{
public function index()
{
$this->assign(request()->get());
return $this->fetch(); // 当前模块/默认视图目录/当前控制器(小写)/当前操作(小写).html
}
}
application/index/view/index/index.html内容任意(空文件亦可),主要是作为控制器中index方法的模板
分析
payload
?cacheFile=1.php #我在public下写了一个1.php便于文件包含
首先是进入get(),其实get()就是获取我们get传参的值,内容也比较简单所以就粗略的跟进下。
$this->get不为空,$name是字符串,所以没进入if,直接进入input()(圈出来的是各参数值)
input的前两个if都绕开了,
getFilter()给data就是上一步的$get值)
跟进后其实也没执行啥,就执行了最后的filterExp(),对用户传参进行过滤,但这个基本上是针对sql的所以对我们的payload没影响最终返回$data的值,其实$data的值自始至终没发生过改变
在就跟进assign()了,$name就是get()方法retrun的值,也就是$data的值
protected function assign($name, $value = '')
{
$this->view->assign($name, $value);
}
再跟进$this->view->assign($name, $value);的assign()
通过array_merge(),将$this->data和$name的值合并传给this->data默认为null,所以也就相当于把this
回到我们自己定义的控制器$this->assign(request()->get());就执行完了,再跟进下一行的fetch()
protected function fetch($template = '', $vars = [], $replace = [], $config = [])
{
return $this->view->fetch($template, $vars, $replace, $config);
}
又是套娃继续跟进(四个参数默认为空)
还是array_merge()合并,1和3参数为空,所以data;也就是我们get传参的值,renderContent=false所以$method=fetch160行就相当于又执行了fetch()`
跟进$template默认为空,parseTemplate()获取我们模板文件的路径,之后又又进入了fetch(),可以看下三个参数的值
跟进,前边三个if只有第一个执行了,然后进入parseTemplateFile(),里边其实就执行了一个记录模板文件的更新时间的操作,不看了
下边if,对$cacheFile赋值缓存的一个路径,之后直接进入read()
跟进,进入if进行了个变量覆盖在,EXTR_OVERWRITE标记的情况下,如果有冲突,覆盖已有的变量。所以就讲原有的缓存路径替换成了1.php最后文件包含
不得不说TP非RCE的链真的很友好!!!!