[代码审计]ThinkPHP5的文件包含漏洞

漏洞影响范围

加载模版解析变量时存在变量覆盖问题,导致文件包含漏洞的产生
漏洞影响版本:5.0.0<=ThinkPHP5<=5.0.18 、5.1.0<=ThinkPHP<=5.1.10

tp框架搭建

tp框架由两部分组成
应用项目: https://github.com/top-think/think
核心框架: https://github.com/top-think/framework
框架下载好后,需要更名为thinkphp

这里可以直接用composer来获取代码
通过以下命令获取测试环境代码:

composer create-project --prefer-dist topthink/think=5.0.18 tp5.0.18

将 composer.json 文件的 require 字段设置成如下:

"require": {
    
    
    "php": ">=5.6.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(); // 当前模块/默认视图目录/当前控制器(小写)/当前操作(小写).html
    }
}

创建 application/index/view/index/index.html 文件

漏洞分析

payload:

http://127.0.0.1/tp5.0.18/public/index?cacheFile=php://filter/read=convert.base64-encode/resource=/etc/passwd

在这里插入图片描述
打断点进行调试
先进入assign进行模板变量的赋值
在这里插入图片描述
在这里插入图片描述
这边会有一个过滤,看起来像sql的过滤,与我们这次的没啥关系
在这里插入图片描述
然后进入fetch方法,走完前面的缓存,就会进入一个read方法

在这里插入图片描述

在这里插入图片描述
这里进行了一个变量的赋值:extract($vars, EXTR_OVERWRITE);,但是这里他设置了一个属性:EXTR_OVERWRITE
这个属性的存在,会照成一个变量覆盖的效果
在这里插入图片描述
这时候,cacheFile就会变成我们get提交的数据
下一步就是直接包含了这个文件
输出读取的文件
在这里插入图片描述
成功的包含到了
在这里插入图片描述

漏洞总结

总体来说,漏洞的思路就是:

  1. 先通过view的assign把get数据存在数组data中
    在这里插入图片描述

  2. 然后进入view的fetch方法,通过$vars = array_merge(self::$var, $this->data, $vars);,将data中的数据再合并到vars的变量中去
    在这里插入图片描述

  3. 再进入了Think的fetch方法,vars变量被赋进去了
    在这里插入图片描述

  4. 再到template的fetch方法中去,data变量依旧继续传递下去
    在这里插入图片描述

  5. 到template的fetch方法里面,里面有一个cacheFile变量,值为箭头所指的文件,到了read方法,data和cacheFile一起被赋值进去
    在这里插入图片描述

  6. 可以看到,这里的extract函数由于EXTR_OVERWRITE设置了参数,所以cacheFile变量被覆盖了,导致后面的include就包含了我们vars中的值,而这个值我们是可以控制的,这就造成了一个文件包含的漏洞
    在这里插入图片描述

漏洞的修复

官方漏洞的修复方案
他这里是用了一个$this->cacheFile
这样一来,在include的时候就不会因为变量覆盖而包含到我们data中的数据了

public function read($cacheFile, $vars = [])
{
    
    
    $this->cacheFile = $cacheFile;
    if (!empty($vars) && is_array($vars)) {
    
    
        // 模板阵列变量分解成为独立变量
        extract($vars, EXTR_OVERWRITE);
    }
    //载入模版缓存文件
    include $this->cacheFile;
}

这里学长的文章也是提到了为啥参数不换成EXTR_SKIP防止变量的覆盖呢,EXTR_SKIP的作用就是:如果有冲突,不覆盖已有的变量,那么这一步就会失效,万一你确实是想传这么一个$cacheFile=xxx,那么到这里就会直接实效掉,导致功能的损坏,所以利用$this->cacheFile是更优的选择

猜你喜欢

转载自blog.csdn.net/m0_51078229/article/details/120493680
今日推荐