TP3.2.xRCE

前段时间打比赛的时候遇到了Think PHP3.2.x RCE的题目,这个洞是上个月爆出来的:【漏洞通报】ThinkPHP3.2.x RCE漏洞通报。虽然3已经不是主流版本了,但是考虑到还是有不少老的站在用,所以还是有一定的价值的,这里分析一下。

利用

这里用的是Think PHP3.2.5完整版,具体每个版本之间的区别可以看看参考链接

利用的条件是assign方法的第一个变量可控。因此我们可以在indexController写入demo:

1
2
3
4
	public function index($value=''){
        $this->assign($value);
        $this->display();
    }

payload:?m=Home&c=Index&a=index&value[_filename]=.\Application\Runtime\Logs\Home\21_06_30.log

本质上是一个文件包含,再结合报错写log最终达到rce的目的

分析

这里我们先不包含log,而是包含config.ini来分析文件包含,payload:

1
?m=Home&c=Index&a=index&value[_filename]=C://config.ini

首先我们的可控参数通过Controller.class.php中的assign函数最终跳到了View.class.php中的assign函数: test

在该函数中将其赋值给$this->tVar变量:

赋值结束后回到IndexController再进入到display函数,和上面的assign函数一样最终跳到View.class.phpdisplay函数中,该函数中的fetch函数解析并获取模板文件内容,此时模板文件路径和内容为空:

继续跟进fetch函数,该函数中将空的templateFile传入parseTemplate函数:

当参数为空时,parseTemplate函数返回默认的模板文件位置./Application/Home/View/Index/index.html

接着往下走,系统配置的默认模板引擎为think,所以程序进入else分支

this->tVar放入params变量中跳入Hook::listentag变量是写死的view_parse,因此name变量为Behavior\ParseTemplateBehavior,接着进入self::exec

exec函数中调用Behavior\ParseTemplateBehaviorrun方法处理带有我们可控参数的$params变量:

在run方法中经过一些判断,最终调用fetch函数编译并加载模板文件,此时第二个参数就是我们的可控参数:array("_filename"=>“C://config.ini”);

继续跟进fetch,获取缓存文件路径后,进入Storage的load方法中:

在load方法中,$_filename为之前获取的缓存文件路径,$var则为之前带有_filename=C://config.ini的数组,利用extract方法进行变量覆盖,实现任意文件包含:

众所周知,include函数不在意包含的什么文件:

因此我们可以构造一个不存在的模块,使得tp报错,此时tp会将url写入log中,所以我们可以在url中写入恶意代码,再结合上面的LFI实现任意代码执行。

=======

title: “TP3.2.xRCE” date: 2021-08-14T16:19:19+08:00 categories:

  • 漏洞复现 tags:
  • TP
  • web

前段时间打比赛的时候遇到了Think PHP3.2.x RCE的题目,这个洞是上个月爆出来的:【漏洞通报】ThinkPHP3.2.x RCE漏洞通报。虽然3已经不是主流版本了,但是考虑到还是有不少老的站在用,所以还是有一定的价值的,这里分析一下。

利用

这里用的是Think PHP3.2.5完整版,具体每个版本之间的区别可以看看参考链接

利用的条件是assign方法的第一个变量可控。因此我们可以在indexController写入demo:

1
2
3
4
	public function index($value=''){
        $this->assign($value);
        $this->display();
    }

payload:?m=Home&c=Index&a=index&value[_filename]=.\Application\Runtime\Logs\Home\21_06_30.log

本质上是一个文件包含,再结合报错写log最终达到rce的目的

分析

这里我们先不包含log,而是包含config.ini来分析文件包含,payload:

1
?m=Home&c=Index&a=index&value[_filename]=C://config.ini

首先我们的可控参数通过Controller.class.php中的assign函数最终跳到了View.class.php中的assign函数:

在该函数中将其赋值给$this->tVar变量:

赋值结束后回到IndexController再进入到display函数,和上面的assign函数一样最终跳到View.class.phpdisplay函数中,该函数中的fetch函数解析并获取模板文件内容,此时模板文件路径和内容为空:

继续跟进fetch函数,该函数中将空的templateFile传入parseTemplate函数:

当参数为空时,parseTemplate函数返回默认的模板文件位置./Application/Home/View/Index/index.html

接着往下走,系统配置的默认模板引擎为think,所以程序进入else分支

this->tVar放入params变量中跳入Hook::listentag变量是写死的view_parse,因此name变量为Behavior\ParseTemplateBehavior,接着进入self::exec

exec函数中调用Behavior\ParseTemplateBehaviorrun方法处理带有我们可控参数的$params变量:

在run方法中经过一些判断,最终调用fetch函数编译并加载模板文件,此时第二个参数就是我们的可控参数:array("_filename"=>“C://config.ini”);

继续跟进fetch,获取缓存文件路径后,进入Storage的load方法中:

在load方法中,$_filename为之前获取的缓存文件路径,$var则为之前带有_filename=C://config.ini的数组,利用extract方法进行变量覆盖,实现任意文件包含:

众所周知,include函数不在意包含的什么文件:

因此我们可以构造一个不存在的模块,使得tp报错,此时tp会将url写入log中,所以我们可以在url中写入恶意代码,再结合上面的LFI实现任意代码执行。

ef5418316bb4efc68bd96772d45afc77caf7808c

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计