2007年12月6日木曜日

画像ファイルによるクロスサイト・スクリプティング(XSS)傾向と対策

補足

この記事は旧徳丸浩の日記からの転載です(元URLアーカイブはてなブックマーク1はてなブックマーク2)。
備忘のため転載いたしますが、この記事は2007年12月6日に公開されたもので、当時の徳丸の考えを示すものを、基本的に内容を変更せずにそのまま転載するものです。
補足終わり


最近、画像ファイルを用いたクロスサイト・スクリプティングが注目されている。本稿では、画像を悪用したXSSについて説明した後、対策方法について解説する。

画像によるXSSとはどのようなものか

Internet Explorer(IE)の特性として、コンテンツの種類を判別する際に、レスポンスヘッダ内のContent-Typeだけでなく、コンテンツの内容も判断基準にしている。このため、Content-Typeが例えばimage/gif(GIF画像)となっていても、中身がHTMLであればHTMLと解釈して表示する。このため、JavaScriptが埋め込まれていたら、JavaScriptを実行することになる。 例を示そう。このファイル(html.gif)は、拡張子は.gifなので、ダウンロードするとContent-Typeはimage/gifとなるが、内容はHTMLでありJavaScriptが埋め込んである。これをIEとFirefoxで表示した例を以下に示そう。
IE7での表示
Firefoxでの表示
IEが、状況によってはContent-Typeを無視して、画像をHTMLと解釈し内部に埋め込まれたJavaScriptを実行してしまう。これによるXSSが成立する場合がある。典型的な状況とてしは、画像のアップロード機能を有するアルバム・サービスのような場合だ。たとえば、はてなの画像アップロードシステムには、この脆弱性があったとして、対応がなされたことがある。 下図は、画像によるXSSの模式図である。攻撃者(左側のサングラスの人物)は、攻撃用JavaScriptを仕込んだ画像を、maitter.com画像アップロードシステムを利用して登録・公開し、この画像のURLをダウンロードするよう、メールやブログなどで誘導する。被害者がこの誘導に引っかかって画像を閲覧すると、JavaScriptが実行され、maitter.comドメインのCookieが盗難されるなどの被害にあう。


先に示したhtml.gifは内容はhtmlテキストだけという素朴なものだが、イメージそのもの、パレット、コメントなどにhtmlやJavaScriptを仕込む手法が知られている(*1)。

対策の検討

IEがコンテンツの種類をどのように判別しているかは公開されていないようだが、たとえば2007年10月10日に公開されたマイクロソフト セキュリティ情報 MS07-057には以下のような記述がある。
PNGs が MIME スニッフィング アルゴリズム の jpg/gif と同じ状態に昇格されます。例: サーバーが png のコンテンツの種類を送信した場合、Internet Explorer は magic-byte (マジックバイト) のテストを実行し、成功した場合、権限のあるサーバーの MIME の種類として処理します。
意味のとりにくい日本語(機械翻訳?)だが、どうもコンテンツの種類判別にIEがマジックバイトを利用しているらしいことがわかる。

マジックバイトとは

マジックバイトとは、画像などのフォーマットを判別しやすいように、ファイルの先頭の数バイトに置かれた固定のデータである。GIF形式の場合であれば、"GIF87a"あるいは"GIF89a"で始まることになっており、先頭6文字を見ればGIF形式であることが容易に判別できる。下表に、主な画像形式のマジックバイトを示そう。
画像形式BMPGIFJPEGPNG
マジックバイトBMGIF8[79]a\xFF\xD8\x89PNG\x0D\x0A\x1A\x0A

IEのコンテンツ種類判別はContent-Typeとマジックバイトの組み合わせ

以上の情報などから、どうもIEのコンテンツ種類判別は、Content-Typeとマジックバイトの組み合わせにより決まるように思える。これを検証するために、主要な画像フォーマット4種(BMP、GIF、JPEG、PNG)のContent-Typeとマジックバイトの全ての組み合わせを試してみた。検証用に用いたサンプルデータは、マジックバイトとJavaScriptを組み合わせただけの簡単なものである。一例を下図に示す(GIF形式の偽画像)。
結果は下表の通りである。表で、「HTML」となっている欄はHTMLと判別され、JavaScriptが起動するもの、「画像」となっているのは、画像と解釈しようとしたが表示できないため「×」表示となることを示している。これらはリンクとなっていて、実際のサンプルデータで試すことが出来るようにした。

