host header attack 之tinyshop重置密码漏洞
文章目錄
host header attack这个词也是从老外那里学来的。利用HTTP host头攻击的技术 这里翻译不是很流畅,最好看看原文。
tinyshop中生成找回密码邮件的方法如下:
public function forget_act(){
$email = Filter::sql(Req::args('email'));
$model = $this->model->table('user');
$obj = $model->where("email = '".$email."'")->find();
if(!empty($obj)){
$model = $this->model->table('reset_password');
$obj = $model->where("email = '".$email."'")->find();
$safecode = md5(md5($email).md5(CHash::random(32)));
if(!empty($obj)){
$obj['safecode'] = $safecode;
$model->data($obj)->update();
}
else{
$model->data(array('email'=>$email,'safecode'=>$safecode))->add();
}
$reset_url = Url::fullUrlFormat("/simple/reset_password/safecode/$safecode");
$msg_content = '';
可以看到,生成32位随机数取hash坐位safecode,发送给用户重置密码,这个逻辑是没有问题的。跟一下fullUrlFormat方法。
static function fullUrlFormat($path)
{
$path = trim($path);
if(preg_match('@[/\@#*!]?(https?://.+)$@i', $path,$matches)) return $matches[1];
return self::getHost().self::urlFormat($path);
}
静态方法fullUrlFormat使用了getHost()来获得当前网站自身的域名。继续跟gethost方法。
/**
*取得网站的host地址
*/
public static function getHost($http='http')
{
if(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"]=='on') $http = "https";
if(self::$_host!==null) return self::$_host;
if(isset($_SERVER['HTTP_HOST']))
self::$_host = $http.'://'.$_SERVER['HTTP_HOST'];
else
self::$_host = $http.'://'.$_SERVER['SERVER_NAME'];
return self::$_host;
}
这里输出一下可以看到找回密码的流程中,调用getHost的时候$_host变量的值是null。所以会依次尝试取$_SERVER[‘HTTP_HOST’]和$_SERVER[‘SERVER_NAME’]作为拼接url的域名使用。而$_SERVER[‘HTTP_HOST’]是取自客户端传递的host头部的值,即客户端是可以伪造这个值的。
漏洞危害因为需要交互,所以取决于用户量和用户价值。当用户收到这封真实的找回密码邮件,如果点击了URL,则safecode就会发送给攻击者,从而导致自己的账号被盗。