ekucms2.5本地文件包含漏洞-代码审计

ekucms2.5本地文件包含漏洞-代码审计

一、前言

​ 为了学习Thinkphp框架的运行原理以及加强自身代码审计能力,所以特意在网上寻找了一个由php编写的CMS漏洞文章,对其进行复现和逆向代码审计。漏洞参考文章如下:

易酷 cms2.5 本地文件包含漏洞 getshell - Oran9e - 博客园 (cnblogs.com)

  • 调试工具:

phpstudy2018+phpstorm+xdebug; Firefox; xdebug helper


  • 工具使用说明:

​ (1) phpstudy2018中已经内置了适应的xdebug模块,可以根据需要进行自由调整,较为方便。

​ (2) phpstudy2018中Xdebug模块位置:phpstudy安装路径\phpstudy\PHPTutorial\php\php-{版本}-nts\ext\php_xdebug.dll

​ (3) 环境配置参考连接:

(32条消息) ThinkPHP学习笔记(七)–PHPstorm+PHPstudy+Xdebug断点调试_limingliang_的博客-CSDN博客_thinkphp断点调试

二、代码审计的思路

(1)利用PHP代码中文件包含存在的高危函数,快速定位那些文件可能存在本地文件包含漏洞。(主要通过全局搜索功能)

(2)在分析文件是否存在本地含漏洞过程中,分析文件关系,确认文件的主要功能点。(静态跟踪函数和变量)

(3)定位可控参数传参点,并使用动态调试,分析数据之间的传递关系。(动态调试)


三、代码审计过程

1.利用关键函数(include)定位可能存在文件包含漏洞的PHP文件,再经过排除从搜索结果中显示文件名已经固定好的文件,最后结果如下:


core/Lib/View.class.php

core/ThinkPHP/Lib/Think/Core/View.class.php

core/ThinkPHP/Lib/Think/Template/ThinkTemplate.class.php

core/ThinkPHP/Common/functions.php

temp/~runtime.php


2.依次定位上述三个文件中的函数位置,并分析逻辑,结果如下:

  • Lib\View.class.php

在这里插入图片描述

通过分析上述代码发现,该函数在调试时使用,同时由于开头已经定义了包含文件名($traceFile = CONFIG_PATH.‘trace.php’;),因此不存在可输入点,可以直接跳过。

Note:

(1) 经过追踪变量CONFIG_PATH,发现该变量在(core/ThinkPHP/Common/paths.php)已经定义。
在这里插入图片描述

(3) 变量 APP_PATH 定位位置:core/Conf/define.php

在这里插入图片描述

(3) 变量 CONF_DIR 定义的位置:core/ThinkPHP/Common/paths.php
在这里插入图片描述
综上所述,同理查找该文件中使用了include其他的函数,最后发现未使用固定的文件路径的函数为:fetch()

代码如下:

public function fetch($templateFile='',$charset='',$contentType='text/html',$display=false)
    {
        $GLOBALS['_viewStartTime'] = microtime(TRUE);
        if(null===$templateFile)
            // 使用null参数作为模版名直接返回不做任何输出
            return ;
        if(empty($charset))  $charset = C('DEFAULT_CHARSET');
        // 网页字符编码
        header("Content-Type:".$contentType."; charset=".$charset);
        header("Cache-control: private");  //支持页面回跳
        //页面缓存
        ob_start();
        ob_implicit_flush(0);

        if(!file_exists_case($templateFile))
            // 自动定位模板文件
            $templateFile   = $this->parseTemplateFile($templateFile);

        $engine  = strtolower(C('TMPL_ENGINE_TYPE'));
        if('php'==$engine) {
            // 模板阵列变量分解成为独立变量
            extract($this->tVar, EXTR_OVERWRITE);
            // 直接载入PHP模板
            include $templateFile;
        }elseif('think'==$engine && $this->checkCache($templateFile)) {
            // 如果是Think模板引擎并且缓存有效 分解变量并载入模板缓存
            extract($this->tVar, EXTR_OVERWRITE);
            //载入模版缓存文件
            include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX');
        }else{
            // 模板文件需要重新编译 支持第三方模板引擎
            // 调用模板引擎解析和输出
            $className   = 'Template'.ucwords($engine);
            require_cache(THINK_PATH.'/Lib/Think/Util/Template/'.$className.'.class.php');
            $tpl   =  new $className;
            $tpl->fetch($templateFile,$this->tVar,$charset);
        }
        $this->templateFile   =  $templateFile;
        // 获取并清空缓存
        $content = ob_get_clean();
        // 模板内容替换
        $content = $this->templateContentReplace($content);
        // 布局模板解析
        $content = $this->layout($content,$charset,$contentType);
        // 输出模板文件
        return $this->output($content,$display);
    }

通过分析以上代码逻辑,出现以下结论:

(1)该函数存在接收变量:$templateFile

