任意用户密码修改(二)

  Boom    编号: 030202    奖励 60 积分   2015.02.04   web安全 设计缺陷

前言

 

正如所说的,导致任意密码重置的漏洞有很多种类型,上一篇泳少给我们写了一篇弱验证码所导致的可能会被猜解,分析的也比较细,这一期笔者给介绍的是弱加密导致的任意密码重置。

 

漏洞产生过程

 

本次的案例就以邮箱找回密码来进行切入,笔者就根据泳少的demo进行相应的修改,笔者看到留言说那个demo存在sql注入,笔者下回来看了一下确实存在,不过按照漏洞本身来说,贴合主题就可以了,下面简单的说一下流程:

 

找回密码流程:

 

 

很多邮箱找回密码的方式都是用到这种,通常都是生成一个密钥,然后发送到找回密码的邮箱中,如图:

 

 

校验密钥重置密码流程如下:

 

 

流程已经看完了,下面写一下部分的核心代码,将codekey发送到邮箱代码如下:

 

$email=$_GET['email'];
	$sql="SELECT * FROM userinfo WHERE email = '".$email."'";
	//echo $sql;
	$isuser=$oMySQL->ExecuteSQL($sql);
	if (count($isuser['id'])==1) {
		$time =$oMySQL->ExecuteSQL("SELECT * FROM repass WHERE uid = ".$isuser['id']);
		$retime=date('Y-m-d H:i:s',time());//获取当前时间
		$guid=guid();
		$codekey=base64_encode($retime."|".guid()."|".$isuser['id']);
		//检查时间是否为空
		if (count($time)== 4) {
			$hour=(strtotime($time['starttime'])-strtotime($retime))%86400/3600;//计算时间差
			if ($hour<=-1) {//如果时间操作了限制,则更新下密钥
				if (sendemail($codekey,$email)) {
					$re = array ('Start'=>"Ok",'codekey'=>$codekey);//这里输出codekey是为了方便测试
					echo json_encode($re);	
				}else{
					$re = array ('Start'=>"Error");
					echo json_encode($re);	
				}
				$oMySQL->ExecuteSQL("UPDATE repass SET codekey = ".$guid.",starttime = now() WHERE uid = ".$isuser['id']);
			}else{//如果时间没有超过
				$codekey=base64_encode($time['starttime']."|".$time['codekey']."|".$isuser['id']);
				if (sendemail($codekey,$email)) {
					$re = array ('Start'=>"Ok",'codekey'=>$codekey);//这里输出codekey是为了方便测试
					echo json_encode($re);	
				}else{
					$re = array ('Start'=>"Error");
					echo json_encode($re);	
				}
				//echo '2';
			}
		}else{//如果不等于空,则说明这个账号没有被找回过
			if (sendemail($codekey,$email)) {
				$re = array ('Start'=>"Ok",'codekey'=>$codekey);//这里输出codekey是为了方便测试
				echo json_encode($re);	
			}else{
				$re = array ('Start'=>"Error");
				echo json_encode($re);	
			}
			$oMySQL->ExecuteSQL("INSERT INTO repass (uid,codekey ,starttime) VALUES ('".$isuser['id']."', '".$guid."',now())
                      ");
		}
	}

 

重置密码代码如下:

 

$key=base64_decode($_GET['key']);
$arr = explode("|",$key);//分割传过来的字符串
$time =$oMySQL->ExecuteSQL("SELECT * FROM repass WHERE uid = ".$arr[2]);
$retime=date('Y-m-d H:i:s',time());//获取当前时间
$hour=(strtotime($arr[0])-strtotime($retime))%86400/3600;//计算时间差

if (count($time)== 4) {
	if ($hour<=-1) {//超过时间
		$result = array ('Start'=>"Error");
		echo json_encode($result);	
	}else{//如果时间没有超过
		$result = array ('Start'=>"OK");
		echo json_encode($result);	
	}
}else{
	$result = array ('Start'=>'Error','Count'=>'0');
	echo json_encode($result);
}

 

总结下很容易看出来的几个问题:

 

验证码采用弱加密base64是可以逆的,其中算法为base64_encode(当前时间+唯一id+用户id)
计算时间差的时间直接经过base64加密发给用户了,有效时间是用户可控的
直接用id校验用户身份,容易导致恶意者任意重置密码

 

当然还会有一些其他问题存在,比如sql注入等,因为不再本次的讨论范围之内所以就不细说了。

 

漏洞复现

 

漏洞复现相对来说都比较简单,通常笔者在挖掘任意密码重置漏洞的时候都会去注册两个账号,这样做的目的主要是为了对比两个账号找回密码的key的不同之处,在正常的流程当中我们不可能知道加密的算法,唯一的办法,只能靠“猜”,在我们切换到找回密码界面,输入一个正确邮箱点击提交然后邮箱找回密码,可以看到邮箱已经接收到找回密码的连接了,如图:

 

 

看到这一类信息笔者的想法就是,先点击进去看一下,点进去的页面如下,直接叫笔者输入密码和确认密码了,在重置密码的时候,必须要让程序知道,到底是重置谁得密码,那么肯定需要给服务器传送一个值,这个值对应着一个用户的身份,笔者把对应的数据包抓下来,看到如下,总共传了两个值:

 

GET /demo/repass.php?password=123456&key=MjAxNS0wMS0yOCAxMzowNDoyOXw4RTkyOEQwRjM3QUJBOEZEMzI1RjlEREQ5Mzg3RDhDNHwx HTTP/1.1
Host: 127.0.0.1
Proxy-Connection: keep-alive
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36
Referer: http://127.0.0.1/demo/repwd.php?key=MjAxNS0wMS0yOCAxMzowNDoyOXw4RTkyOEQwRjM3QUJBOEZEMzI1RjlEREQ5Mzg3RDhDNHwx
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8

 

可以看到其中key肯定是用于校验用户身份的,这种加密类型可以看出来为base64,笔者解密下,发现如下:

 

MjAxNS0wMS0yOCAxMzowNDoyOXw4RTkyOEQwRjM3QUJBOEZEMzI1RjlEREQ5Mzg3RDhDNHwx
2015-01-28 13:04:29|8E928D0F37ABA8FD325F9DDD9387D8C4|1

 

解密下发现了3个值,分别为时间、未知key、用户id,在一个安全的密码找回流程中,这个未知的key可能会被用于再次校验用户身份,并从数据库中查询对应的用户id是否拥有这个未知key,如果不拥有则代表这个找回链接是无效的,但是在我们上述的源码中,并没有这个流程,而是直接把时间和用户id传输进去做修改了,那么利用方式也相对于简单,笔者可以自行构造重置密码链接,来重置任意用户的密码了,笔者将当前时间、任意未知key和用户id链接如下,并且用base64进行加密:

 

2015-01-28 13:04:29|8E928D0F37ABA8FD325F9DDD9387D8C4|123456
MjAxNS0wMS0yOCAxMzowNDoyOXw4RTkyOEQwRjM3QUJBOEZEMzI1RjlEREQ5Mzg3RDhDNHwxMjM0NTY=

 

将上述的链接拼接至重置密码链接,访问即可达到重置任意用户密码的目的。

 

Demo 下载:http://pan.baidu.com/s/1eQrgGpG



全部评论 (3)

登录注册


darkston

请问笔者是用什么软件抓取数据包的呢?

2015-02-09 22:09 1楼


小生

soga

2015-02-11 20:53 2楼


yyfzbj

太测了

2015-08-20 14:25 3楼