这个逻辑其实是一个传统的逻辑,首先我们分析一下代码: 条件一: 如果允许用户找回密码操作,phpyun就必须后台配置email或者短信,为了分析方便我们注释掉这一块: 可以确定官网demo是开启了这个配置,因为它允许用户找回密码 wap/forgetpw.class.php:
function send_action(){ $username=yun_iconv("utf-8","gbk",$_POST['username']); if(!$this->CheckRegUser($username)&&!$this->CheckRegEmail($username)){ $res['msg']=yun_iconv("gbk","utf-8","用户名不符合规范!"); $res['type']='8'; echo json_encode($res);die; } $M=$this->MODEL("userinfo"); $where=array("`username`='".$username."' or `email`='".$username."' or `moblie`='".$username."'"); $info=$M->GetMemberOne($where,array("field"=>"`uid`,`username`,`email`,`moblie`")); if($info['uid']){ $sendcode=rand(100000,999999); setcookie("moblie_code",$sendcode,time()+120, "/"); /* if($_POST['sendtype']=='email'){ if(!($this->config['sy_smtpserver']!="" && $this->config['sy_smtpemail']!="" && $this->config['sy_smtpuser']!="")){ $res['msg']=yun_iconv("gbk","utf-8","还没有配置邮箱,请联系管理员!"); $res['type']='8'; echo json_encode($res);die; }elseif($this->config['sy_email_getpass']=="2"){ $res['msg']=yun_iconv("gbk","utf-8","网站未开启邮件找回密码!"); $res['type']='8'; echo json_encode($res);die; } }else{ if(!$this->config["sy_msguser"] || !$this->config["sy_msgpw"] || !$this->config["sy_msgkey"]){ $res['msg']=yun_iconv("gbk","utf-8","还没有配置短信,请联系管理员!"); $res['type']='8'; echo json_encode($res);die; }elseif($this->config['sy_msg_getpass']=="2"){ $res['msg']=yun_iconv("gbk","utf-8","网站未开启短信找回密码!"); $res['type']='8'; echo json_encode($res);die; } } */ $fdata=$this->forsend(array('uid'=>$info['uid'],'usertype'=>$info['usertype'])); $data['uid']=$info['uid']; $data['username']=$info['username']; $data['name']=$fdata['name']; $data['type']="getpass"; if($_POST['sendtype']=='email'){ $data['email']=$info['email']; }else{ $data['moblie']=$info['moblie']; } $data['sendcode']=$sendcode; $data['date']=date("Y-m-d"); $status=$this->send_msg_email($data); if($_POST['sendtype']=='email'){ $check=$info['email']; }else{ $check=$info['moblie']; } $cert=$M->GetCompanyCert(array("uid"=>$info['uid'],"type"=>"5","check"=>$check),array("field"=>"`uid`,`check2`,`ctime`,`id`")); if($cert){ $M->UpdateCompanyCert(array("check2"=>$sendcode,"ctime"=>time()),array("id"=>$cert['id'])); }else{ $M->AddCompanyCert(array('type'=>'5','status'=>0,'uid'=>$info['uid'],'check2'=>$sendcode,'check'=>$check,'ctime'=>time())); }
从以上代码可以看出来,只要知道用户名即可,这个太方便了,我在系统里面注册了一个用户名为test的用户 url: http://localhost/phpyun40/upload/index.php?c=forgetpw&m=wap&a=send postdata: username=test&sendtype=email 这样就会在cert表里面存储一个东西,看看抓到的sql是什么: 如果之前这个人找回过密码也就是数据库里面存在记录,那么就执行 UPDATE `phpyun_company_cert` SET `check2`=486196,`ctime`=1437024758 WHERE 1 and `id`='1' 如果没有记录就会进行insert操作 INSERT INTO `phpyun_company_cert` SET `type`='5',`status`='0',`uid`='1',`check2`='674584',`check`='test@test.com',`ctime`='1437024891' 这个check2 居然是个六位的纯数字,我们在看看check2是怎么产生的 $sendcode=rand(100000,999999); 我们继续在看这一段代码:
function editpw_action(){ $username=yun_iconv("utf-8","gbk",$_POST['username']); if(!$this->CheckRegUser($username)&&!$this->CheckRegEmail($username)){ $res['msg']=yun_iconv("gbk","utf-8","用户名不符合规范!"); $res['type']='8'; echo json_encode($res);die; } $M=$this->MODEL("userinfo"); $where=array("`username`='".$username."' or `email`='".$username."' or `moblie`='".$username."'"); $info = $M->GetMemberOne($where,array("field"=>"`uid`,`username`,`email`,`moblie`")); if($_POST['sendtype']=='email'){ $check=$info['email']; }else{ $check=$info['moblie']; } $cert = $M->GetCompanyCert(array("uid"=>$info['uid'],"type"=>"5","check"=>$check),array("field"=>"`uid`,`check2`,`ctime`,`id`")); if($_POST['code']!=$cert['check2']){ $res['msg']=yun_iconv("gbk","utf-8","验证码错误"); $res['type']='8'; echo json_encode($res);die; } if(!$_POST['password']){ $res['msg']=yun_iconv("gbk","utf-8","请完整填写信息!"); $res['type']='8'; echo json_encode($res);die; } $password = $_POST['password']; if(is_array($info)) { if($this->config[sy_uc_type]=="uc_center" && $info['name_repeat']!="1") { $this->uc_open(); uc_user_edit($info[username], "", $password, $info['email'],"0"); }else{ $salt = substr(uniqid(rand()), -6); $pass2 = md5(md5($password).$salt); $M->UpdateMember(array("password"=>$pass2,"salt"=>$salt),array("uid"=>$cert['uid'])); }
要想更改这个用户的密码,由以下几个条件 第一个email 这个其实等于不是条件,因为这个email是内部传输的,这样一来就为我们减轻了一个参数,其实就是里面的check 第二个,check2 这个就是我们刚才的六位纯数字 url: http://localhost/phpyun40/upload/index.php?c=forgetpw&m=wap&a=editpw postdata: username=test&password=111111&sendtype=email&code=674584 看看后台抓取的sql: 2015/7/16 13:38 UPDATE `phpyun_member` SET `password`='b14a85b5b44b9a523d20ec497fa82f0c',`salt`='01ad17' WHERE 1 and `uid`='1' 跟我们分析的一模一样 那么下来的问题就落在了 这个六位纯数字了 我们brute跑跑看看:
看到这个这个长度了就是了破解成功 六位纯数字的爆破解释 可以参考 WooYun: 21cn密码找回功能设计缺陷(爆破)