画像種類マジックバイトContent-Type
image/bmpimage/gifimage/jpegimage/png
BMPBMHTMLHTMLHTMLHTML
GIFGIF87aHTML画像HTMLHTML
JPEGxFFxD8HTMLHTML画像HTML
PNG\x89PNG\x0d\x0a\x1a\0aHTMLHTMLHTML画像(*2)
この表から分かることは以下の二点である Content-Typeとマジックバイトは同一の画像フォーマットに対応したものでなければならず、不一致だとHTMLとみなされる(可能性がある) BMP形式に関しては、Content-Typeとマジックバイトの両方を揃えても、なおHTMLとみなされる場合がある なお、マジックバイトのContent-TypeからPNG形式を判定するようになったのは、前述のようにMS07-057(2007年10月10日)適用後のことであるので、ちょうど2ヶ月前からのことである。

対策:ではどうすればよいか

従来、画像XSSの対策には、イメージを他の形式に変換してから元の形式に戻す、あるいは竹迫氏のmod_imagefightのように画像中にXSS防御文字列を挿入するなど、さまざまな手法が提案されている。しかしながら、対策として不十分であったり、画質や処理速度の低下を招くなどさまざまな副作用があった。 マイクロソフトがMS07-057にてPNG画像のコンテンツ種別判定を改善してくれたことから、Content-Typeとマジックバイトの判定のみで、画像XSSを予防できる可能性が高くなった。 これでもまだ、BMP形式については改善がされておらず、画像XSSの危険性が残っている。コレに対しては、BMP形式画像のアップロードを許容する場合はPNGに変換して公開するというガイドラインを提案したい。BMP形式は通常画像が圧縮されていないので圧縮して公開した方が好ましいこと、BMPの特性(色数、可逆性など)はPNGで全てカバーしていることがその根拠である。 結論としては以下のようになる。 画像のマジックバイトとContent-Typeが同一の画像フォーマットに対するものであることを確認する MS07-057を適用する(ようにユーザに促す) 例えば、BMPを避ける。あるいはPNGに変換して公開する。

謝辞:
画像埋め込みのHTML/JavaScriptについては、 はせがわようすけ氏からさまざまな情報を教授いただいた。記して、感謝の意を表する。

脚注
*1:JavaScriptを埋め込んだ画像を作ってみました参照
*2:MS07-057を適用していないとHTMLと解釈される

参考文献:
マイクロソフト セキュリティ情報 MS07-057
2007-07-15 - T.Teradaの日記 - 画像へのPHPコマンド挿入
TAKESAKO @ Yet another Cybozu Labs: LL魂お疲れ様でした[LLSpirit]
yohgaki's blog - 画像ファイルにPHPコードを埋め込む攻撃は既知の問題

本日のツッコミ(全3件)

□ はせがわ (2007年12月10日 13:54)
はてなでの2004年の対策は、MS07-034のmhtml:に対する対策だったはずです。mhtml:をURLに付与することで、あらゆるリソースがRFC557のMHTML形式のドキュメントであると強制可能だったため、画像でも何でもbase64なスクリプトが埋め込み可能でした(なのでスタイルシート内でboundaryを削除している)。IEがContent-Typeを無視するというのとは、表面的・結果的には似ていますが、原理的には異なるものでした。

□ hoshikuzu (2007年12月23日 16:26)
まさしくアレはmhtml対策でした。はてなに報告した人より。

□ えむけい (2008年08月30日 05:49)
IE8でサンプルデータを試してみたらBMPはすべてtext/plainで(JavaScriptは起動せず)、GIF/JPG/PNGはすべて壊れた画像アイコンで表示されました。
ようやく画像XSSも過去のものになりそうです。

2007年11月26日月曜日

DNS Rebinding ~今日の用語特別版~

補足

この記事は旧徳丸浩の日記からの転載です。元URLアーカイブはてなブックマーク1はてなブックマーク2
備忘のため転載いたしますが、この記事は2007年11月26日に公開されたもので、当時の徳丸の考えを示すものを、基本的に内容を変更せずにそのまま転載するものです。
補足終わり


楽天テクノロジーカンファレンス2007にて、カーネギーメロン大学日本校武田圭史先生の講演を聴講して、DNS Rebindingの説明がとても分かりやすかったので、ここに再現を試みる(文責は徳丸にある)。

DNS Rebindingとは

