Bypassing IE's XSS Filter with showModalDialog
I'm not good at English, but I think it is easier to read than Google translate. Maybe.
Enjoy!
-----------------------------------------------------------------------------
先日、古くからあるJavaScriptの関数の1つの、
showModalDialog
の挙動について詳しくみていました。showModalDialog
は、Chromeでは既に動かないし、次期Windowsに搭載されるMicrosoftの新ブラウザ「Edge」でも廃止、Firefoxでも間もなく廃止予定という、着々と消されつつある機能です。なぜこんな死にかけを見ようと思ったかというと、この関数は、ただ新しいウインドウを開くだけではない、個性的な機能を持っており、ちゃんと見てみれば今でも何か面白いことがみつかるかもしれないと思ったからです。その結果、IEのXSSフィルターをバイパスできることに気付いたので今日はそれを紹介します。まずはshowModalDialogの機能をおさらいしましょう。
showModalDialog
の第1引数はモーダルなウインドウ(閉じるまで他のウインドウの操作ができない)にロードするURL、第2引数はモーダルなウインドウに渡せる特別な引数です。第2引数にいれた値は、モーダルなウインドウのwindow.dialogArguments
プロパティを通じてアクセスできます。さらに、モーダルなウインドウ中で、window.returnValue
プロパティに何かを代入すると、モーダルなウインドウを閉じた時に、showModalDialog
を実行した側の戻り値に使われます。うわあ。この、古い機能のダサすぎるかんじ、いいですね…(*´_`*)
要は、
dialogArguments
やreturnValue
は、ウインドウ間の情報の引き渡しに使われているということです。ここで、dialogArguments
やreturnValue
は2つのウインドウのオリジンが異なっていても渡せるのか、ということが気になりました。それぞれ、渡せるとすれば、渡せないことを前提にdialogArguments
/returnValue
を書き出すようなことをしていればXSSが起きるかもしれないし、returnValue
に機密情報を入れている場合は、無関係なところに情報が渡るかもしれないことになります。ということで、簡単にテストしてみました。まず、
dialogArguments
は、現在showModalDialog
をサポートしているFirefox、IE、Safari(OS X)のすべてで別オリジンに引き渡すことはできませんでした。Firefoxは過去に値を設定できていたようですが、脆弱性として修正されたようです。
MFSA 2010-04: window.dialogArguments がクロスドメインで読み取り可能なことによる XSS
http://www.mozilla-japan.org/security/announce/2010/mfsa2010-04.html
一方、
returnValue
は違いました。Firefoxでは制限されていましたが、SafariとIEではオリジンを超えて引き渡すことができました。以下でテストできます。
http://vulnerabledoma.in/showModalDialog/opener.html
Safariは素直に引き渡せます。x-originのボタンを押しダイアログを開いて、「Set returnValue and close this dialog」を押し、異なるオリジン( www.vulnerabledoma.in → vulnerabledoma.in ) へ 値が渡ることを確認してみてください。
IEは間にリダイレクトを挟むと渡せます。x-originのボタンからは動かないですが、x-origin(redirect) のボタンからは動きます。
この挙動によって、次の2つの問題が考えられます。
1.
showModalDialog
を実行した場所が同じオリジンかどうか確認せずにreturnValue
に機密情報を渡している場合に、無関係のサイトに情報を奪取される可能性がある。2.
showModalDialog
で開いたダイアログ内で攻撃者のページまでページ遷移を発生させることができた場合、別ページで攻撃者の設定したreturnValue
が元ページの戻り値に渡り、XSSなどが発生する可能性がある。(ただしこれはSafariのみ。IEはshowModalDialog
のウインドウでのページ遷移が制限されている模様。)どちらもターゲットのサイトで
showModalDialog
がたまたまこの条件で使われていなければ問題にならないので、あまり大きな問題ではないと思います。今回は、
showModalDialog
の安全な使い方を論じるつもりでこの話をしたわけではありません。ここからが本題です。この挙動を使ってIEのXSSフィルターをバイパスします。
悪用が可能になるには次の2つの条件が必要です。
1. JavaScriptの文字列リテラルにXSSがある。
2. JavaScriptのプロパティのどれかに機密情報が含まれている。
以下はこの条件を持ったテストページです。
http://vulnerabledoma.in/xss_token?q=[XSS_HERE]
<form name=form>
<input type=hidden name=token value=f9d150048b>
</form>
<script>var q="[XSS_HERE]"</script>
ページ内にCSRFトークンが含まれており(条件2)、XSS_HERE が入っている文字列リテラルの部分にXSSがある(条件1) といったかんじです。
今回はこのページからトークンを奪います。早速ですが、以下にバイパスのデモページを用意したので、アクセスして、"go"をクリックしてみてください。
http://l0.cm/xssfilter_bypass/showModalDialog.html
うまくいけば、モーダルダイアログを閉じた時にトークンがアラートされるはずです。
原理はまず、XSSに脆弱なページに3xx台のリダイレクトをかますことで、前述のIEの挙動を利用して
returnValue
が別オリジンにも渡るようにします。リダイレクト後の脆弱なページには次のような文字列を挿入します。
http://vulnerabledoma.in/xss_token?q=%22%3BreturnValue=form.token.value//
<form name=form>reurnValueにtokenを引き渡しています。これでウインドウを閉じた時に、別オリジンに情報がパスされるという訳です。
<input type=hidden name=token value=f9d150048b>
</form>
<script>var q="";returnValue=form.token.value//"</script>
また、次のような文字列も攻撃に使える場合があるでしょう。
";returnValue=document.cookie//
";returnValue=localStorage.key//
同一オリジンの別の
window
オブジェクトにwindow.opener
を経由してアクセスできたらもっと面白いと思ったのですが、opener
を参照できず、失敗に終わりました。誰かこの手の方法、思いつきますかね?このバイパスはXSSフィルター側で容易に対策できると思います。具体的には、文字列リテラル部分の遮断ルールのブラックリストに
returnValue
を追加するだけです。"returnValue"という文字列は長いので、副作用もなく簡単に追加できると思います。まぁ、リダイレクトを通さないと値が渡らないことから、別オリジンのreturnValue
から値が渡ることはMicrosoftの認識からすればバグだと思うので根本的に直すならそっちを直すべきだと思いますが。以上です。古い機能の有効活用みたいなかんじですね!
余談ですが、ブログにまとめるために周辺の挙動を改めてみていたら、もっと重大な問題に気がつきました。こっちは修正されたときに改めて書きます。それじゃまた!
追記(2015/6/17)
同一オリジンの別ページの情報を取得する方法を思いつきました。とりあえず以下のページで"go"を押して何が起こるか見てみてください。
http://l0.cm/xssfilter_bypass/showModalDialog2.html
別ページにある「<h1>This is secret Text!</h1>」がアラートされれば成功です。XSSに脆弱なフレームから欲しい情報があるフレームに
top.targetFrame.document.body.innerHTML
を経由してアクセスしてます。気付いたかもしれませんが、今回はリダイレクトを使っていません。どうも、リダイレクトを使った場合だけでなく、showModalDialog
を実行したページとダイアログに開いたページが同一オリジンの場合、ダイアログに含まれるインラインフレームの別オリジンのページもreturnValue
を渡せる力があるみたいです。これ以上触ると蛇が出そうな気しかしません!
追記(2016/2/9)
XSSフィルターバイパスの問題は、2015年12月の月例アップデートで修正されたようです。"returnValue"という文字列が文字列リテラルでのXSSの遮断でブラックリストに追加されているのを確認しました。CVE-2015-6164が恐らくこれです。
https://technet.microsoft.com/ja-jp/library/security/ms15-124.aspx#ID0EX1BG
showModalDialog
自体の動作(クロスオリジンで値が渡る動作)は特に変更されていないようです。