(2)该函数在接收变量的参数值时,不存在严格过滤行为

(3)该函数中存在 include $templateFile 操作

因此可以判断该函数存在本文件包含漏洞,需要进一步跟踪该函数被调用的位置,同时确认 $templateFile 变量是否能够由URL中获取。

经过查找,发现 $templateFile 变量在该文件中被定义,但未找到该项目中,调用该文件下View类的方法。(后续分析发现,是源代码有过改动,因此不能利用。)

3.通过上述结论,并查找项目中所有代码发现,开发者相同的函数存在多处定义的情况。因此直接利用函数 fetch() 查找代码,最终发现如下文件中,也存在相同的函数定义和调用:

(1)temp/~runtime.php

(2)core/ThinkPHP/Lib/Think/Core/Action.class.php

(1)经过分析发现 core/ThinkPHP/Lib/Think/Core/Action.class.php 文件中不存在 fetch() 函数调用,因此直接排除该文件。
在这里插入图片描述
(2)分析 temp/~runtime.php 的源代码中的fecth()函数。

 public function fetch($templateFile='',$charset='',$contentType='text/html',$display=false) {
        $GLOBALS['_viewStartTime'] = microtime(TRUE);
        if(null===$templateFile) return ;
        if(empty($charset)) $charset = C('DEFAULT_CHARSET');
        header("Content-Type:".$contentType."; charset=".$charset);
        header("Cache-control: private");
        ob_start();
        ob_implicit_flush(0);
        if(!file_exists_case($templateFile)) $templateFile = $this->parseTemplateFile($templateFile);
        $engine = strtolower(C('TMPL_ENGINE_TYPE'));
        if('php'==$engine) {
            extract($this->tVar, EXTR_OVERWRITE);
            include $templateFile;
        } elseif('think'==$engine && $this->checkCache($templateFile)) {
            extract($this->tVar, EXTR_OVERWRITE);
            include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX');
        } else {
            $className = 'Template'.ucwords($engine);
            require_cache(THINK_PATH.'/Lib/Think/Util/Template/'.$className.'.class.php');
            $tpl = new $className;
            $tpl->fetch($templateFile,$this->tVar,$charset);
        }
        $this->templateFile = $templateFile;
        $content = ob_get_clean();
        $content = $this->templateContentReplace($content);
        $content = $this->layout($content,$charset,$contentType);
        return $this->output($content,$display);
    }

通过分析代码能发现存在两处本地文件包含漏洞位置;


        if('php'==$engine) {
            extract($this->tVar, EXTR_OVERWRITE);
            include $templateFile;
        } elseif('think'==$engine && $this->checkCache($templateFile)) {
            extract($this->tVar, EXTR_OVERWRITE);
            include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX');
        } else {
            $className = 'Template'.ucwords($engine);
            require_cache(THINK_PATH.'/Lib/Think/Util/Template/'.$className.'.class.php');
            $tpl = new $className;
            $tpl->fetch($templateFile,$this->tVar,$charset);
        }

  • include $templateFile;

​ 经过分析代码逻辑发现,该处由于自定义变量 TMPL_ENGINE_TYPE=think ,不满足 if(‘php’==$engine) 判定条件,因此无法调用。

  • include C(‘CACHE_PATH’).md5($templateFile).C(‘TMPL_CACHFILE_SUFFIX’)

​ 1)通过继续追踪代码逻辑,需要满足调用 checkCache($templateFile) 的条件才能使用include,接下来继续追踪分析分析 checkCache($templateFile)

    protected function checkCache($tmplTemplateFile) {
        if (!C('TMPL_CACHE_ON')) return false;
        $tmplCacheFile = C('CACHE_PATH').md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX');
        if(!is_file($tmplCacheFile)) {
            return false;
        } elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) {
            return false;
        } elseif (C('TMPL_CACHE_TIME') != -1 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) {
            return false;
        }
        return true;
    }

​ 通过最终追踪分析 C(‘CACHE_PATH’)=/temp/CacheC(‘TMPL_CACHFILE_SUFFIX’)=html,得到变量 $tmplCacheFile=/temp/Cache/模板名称.html,并判断缓存文件是否存在;若缓存文件不存在,则放回True;若存在缓存文件,且缓存文件的修改时间要小于保存的时间,则返回FALSE。 (在进一步的动态调试测试分析过程中,发现TMPL_CACHE_ON 变量经过处理后一直为 OFF状态,因此会直接跳过。)

2)返回fetch()函数,继续分析,最终定位到可利用代码块如下:

​ a.不存在缓存文件的情况,且 TMPL_CACHE_ON 在传入是为 ON 状态:

...
    extract($this->tVar, EXTR_OVERWRITE);
    include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX');
...

​ 可以直接通过该值进行利用。(PS:这个时候与ThinkPHP3.X~5.X 存在的本地包含漏洞原理一致)

