浏览器回退劫持

Report 漏洞复现

0x01:关于 pushState

DOM的window.history提供了对浏览器历史记录的读取,从HTML5开始我们可以操作历史记录堆栈。pushState()函数支持修改history实体,用于改变当前页面历史记录,它和window.location="#foo"相当,都会创建一个与当前页面有关的历史记录,但pushState可以是同源下的任意地址,并且它不会触发hashchange事件。pushState()使用示例:

var state = { foo : 'bar' };
var title = '';
var url = 'test.php';
history.pushState(state, title, url);    

     

0x02:回退劫持示例

根据0x01的描述pushState()可以添加历史记录,添加的记录必须满足同源策略,而且该方法不会触发hashchange事件,那么要怎样才能利用到它呢?先来看段代码:

<script>
var stateObj = {foo : 'bar' };
history.pushState(stateObj,"","#hash1");
history.pushState(stateObj,"","#hash2");
</script>

<a href="#hash1">set hash1</a>
<a href="#hash2">set hash2</a>

<script>
window.onhashchange=function(){
    alert(location.hash);
}
</script>

这个例子给了个特别厉害的思路,通过pushState加载两个该页面的锚点#hash1,#hash2到历史记录,当前地址的锚点是#hash2,如果点击浏览器后退按钮,锚点从#hash2变到 #hash1就会触发hashchange事件,这样既不用担心url同源问题,也不需要担心该怎么触发事件了。

     

0x03:使用场景

上节提到了怎么用pushState触发一个事件,但这有什么用呢?注意上节我提到的是通过后退按钮来触发hashchange,电脑终端的浏览器很少用后退按钮,但手机和平板就不一样了,后退键的使用频率都比较高,所以这个漏洞针对的就是移动端。

通过Nginx反向代理一个网站,用较长的二级域名模仿反向代理网站域名,因为针对的目标是手机端,显示屏显示不了这么长的域名,所以看起来就和正常域名差不多,当用户浏览网页点击后退的时候,我们可以让它跳转到钓鱼界面劫持它。