验证。参考漏洞:http://wooyun.jozxing.cc/static/bugs/wooyun-2015-0152291.html
漏洞出现在/phpcms/modules/member/index.php 第1687-1756行
public_forget_password_username()函数
public function public_forget_password_username() { $step = intval($_POST['step']); $step = max($step,1); $this->_session_start(); if(isset($_POST['dosubmit']) && $step==2) { //处理提交申请,以手机号为准 if ($_SESSION['code'] != strtolower($_POST['code'])) { showmessage(L('code_error'), HTTP_REFERER); } $username = safe_replace($_POST['username']); $r = $this->db->get_one(array('username'=>$username),'userid,email'); if($r['email']=='') { $_SESSION['userid'] = ''; $_SESSION['code'] = ''; showmessage("该账号没有绑定手机号码,请选择其他方式找回!"); } else { $_SESSION['userid'] = $r['userid']; $_SESSION['email'] = $r['email']; } $email_arr = explode('@',$r['email']); include template('member', 'forget_password_username'); } elseif(isset($_POST['dosubmit']) && $step==3) { $sms_report_db = pc_base::load_model('sms_report_model'); $mobile_verify = $_POST['mobile_verify']; $email = $_SESSION['email']; if($email){ if(!preg_match('/^([a-z0-9_]+)@([a-z0-9_]+).([a-z]{2,6})$/',$email)) exit('check email error'); if($_SESSION['emc_times']=='' || $_SESSION['emc_times']<=0){ showmessage("验证次数超过5次,验证码失效,请重新获取邮箱验证码!",HTTP_REFERER,3000); } $_SESSION['emc_times'] = $_SESSION['emc_times']-1; if($_SESSION['emc']!='' && $_POST['email_verify']==$_SESSION['emc']) { $userid = $_SESSION['userid']; $updateinfo = array(); $password = random(8,"23456789abcdefghkmnrstwxy"); $encrypt = random(6,"23456789abcdefghkmnrstwxyABCDEFGHKMNRSTWXY"); $updateinfo['encrypt'] = $encrypt; $updateinfo['password'] = password($password, $encrypt); $this->db->update($updateinfo, array('userid'=>$userid)); $rs = $this->db->get_one(array('userid'=>$userid),'phpssouid'); if(pc_base::load_config('system', 'phpsso')) { //初始化phpsso $this->_init_phpsso(); $this->client->ps_member_edit('', '', '', $password, $rs['phpssouid'], $encrypt); } $_SESSION['email'] = ''; $_SESSION['userid'] = ''; $_SESSION['emc'] = ''; $_SESSION['code'] = ''; pc_base::load_sys_func('mail'); sendmail($email, '密码重置通知', "您在".date('Y-m-d H:i:s')."通过密码找回功能,重置了本站密码。"); include template('member', 'forget_password_username'); exit; } else { showmessage("验证码错误!请重新获取!",HTTP_REFERER,3000); } } else { showmessage("非法请求!"); } } else { include template('member', 'forget_password_username'); } }
经历了第一步:
$step = intval($_POST['step']);
$step = max($step,1);
$this->_session_start();
这时候开启_session_start(),然后从phpcms_session取session的值,
然后在第二步时,验证下账户有没有绑定邮箱。然后就返回这个页面。点击获取邮箱校验码。
这时候的url是这样的。
/index.php?m=member&c=index&a=public_get_email_verify&session_code=ftrz&random=0.08188270693514244
执行public_get_email_verify()函数。
public function public_get_email_verify() { pc_base::load_sys_func('mail'); $this->_session_start(); $code = $_SESSION['emc'] = random(8,"23456789abcdefghkmnrstwxy"); $_SESSION['emc_times']=5; $message = '您的验证码为:'.$code; sendmail($_SESSION['email'], '邮箱找回密码验证', $message); echo '1'; } }
然后随机生成$_SESSION['emc']的值,利用sendmail发送邮件,发完以后走第三步,验证校验码。
这时候的session中存在$_SESSION['emc']的值,也就是发送到邮件中的值。对于session,只要浏览器不关,session值就会一直存在本地,除非过期了。
然后我们退回到第一步,输入要重置的另一个账号,这时候的$_SESSION['emc']值是第一个账户的。
然后不走点击获取验证码,直接来到
elseif(isset($_POST['dosubmit']) && $step==3) {
输入第一个账户的$_SESSION['emc']值,然后进行第三步校验,
if($_SESSION['emc']!='' && $_POST['email_verify']==$_SESSION['emc'])
这时候的浏览器中的$_SESSION['emc']值我们是知道的,所以也能进入这个if,然后重置第二个账户的密码。
这个漏洞在phpcmsv9.6.0 中修复了,修复方案就是在第一步查询$username是否有绑定邮箱的时候加入两句话,清空$_SESSION['emc']的值,确保在重置当前账户的时候,session中的userid,email是用户所指定的。