文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox

VulnHub

代码审计

PHP代码审计

大数据安全

机器学习

基础学习

Python

Python基础

Python安全

Java

Java基础

算法

Leetcode

随笔

经验

技术

 2020-12-19   931

骑士CMS模板注入+日志包含RCE复现

本文参考自TimeLine Sec团队成员microworld的复现记录。

0x01 漏洞概述

http://www.74cms.com/news/show-2497.html

骑士 CMS 官方发布安全更新,修复了一处远程代码执行漏洞。由于骑士 CMS 某些函数存在过滤不严格,攻击者通过构造恶意请求,配合文件包含漏洞可在无需登录的情况下执行任意代码,控制服务器。

0x02 影响版本

骑士 CMS < 6.0.48

0x03 环境搭建

从官网下载6.0.20版本源代码

http://www.74cms.com/download/index.html

新建数据库,用MAMP Pro搭建站点

0x04 漏洞复现

发送如下请求:

1
2
3
4
5
http://[IP]/index.php?m=home&a=assign_resume_tpl
POST:
variable=
1
&tpl=<?php phpinfo(); ob_flush();?>/r/n<qscms/company_show 列表名="info" 企业id="$_GET['id']"/>

  1. 查看站点日志,文件位于/data/Runtime/Logs/home/20_12_15.log

  1. 包含日志

0x05 漏洞分析

在正式分析漏洞之前,先看一看74CMS的路由和日志记录。

由于74CMS是基于ThinkPHP 3.2.3,其标准的URL路径为:

1
http://[IP]/index.php/模块/控制器/操作

但是74CMS采用的是普通模式,使用传统的GET传参来指定当前访问的模块、控制器和方法,例如:

1
http://localhost/?m=模块&c=控制器&a=方法&var=参数

当然这些参数也是可以自定义的,配置文件位于ThinkPHP/Conf/convention.php

其次,ThinkPHP定义了日志记录的方式,在ThinkPHP/Library/Think/Log.class.php中的write方法:

ERR代表一般性错误,$destination是日志的存储位置,日志文件名是有年_月_日组成。

根据官方通告,漏洞代码位于Application/Common/Controller/BaseController.class.phpassign_resume_tpl方法,用于渲染简历模板:

继续跟进fetch函数,该函数位于Controllor.class.php文件中:

函数内部又调用了ThinkPHP/Lirary/Think/View.class.php类中的fetch方法:

content为空进入第一个if判断,模板文件不存在的话直接返回,下一个if语句判断TMPL_ENGINE_TYPE是否是php,我们可以全局搜索这个常量,在ThinkPHP/Conf/convention.php中定义为Think,也就是说使用Think模板,那么就进入到else语句中。

首先构造一个参数数组$params,然后将调用静态方法Hook::listen,继续跟进,位于ThinkPHP/Library/Hook.class.php文件中:

此时tag=view_parse,该方法会查找$tags中有没有绑定view_parse事件的方法,然后用foreach遍历$tags属性,并执行Hook:exec方法。

此方法会检查行为名称中是否存在Behavior,若存在此关键字,行为扩展必须使用run入口方法,关于Hook的配置在/ThinkPHP/Mode/common.php

继续跟进到ThinkPHP/Behavior/ParseTemplateBehavior.class.php,找到文件中的run方法:

已知74CMS采用的是Think模板引擎,当首次运行时不存在缓存文件,会进入到else语句中,新建一个Template类,在调用类中的fetch方法,位于ThinkPHP/Library/Think/Template.class.php文件:

调用loadTemplate(),将其存入templateCacheFile中,我们跟入loadTemplate

首先读取templateFile的文件内容存到tmplContent中,然后再调用compiler函数编译模板内容,继续跟进:

传入的模板内容未经过过滤就直接被拼接到$tmplContent变量,然后返回loadTemplate方法,调用put方法写入缓存文件,并返回缓存文件名,于是我们再回归到fetch()方法,调用了Storage::load,位于ThinkPHP/Library/Think/Storage/Driver/File.class.php

这里就直接包含文件,最终造成了模板注入。

Copyright © ca01h 2019-2020 | 本站总访问量