DNS Rebindingは、DNSの返すIPアドレスを巧妙に変化させることにより、JavaScriptやJavaアプレットなどのsame origin policyを破り、インターネットからローカルネットワーク(通常外部からはアクセスできない)などに対してアクセスする手法をいう。

攻撃に必要なもの

攻撃者は、自分のコントロール可能なドメイン名(以下の例ではtokumaru.orgを用いる)を持っているおり、かつそのドメイン名のWebサーバー(以下、罠サーバーと呼ぶ)があること。

攻撃のシナリオ

DNS Rebindingは受動攻撃の一種であり、攻撃者は、攻撃対象にアクセス可能なユーザに対して、メールなどにより罠サーバー(ここでは、tokumaru.org)に誘導する。罠サーバーに誘導された後の流れは以下の通り。

画像の説明 (1)↑tokumaru.org のIPアドレスをDNSに要求
(2)↓210.188.204.136 (TTL=5秒)を返す
(3)↑HTMLコンテンツを要求
(4)↓HTMLコンテンツを返す
(5) 10秒後に、HTML中に埋められたJavaScriptがtokumaru.orgのコンテンツを要求(same origin policyには違反しない)
(6)↑すでにDNSのキャッシュは無効なので、再びtokumaru.org のIPアドレスをDNSに要求
(7)↓今度はプライベートアドレス 172.21.21.11(TTL=1日)を返す
(8)←JavaScriptは、ローカルネットワーク内のWebサーバー(172.21.21.11)にコンテンツを要求する
(9)→ローカルサーバー上のコンテンツが返る
(10)↑form.submit()などを用いて、(9)の情報を罠サーバー(210.188.204.136)に返す

上記のように、DNSのTTLを極端に短く(上記例では5秒)設定することにより、同一ドメイン上のコンテンツを要求する際にDNSサーバーへの問い合わせを再度実行させ、二番目の問い合わせに対しては、攻撃対象(外部からはアクセスできない)のIPアドレスを返すことがミソである。これにより、見かけ上はsame orign policyに抵触することなく、特定のユーザを中継することで、ローカルネットワークなどの資源にアクセスすることができる。

DNS Rebindingについては、金床氏の研究が有名で、Black Hat Japan 2007にて、金床氏の研究が発表された。これによると、JavaアプレットやFLASHのSocketを利用することにより、任意のプロトコルに対しても、ローカルネットワークに対する情報の収集や攻撃などが可能である。 金床氏による、DNS Rebindingのデモページはこちら

対策(DNS Pinningなど)は後で。 tokumaru.orgは単なる例なのに、徳丸浩までなんか悪い奴に見えますね。しまった。

自作コンパイラの部屋 > 用語集 > DNS Rebinding

追記(2010/03/01)

携帯電話の「かんたんログイン」に対するDNS Rebindingによるなりすまし脆弱性については「iモードIDを用いた「かんたんログイン」のDNS Rebinding脆弱性」を参照されたい。また、現実に発見された脆弱性については「ケータイtwitter(twtr.jp)においてDNS Rebinding攻撃に対する脆弱性を発見・通報し、即座に修正された」で報告している。

本日のツッコミ(全7件)

□ yamagata21 (2007年11月26日 11:00)
(7) で レスポンスを TTL=1日にしてしまうと、(10) の情報の送信先が 172.21.21.11 になってしまう気がしないでもありませんw (サブドメインを使い分けるか、TTL を短くするかしないとダメかも知れませんね~。)

□ 金床 (2007年11月26日 11:59)
そこはサブドメ使い分けでしょう(゜д゜)
なんならまったく別ドメでもおk(゜д゜)

□ 徳丸浩 (2007年11月26日 12:28)
金床さんからもコメントありますが、データの戻しにform.submit()を使うという前提であれば、別ドメインでもいいし、IPアドレスでもいいですよね。Formのaction先はsame orign policyの制約を受けませんので。

□ yamagata21 (2007年11月26日 13:15)
図と説明が、罠サーバー(tokumaru.org)宛になってたのでツッコミ入れてみただけです。(^-^;

□ 徳丸浩 (2007年11月26日 20:55)
(10)の中で、罠サーバーにIPアドレスを付記しました。

□ yamagata21 (2007年11月26日 23:44)
お手数をおかけしました~。ありがとうございます♪

□ Hash (2012年11月18日 05:03)
> (7)↓今度はプライベートアドレス 172.21.21.11(TTL=1日)を返す
とありますが, 長い時間を指定するのは何故でしょうか? 5秒から変更する意義がわかりませんでした.

フォロワー