缺陷编号:WooYun-2015-0127151
漏洞标题:PHPYUN最新版任意密码暴力重置(需爆破6位数)
相关厂商:php云人才系统
漏洞作者:menmen519
提交时间:2015-07-20 14:06
公开时间:2015-10-18 14:18
漏洞类型:设计缺陷/逻辑错误
危害等级:高
自评Rank:15
漏洞状态:厂商已经确认
Tags标签:
2015-07-20: 细节已通知厂商并且等待厂商处理中
2015-07-20: 厂商已经确认,细节仅向厂商公开
2015-07-23: 细节向第三方安全合作伙伴开放(绿盟科技、唐朝安全巡航、无声信息)
2015-09-13: 细节向核心白帽子及相关领域专家公开
2015-09-23: 细节向普通白帽子公开
2015-10-03: 细节向实习白帽子公开
2015-10-18: 细节向公众公开
PHPYUN最新版任意密码暴力重置
条件为:后台需开启邮件密码找回功能,默认不开启
这个逻辑其实是一个传统的逻辑,首先我们分析一下代码:条件一:如果允许用户找回密码操作,phpyun就必须后台配置email或者短信,为了分析方便我们注释掉这一块:可以确定官网demo是开启了这个配置,因为它允许用户找回密码wap/forgetpw.class.php:
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
function send_action(){<br> $username=yun_iconv("utf-8","gbk",$_POST['username']);<br> if(!$this->CheckRegUser($username)&&!$this->CheckRegEmail($username)){<br> $res['msg']=yun_iconv("gbk","utf-8","用户名不符合规范!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }<br> $M=$this->MODEL("userinfo");<br> $where=array("`username`='".$username."' or `email`='".$username."' or `moblie`='".$username."'");<br> $info=$M->GetMemberOne($where,array("field"=>"`uid`,`username`,`email`,`moblie`"));if($info['uid']){<br> $sendcode=rand(100000,999999);<br> setcookie("moblie_code",$sendcode,time()+120, "/");<br> /*<br> if($_POST['sendtype']=='email'){<br> if(!($this->config['sy_smtpserver']!="" && $this->config['sy_smtpemail']!="" && $this->config['sy_smtpuser']!="")){<br> $res['msg']=yun_iconv("gbk","utf-8","还没有配置邮箱,请联系管理员!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }elseif($this->config['sy_email_getpass']=="2"){<br> $res['msg']=yun_iconv("gbk","utf-8","网站未开启邮件找回密码!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }<br> }else{<br> if(!$this->config["sy_msguser"] || !$this->config["sy_msgpw"] || !$this->config["sy_msgkey"]){<br> $res['msg']=yun_iconv("gbk","utf-8","还没有配置短信,请联系管理员!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }elseif($this->config['sy_msg_getpass']=="2"){<br> $res['msg']=yun_iconv("gbk","utf-8","网站未开启短信找回密码!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }<br> }<br> */<br> $fdata=$this->forsend(array('uid'=>$info['uid'],'usertype'=>$info['usertype']));<br> $data['uid']=$info['uid'];<br> $data['username']=$info['username'];<br> $data['name']=$fdata['name'];<br> $data['type']="getpass";<br> if($_POST['sendtype']=='email'){<br> $data['email']=$info['email'];<br> }else{<br> $data['moblie']=$info['moblie'];<br> }<br> $data['sendcode']=$sendcode;<br> $data['date']=date("Y-m-d");<br> $status=$this->send_msg_email($data);<br> if($_POST['sendtype']=='email'){<br> $check=$info['email'];<br> }else{<br> $check=$info['moblie'];<br> }<br> $cert=$M->GetCompanyCert(array("uid"=>$info['uid'],"type"=>"5","check"=>$check),array("field"=>"`uid`,`check2`,`ctime`,`id`"));<br> if($cert){<br> $M->UpdateCompanyCert(array("check2"=>$sendcode,"ctime"=>time()),array("id"=>$cert['id']));<br> }else{<br> $M->AddCompanyCert(array('type'=>'5','status'=>0,'uid'=>$info['uid'],'check2'=>$sendcode,'check'=>$check,'ctime'=>time()));<br> } |
从以上代码可以看出来,只要知道用户名即可,这个太方便了,我在系统里面注册了一个用户名为test的用户url:http://localhost/phpyun40/upload/index.php?c=forgetpw&m=wap&a=sendpostdata: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@**.**.**.**',ctime
='1437024891'这个check2 居然是个六位的纯数字,我们在看看check2是怎么产生的$sendcode=rand(100000,999999);我们继续在看这一段代码:
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 28 29 30 31 32 33 34 35 36 |
function editpw_action(){<br> $username=yun_iconv("utf-8","gbk",$_POST['username']);<br> if(!$this->CheckRegUser($username)&&!$this->CheckRegEmail($username)){<br> $res['msg']=yun_iconv("gbk","utf-8","用户名不符合规范!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }<br> $M=$this->MODEL("userinfo");<br> $where=array("`username`='".$username."' or `email`='".$username."' or `moblie`='".$username."'");<br> $info = $M->GetMemberOne($where,array("field"=>"`uid`,`username`,`email`,`moblie`"));<br> if($_POST['sendtype']=='email'){<br> $check=$info['email'];<br> }else{<br> $check=$info['moblie'];<br> }<br> $cert = $M->GetCompanyCert(array("uid"=>$info['uid'],"type"=>"5","check"=>$check),array("field"=>"`uid`,`check2`,`ctime`,`id`"));<br> if($_POST['code']!=$cert['check2']){<br> $res['msg']=yun_iconv("gbk","utf-8","验证码错误");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }<br> if(!$_POST['password']){<br> $res['msg']=yun_iconv("gbk","utf-8","请完整填写信息!");<br> $res['type']='8';<br> echo json_encode($res);die;<br> }<br> $password = $_POST['password'];if(is_array($info))<br> {<br> if($this->config[sy_uc_type]=="uc_center" && $info['name_repeat']!="1")<br> {<br> $this->uc_open();<br> uc_user_edit($info[username], "", $password, $info['email'],"0");<br> }else{$salt = substr(uniqid(rand()), -6);<br> $pass2 = md5(md5($password).$salt);<br> $M->UpdateMember(array("password"=>$pass2,"salt"=>$salt),array("uid"=>$cert['uid']));<br> } |
要想更改这个用户的密码,由以下几个条件第一个email 这个其实等于不是条件,因为这个email是内部传输的,这样一来就为我们减轻了一个参数,其实就是里面的check第二个,check2 这个就是我们刚才的六位纯数字url:http://localhost/phpyun40/upload/index.php?c=forgetpw&m=wap&a=editpwpostdata: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跑跑看看:
看到这个这个长度了就是了破解成功六位纯数字的爆破解释 可以参考http://**.**.**.**/bugs/wooyun-2010-043314
危害等级:低
漏洞Rank:5
确认时间:2015-07-2014:16
感谢提供!我们会尽快修复!
暂无
原文连接
的情况下转载,若非则不得使用我方内容。