漏洞概要
漏洞存在于 ThinkPHP模板引擎中,在加载模版解析变量时存在变量覆盖问题,而且程序没有对数据进行很好的过滤,最终导致文件包含漏洞 的产生。
影响版本
5.0.0 <= Thinkphp <= 5.0.18
5.1.0 <= ThinkPHP <= 5.1.10
环境搭建
Phpstudy:
- OS:
Windows - PHP:
7.3.4 - ThinkPHP:
5.0.18
创建测试环境:
composer create-project topthink/think=5.0.18 thinkphp5.0.18
将 composer.json 文件的 require 字段设置成如下:
"require": {
"php": ">=5.4.0",
"topthink/framework": "5.0.18"
},
执行composer update
控制器: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();
}
}
创建 application/index/view/index/index.html 文件,内容任意,作为这个index控制器的index方法的模板。
在public目录放置一个图片马,模拟文件上传操作
漏洞复现
http://localhost:8090/public/?cacheFile=1.jpg
访问即可文件包含
漏洞分析
public function index()
{
$this->assign(request()->get());
return $this->fetch();
}
跟进assign() 方法
跟进$this->view->assign
在:thinkphp/library/think/View.php
将参数赋值后返回,跟进fetch
继续跟进
变量$vars 为我们get传入的参数并赋值给$this->data
跟进$this->engine->$method($template, $vars, $config);
在think/view/driver/Think.php
可以看到,$data 是get传参。parseTemplate() 函数获取模板文件名,得到默认文件名
继续跟进fetch 方法
public function fetch($template, $vars = [], $config = [])
{
if ($vars) {
$this->data = $vars;
}
...
if ($template) {
...
$this->storage->read($cacheFile, $this->data);
...
echo $content;
}
}
跟进$this->storage->read($cacheFile, $this->data);
在:think/template/driver/File.php
这里有extract($vars, EXTR_OVERWRITE); 。在EXTR_OVERWRITE标记的情况下,如果有冲突,覆盖已有的变量。那么我们可以通过变量覆盖$cacheFile 变量,从而实现文件包含。
方法调用栈:
漏洞修复
判断get传参里是否有cacheFile 键,有的话就删掉,也删掉_think_cacheFile 键,然后再进行文件包含。
|