0x01 背景
? ? ? 通常来讲,扫描器难以发现逻辑类漏洞,所以企业和安全研究者都比较重视这方面的漏洞。
? ? ? 最近国外漏洞披露平台hackerone上,一位白帽子发现Uber一修改任意账户密码的逻辑漏洞,获得了$10000美元的奖励。
? ? ? 所以如何通过代码审计来挖掘逻辑漏洞是安全研究人员和开发人员必须熟悉的技能。本篇将主要讲解代码审计中的任意用户密码重置的安全问题。
? ? ? 找回密码原理:用户修改密码时,邮箱中会收到一个含有auth的链接,在有效期内用户点击链接,即可进入重置密码环节。
0x02 rand函数生成auth
? ? ? Windows环境下rand()最大值为32768,所以可被穷举,使用不当就会出现漏洞。之前出现过的漏洞代码如下:
<?php
...
$resetpwd = md5(rand());
$new['user']->update('user',array(
'email'=>$email,
),array(
'resetpwd'=>$resetpwd,
));
//发送邮件
$subject = $TS_SITE['base']['site_title'].'会员密码找回';
$content = '您的登陆信息:<br />Email:'.$email.
? ? ? ? ? ?'<br />重设密码链接:<br /><a href="'.$TS_SITE['base']['site_url'].
? ? ? ? ? ?'index.php?app=user&ac=resetpwd&mail='.$email.'&set='.$resetpwd.'">'.$TS_SITE['base']['site_url'].'index.php?app=user&ac=resetpwd&mail='.$email.'&set='.$resetpwd.'</a>';
echo $content;
? ? ? 可以看到重置密码链接就两个参数,一个是邮箱另外一个就是auth,然而auth是使用了rand()函数生成的,所以我们可以写个脚本生成1-32768的md5值,然后使用burp来Fuzz就能重置任意用户密码了。
? ? ? 生成1-32768的md5脚本如下:
$a=0;
for ($a=0;$a<=32768;$a){
$b = md5(++$a);
echo "\r\n";
echo $b;
}
? ? ? 之后我们以重置管理员admin@admin.com的密码为例,首先抓重置密码的包并设置好变量如下:
? ? ? 然后爆破resetpwd这个auth字段,发现爆破成功!
0x03 auth过于简单可被猜解
? ? ? 跟与rand函数生成auth类似,这里讲另外一个auth生成的算法,算法中的Key没初始化导致的可被枚举,缺陷代码如下:
else{
$timetemp=date("Y-m-d H:i:s",$this->time);
$auth = util::strcode($timetemp,'ENCODE');
$verification= rand(1000,9999);
$encryptstring=md5($this->time.$verification.$auth);
$reseturl=WIKI_URL."/index.php?user-getpass-".$user['uid'].'-'.$encryptstring;
$_ENV['user']->update_getpass($user['uid'],$encryptstring);
$mail_subject = $this->setting['site_name'].$this->view->lang['getPass'];
$mail_message = $this->view->lang['resetPassMs1'].$user['username'].$this->view->lang['resetPassMs2'].$timetemp.$this->view->lang['resetPassMs3']."<a href='".$reseturl."' target='_blank'>".$reseturl."</a>".$this->view->lang['resetPassMs4'].$this->setting['site_name'].$this->view->lang['resetPassMs5'].$this->setting['site_name'].$this->view->lang['resetPassMs6'];
$this->load('mail');
$_ENV['mail']->add(array(),array($email),$mail_subject,$mail_message,'',1,0);
$this->message($this->view->lang['emailSucess'],'index.php?user-login',0);
}
? ? ? 简单分析可知这里重置密码的auth是由
$encryptstring=md5($this->time.$verification.$auth);
? ? ? 这段代码生成的,而$this->time和$vertification=rand(1000,9999)都是可控的变量
? ? ?(一个是当前时间的时间戳、一个是1000-9999随机的数值,这两个可以生成一个字典),
? ? ? 所以关键点就是$auth,我们跟进strcode函数:
function strcode($string,$action='ENCODE'){
$key = substr(md5($_SERVER["HTTP_USER_AGENT"].PP_KEY),8,18);
$string = $action == 'ENCODE' ? $string : base64_decode($string);
$len = strlen($key);
$code = '';
for($i=0; $i < strlen($string); $i++){
$k = $i % $len;
$code .= $string[$i] ^ $key[$k];
}
$code = $action == 'DECODE' ? $code : base64_encode($code);
return $code;
}
? ? ? 函数里有个$key是生成$auth的关键,而$key是对一个字符串进行了截取操作,其中的$_SERVER[“HTTP_USER_AGENT”]是我们请求header里的user_agent变量,用户可控;后面有个PP_KEY居然没有初始化,至此$key也可控了即$auth可控,最终就可以构造找回密码链接来重置任意账户密码了。
其他推荐:
1、重磅分享 | 白帽子黑客浅谈顾问式销售与服务
2、安全观点:企业信息安全十大痛点,你中招了?
3、招人必看!301浅谈国内安全人才薪酬现状
4、白帽黑客成长独白:301消失的那几年
5、邻居说WiFi安全不重要,结果被“黑”傻了
6、美女iPhone丢了后,黑客跟妹子干了这样一件事
7、不看后悔:为什么企业招不到安全人才?你知道吗?
8、我有笔钱,想给你。
长按二维码关注301公众号