IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> ekucms2.5本地文件包含漏洞-代码审计 -> 正文阅读

[PHP知识库]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的产生的原因基本一致。在进行漏洞利用时,程序运行的流程图参考如下:

在这里插入图片描述

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 00:56:09  更:2022-02-19 00:56:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 5:01:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计