html%3ca%3e标签中有变量,前端中存在的变量劫持漏洞

避免博客长草,水一篇文章,这篇文章中主要讲一个在前端中出现的有意思的变量劫持漏洞。

0x1 基础知识

当页面存在iframe

的时候,父页面和子页面是可以相互获取到对方的window

对象的,主要利用下面的方法。

(本文不考虑iframe

的sandbox

属性,所有测试都是在不添加任何sandbox

的限制下进行。)

父访问子:

document.getElementById("iframe1").contentWindow; // 获取iframe的window对象

window.frames[0]; // 获取iframe的window对象

window[0] ; // 这个比较有意思, window 是本页面的window对象,window[0] 是子页面的window对象

子访问父:

window.parent; //获取上一级的window对象,如果还是iframe则是该iframe的window对象

window.top ; // 获取最顶级容器的window对象,即,就是你打开页面的文档

如果父和子页面是同源的,那么可以通过这个window对象获取到任何你想获取的内容,包括但是不限于 document,name,location 等。但是在非同源的情况下,iframe的window对象大多数的属性都会被同源策略block掉,但是有两个属性比较特殊。

frames 可读,但是不可写。 意味着可以读取不同域的子页面里面的iframe的window对象

location 可写,但是不可读。意味着父子可以相互修改彼此的 location

结合以上两点可以推导出,爷可以修改孙(孙可以修改爷)的location。(父页面可以获取子页面的window对象,然后通过frames获取孙页面的window对象,然后修改location)

爷修改孙,演示如下:

Document

// CONFIG = "test";

function loaded(x) {

// myframe = window.frames[0];

// myframe.frames[0].location = 'http://www.baidu.com/';

x.contentWindow.frames[0].location = "http://www.baidu.com/";

// console.log(myframe == x.contentWindow);

}

0x2 重新审视一下 id 属性

我们知道在浏览器中有如下特点,我们定义的所有全局变量,都被存储在window对象中,作为window的属性来被访问的。

下面在console中验证一下:

> content = "i am content storage in window";

< "i am content storage in window"

> window.content

< "i am content storage in window"

> window.content == content

< true

同样,我们在页面中定义的具有id属性的dom对象也是作为全局变量存储在 window 中的。

然后再console里访问一下:

> test

<

> window.test

<

这时候想到一个问题,既然 id 属性会被注册成全局变量,那么它会不会覆盖掉已经存在的全局变量呢?我们写如下的测试代码:

test

test2

// CONFIG = "test";

test = "ddd";

document.getElementsByTagName("h1")[0].setAttribute('id',"test");

document.getElementsByTagName("h2")[0].setAttribute('id',"test2");

在console中输入:

> test

< "ddd"

> test2

>

test2

事实证明无法覆盖已经定义的变量,但是却可以定义新的变量

怎么让页面中出现未定义的全局变量呢?别忘了 chrome 74之后 默认的 xss auditor 从block模式变成了filter模式,可以利用这个删除掉页面中的代码。(此问题文章最后演示)

另外我们知道,如果在页面中定义两个id一样的元素之后,这样使用document.getElementById

就无法获取到这个id了,但是并不意味着着全局变量就不存在了,看下面这个实验。

> test

< HTMLCollection(2) [h1#test, h2#test, test: h1#test]

0: h1#test

1: h2#test

length: 2

test: h1#test

__proto__: HTMLCollection

很明显全局变量test

还是存在的,是包含两个元素的数组。

0x3 同样道理看一下iframe的name属性

在console里验证一下

> viewer

< Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

情况差不多,这里的viewer

是注册在全局变量里的window对象。

但是如果页面中出现两个name

相同的iframe

,又会是什么情况呢?

在console里面输入:

> test

< global {window: global, self: global, location: Location, closed: false, frames: global, …}

> test == document.getElementsByTagName('iframe')[0].contentWindow

< true

> test == document.getElementsByTagName('iframe')[1].contentWindow

< false

发现跟id的情况并不相同,这里只有第一个元素,而且仅有第一个元素。

0x4 id 和 name 重复出现时

name在id前面

> test

< global {window: global, self: global, location: Location, closed: false, frames: global, …}

id在name前面

> test

< global {window: global, self: global, location: Location, closed: false, frames: global, …}

可以发现 name 的优先级是高于 id 的优先级的,无论怎样全局变量里存储的都是 iframe 的 window对象。

0x5 漏洞场景

我们有一个可以控制的域 A.com 中有页面 A.com/A.html , 用iframe加载了 B.com 的域的页面 B.com/B.html 。A.html无法操作B.html页面,因为是不同源的,同时 B.com/B.html 页面用iframe加载了一个新的页面 C.com/C.html 。

此时 B.com/B.html 存在一个未定义的全局变量 (可以是利用chrome的xss auditor的filter模式产生的),怎么利用?场景用代码描述如下:

click me

VUL = "Hijack me";

function test(){

// 不能用alert ,alert 会尝试访问 VUL window对象的特有方法,会爆跨域错误

console.log(VUL);

}

利用的poc如下,修改A.html如下:

function loaded(x){

x.contentWindow.frames[0].location = "http://A.com/index.html"; // 修改为跟A.com同源,这样在修改此iframe的name的时候就不会被同源策略block

setTimeout(function() {

console.log('setting viewer...');

x.contentWindow.frames[0].name = "VUL"; // 重新定义全局变量

},1000);

}

然后访问 A.com/A.html ,就会发现 B.com/B.html 中的VUL

已经被劫持了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值