​ b.存在缓存文件的情况:

...
	$className = 'Template'.ucwords($engine);
	require_cache(THINK_PATH.'/Lib/Think/Util/Template/'.$className.'.class.php');
	$tpl = new $className;
	$tpl->fetch($templateFile,$this->tVar,$charset);
...

​ 进一步跟踪代码,发现是调用并加载模板文件的过程,同时发现调用了 core/ThinkPHP/Lib/Think/Util/Template/TemplateThink.class.php 文件中的 load() 函数。通过进一步跟进函数,发现 load() 函数中存在 文件包含漏洞代码:include $templateCacheFile,至此产生文件包含漏洞的源代码定位成功。
在这里插入图片描述

4.定位参数传递的位置

前提说明:
	由于通过观察源代码项目结构很容易发现,ekucms2.5是利用了thinkphp的MVC(即:Moudle,View,Controller)模式,其传输的URL参数格式有三种:
	(1)http://{IP:port}/index.php?a=test1&b=test2
	(2)http://{IP:port}/index.php/{moudle}/{Controller}/变量/变量值  
	(3)http://{IP:port}/index.php/?s={moudle}/{Controller}/变量/变量值 
通过观察发现,其传输参数为第三种,因此只需要寻找到调用 TemplateThink.class.php 文件的模块和控制器即可

(1)首先依据thinkphp的目录结构,寻找配置文件,查看那些模块能够从HTTP报文中获取参数值。通过搜索最终发现 config.php 中存在两处-
在这里插入图片描述

分别为:/home/info/detail 和 /home/my/show,依次访问相应路径的网页,查看是否正常触发断点。最终确认 /home/my/show 模块能够能够向 参数 id 传入值。
在这里插入图片描述

处理id值的文件位置为:core/Lib/Action/Home/MyAction.class.php

四、总结

​ ekucms2.5底层采用thinkphp5的框架编写,本次本地文件包含漏洞本质上与thinkphp5.x的产生的原因基本一致。在进行漏洞利用时,程序运行的流程图参考如下:

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
易酷免费影视系统V2.5 Final对比以往版本做了如下操作: 1、多分类批量处理 2、分页模板独立 3、后台视频管理可按播放器或者星级选择视频 4、采用友言社会化评论系统 5、后台生成显示当前状态 6、幻灯片支持分类调用 7、添加自定义采集资讯 8、common.php 加载 con_common.php 文件 9、模板自定义主目录(再不不担心模板被盗用了) 10、影片总数、今天更新数量、昨天更新、本周更新、本月更新 11、更多标签的支持完善 01、地区 02、年代 03、星级 04、字母 12、后台数据库密码"*"表示 13、详情页去除多余的关键字描述14、多分类名称可在标题栏显示 15、主演、导演的链接可独立调用 16、其它 易酷免费影视系统是一套专为不同需求的站长而设计的视频点播系统,灵活,方便是最大的特色,为初学者快速架设网站首选,只需5分钟即可建立一个海量的视频讯息的行业网站。 易酷免费影视系统采用PHP MYSQL架构,国内优秀TP的框架为开发基础,其卓越的访问速度和负载能力免去您的后顾之优。 本着免费开源的宗旨、将易酷免费影视系统努力打造成为您身边最贴近的建站程序!不需要庞大的空间与高带宽;一个普通的虚拟空间就可以迅速搭建起一个内容丰富的视频、资讯网站,使你的建站成本低至极点! 现将易酷免费影视系统2.5的一些特性简要概述如下: 1:内核安全稳定(基于ThinkPhp框架开发/PHP MYSQL架构/Jquery类包/超强的负载能力与缓存/UTF8编码) 2:安装使用简单(一健安装/一键采集/一键备份/一键切换动静态模式/操作简便/灵活实用) 3:网站运营全面(支持免费点播/收费点播/QQ用户可直接登录/集成支付宝接口) 4:影片资源丰富(多播放器/多浏览器支持/百万集片库/24小时不间断更新/一键采集/自定义采集) 5:建站资源丰富(SEO优化模板免费下载/实用插件工具免费下载/完善的教程学习) 6:网站管理轻松(支持定时采集/定时生成/做最懒最赚钱的站长) 流量 7:SEO优化工具篇(百度,谷歌地图/rss订阅/单文件RSS聚合/TAG关键字聚合/专题编辑) 8:SEO优化模板篇(标签灵活调用/播放页每集静态标题描述/自定义常用标签/专题匹配/关联词匹配) 9:SEO优化路径篇(静态模式/伪静态模式/动态模式/自定义生成路径) 10:网站互动守住流量(评分/顶踩/评论/留言/会员等用来提升人气的模块可大幅提搞回头客留住流量) 变现 11:流量变现(自定义缓冲广告/内置广告模块/推荐流量互换/推荐广告联盟/友情链接交换)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值