记录一下分析过程
参考文章:
https://srcincite.io/blog/2021/09/30/chasing-a-dream-pwning-the-biggest-cms-in-china.html
****
****
绕过转义
漏洞在:include/filter.inc.php
****
首先dedecms是全局变量注册,这一点在include/common.inc.php可以看出来
首先是遍历post get cookie 并调用_RunMagicQuotes 进行转义
这里是防止你覆盖get post globals这类变量,通过循环注册 转义,并赋值
再来看看filter.inc.php
可以看到这里如果$magic_quotes_gpc从配置文件中读取没有开gpc的话也是通过addslashes转义,可以看出这里有个变量覆盖的问题
并且foreach循环取key的时候也没有过滤magic_quotes_gpc变量,导致这里可以变量覆盖 不进入转义 直接return
可以全局查找一下那些文件引入了filter.inc.php
在dedecms v5.7中 的bookfeedback.php找到了
由于引入顺序的原因,可以导致转移全部失效
如果后引入common.inc.php就不会了
复现如下
语句是我自己打印出来的
就不闭合了,网费不够了
RCE
漏洞存在于dedecms v5.8
阅读完作者文章看漏洞位于flink文件 但是我看到onlymsg值默认是1,不知道作者怎么绕过去的
在进行了一个插入操作后,进入showmsg
可以看到onlymsg默认值为0
function ShowMsg($msg, $gourl, $onlymsg = 0, $limittime = 0){ if (empty($GLOBALS['cfg_plus_dir'])) { $GLOBALS['cfg_plus_dir'] = '..'; } if ($gourl == -1) { $gourl = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; if ($gourl == "") { $gourl = -1; } }
$htmlhead = " <html>rn<head>rn<title>DedeCMS提示信息</title>rn <meta http-equiv="Content-Type" content="text/html; charset={dede:global.cfg_soft_lang/}" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="renderer" content="webkit"> <meta http-equiv="Cache-Control" content="no-siteapp" /> <link rel="stylesheet" type="text/css" href="{dede:global.cfg_assets_dir/}/pkg/uikit/css/uikit.min.css" /> <link rel="stylesheet" type="text/css" href="{dede:global.cfg_assets_dir/}/css/manage.dede.css"> <base target='_self'/> </head> <body> " . (isset($GLOBALS['ucsynlogin']) ? $GLOBALS['ucsynlogin'] : '') . " <center style="width:450px" class="uk-container"> <div class="uk-card uk-card-small uk-card-default" style="margin-top: 50px;"> <div class="uk-card-header" style="height:20px">DedeCMS 提示信息!</div>
<script>rn"; $htmlfoot = " </script> </center> <script src="{dede:global.cfg_assets_dir/}/pkg/uikit/js/uikit.min.js"></script> <script src="{dede:global.cfg_assets_dir/}/pkg/uikit/js/uikit-icons.min.js"></script> </body>rn</html>rn";
$litime = ($limittime == 0 ? 1000 : $limittime); //1000 $func = '';
if ($gourl == '-1') { if ($limittime == 0) { $litime = 3000; }
$gourl = "javascript:history.go(-1);"; }
if ($gourl == '' || $onlymsg == 1) {
$msg = "<script>alert("" . str_replace(""", "“", $msg) . "");</script>";
} else { //当网址为:close::objname 时, 关闭父框架的id=objname元素 if (preg_match('/close::/', $gourl)) { $tgobj = trim(preg_replace('/close::/', '', $gourl));
$gourl = 'javascript:;'; $func .= "window.parent.document.getElementById('{$tgobj}').style.display='none';rn"; //echo $func;
}
$func .= "var pgo=0; function JumpUrl(){ if(pgo==0){ location='$gourl'; pgo=1; } }rn"; $rmsg = $func; $rmsg .= "document.write("<div style='height:130px;font-size:10pt;background:#ffffff'><br />");rn"; $rmsg .= "document.write("" . str_replace(""", "“", $msg) . "");rn"; $rmsg .= "document.write("";
if ($onlymsg == 0) { if ($gourl != 'javascript:;' && $gourl != '') { $rmsg .= "<br /><a href='{$gourl}'>如果你的浏览器没反应,请点击这里...</a>"; $rmsg .= "<br/></div>");rn"; $rmsg .= "setTimeout('JumpUrl()',$litime);"; } else { $rmsg .= "<br/></div>");rn"; } } else { $rmsg .= "<br/><br/></div>");rn"; } $msg = $htmlhead . $rmsg . $htmlfoot; //echo $msg;
}
$tpl = new DedeTemplate(); $tpl->LoadString($msg);
$tpl->Display();}
flink中showmsg gourl参数设置为-1
-1时 取referer的值覆盖$gourl
gourl根据特定字符replace之后传给tgobj 在后面拼到了func 最终频道$msg中
进到loadstring就是根据msg内容md5创建一个文件,并对模板内容进行解析
跟入display
在wirecache的时候有一个黑名单检测
但是这个匹配有点鸡肋,黑名单也不全 自己想办法绕过即可
最终通过include来包含模板 执行代码,复现如下
flink是需要改成1的
通过寻找recommend.php 可以实现无条件rce
条件均满足 即为-1 only也为0 美滋滋
原文始发于微信公众号(8ypass):ZGVkZWNtcyDovazkuYnnu5Xov4cgdjUuOOaXoOadoeS7tnJjZeWIhuaekA==
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论