2013/05/28

上野宣さん著の「HTTPの教科書」

今日は本の紹介です。
上野さん(@sen_u)著の「HTTPの教科書」が発売されました。

http://www.amazon.co.jp/HTTP%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E4%B8%8A%E9%87%8E-%E5%AE%A3/dp/479812625X/



この本の原稿のチェックを山崎さん(@ymzkei5)・はせがわさん(@hasegawayosuke)と一緒にやらせて頂きました。

きっかけは、以前上野さんに献本して頂いた、上野さん監修の「めんどうくさいWebセキュリティ」 です。誤植が結構あったので結構な数を報告していたら、次また本を書くから見てよ、とお話を頂いたというわけです。


「HTTPの教科書」は、通信の方法から個別のHTTPヘッダ・ステータスコードの意味など、HTTPに関する技術を一通り説明してくれます。易しい文体で図も多用されており、とても読みやすいです。また、新しい技術についても一部扱っています。
これからHTTPを学ぼうとする初級者や、よくわからないままなんとなく使ってきたという方に特に適していると思います。

僕も、誤植に関して言えば、かなり慎重にチェックし、修正のお手伝いができたと思います。
まぁ、残念ながら目次に誤植がありましたが…

Webに関わる人のための『HTTPの教科書』を発売 - うさぎ文学日記
http://d.hatena.ne.jp/sen-u/20130521/p1
※初版は目次内に間違えている部分があります。

この件は、本になって手元にきたあとに僕が発見したのですが、目次のステータスコードとメッセージの対応が間違っている(それも見事にすべて!)というものです、なんでこんなことに…!
目次はレビュアーで共有しなかったため、印刷前に誤りを発見することができませんでした。ここは残念ですが、他の部分については、厳しくチェックしたつもりなので安心してください!

素晴らしい本の制作にかかわれたことを嬉しく思います。
上野さん、貴重な体験をさせて頂きありがとうございました。

2013/04/26

Flash動画プレイヤー「ふらだんす」に存在したXSSから学ぶ、FlashのXSS3パターン

ストリーミング・ジャパンが以下のURLで提供しているFlash動画プレイヤーの「ふらだんす」に存在し修正された、僕が報告した3件のXSSについて書きます。

http://www.streaming.jp/fladance/

更新しましょう
 
2013年4月12日に提供されたバージョン 2.1.5以降 を使っていなければXSSの穴をサイトに作っていることになります。一応「ふらだんす」の上で右クリックすると使っているバージョンがわかるので脆弱かどうか確認できますが、こういったFlashの動画プレイヤーの更新情報をちゃんとチェックしている人はほとんどいないと思うので、最近導入した人でなければまず脆弱なものを使っていると思います。心当たりがある人は「2.1.5」に更新しましょう。あるいは使っているサイトをみかけたら教えてあげましょう。
これ以降は技術的な話です。

技術的な話
 
あらかじめことわっておくと、僕はFlashに関してまったく詳しい訳ではないんですが、Flashのセキュリティについてまとめられた日本語の記事がウェブ上に少ない(例えばExternalInterface.call()を使うのにセキュリティ上注意が必要なことについて書かれた記事がほぼみつからない)かんじがするし、「ふらだんす」に存在した3件のXSSは生じ方がそれぞれ違い、サンプルとしてちょうどよいので、この機会に自分のわかる限りの範囲でどのようにXSSが生じたか書いておきたいと思います。

脆弱な「ふらだんす」のソースコードは以下で見ることができます。
http://www.showmycode.com/?b1fb4e4666bc1067ef9f9d40d2950245

1. navigateToURL() によるXSS

「ふらだんす」2.1.3未満は以下のようなリクエストにより、動画の再生後に表示される「LINK」ボタンをクリックするとJavaScriptが動作してしまいます。(※検証したところ、Firefoxでしか動作しませんでした。どうもnavigateToURL()のターゲットが_blankに指定されている場合、Firefox以外のブラウザではjavascript: URLに対してナビゲーションを起こさないようになっているようです。)

http://vulnerabledoma.in/fladance_v2-1-1.swf?video_file=http://vulnerabledoma.in/security/sample.mp4&link_url=javascript:alert%28window.opener.location.href%29

navigateToURL()で、link_urlというパラメータに設定されたURLにリダイレクトするようになっており、この時渡される文字列が一切検証されていなかったため、XSSが起こせていました。
navigateToURL()に渡すURLを検証しないと、XSSに繋がる場合があることは公式のドキュメントにも書かれています。

http://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/flash/net/package.html#navigateToURL()

修正後は「http(s)://」から始まるURLのみリンクを許可するようになったようです。

2. htmlTextプロパティによるXSS

「ふらだんす」2.1.5未満は以下のようなリクエストで、swf上に表示されている「CLICK」という文字列をクリックするとJavaScriptが動作してしまいます。
http://vulnerabledoma.in/fladance_v2-1-1.swf?controllbar=%3Cfont%20size=%2250px%22%3E%3Cbr%3E%3Ca%20href=%22javascript:alert%28location%29%22%3ECLICK


パラメータで使用する文字列が誤っている場合に表示されるエラーメッセージ中で、htmlTextプロパティというHTML形式で文字列を表示するプロパティを使用してパラメータ中の文字列をそのまま書きだしていたため、XSSが起きていました。htmlTextプロパティでは、全てのHTMLタグを使える訳ではありません( サポートされているタグは http://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/fl/text/TLFTextField.html#htmlText を参照 )が、少なくともaタグの記述をサポートしており、javascript: やvbscript: などのリンクを作成することができるため、任意の値が書けるとXSSを引き起こせてしまいます。

修正後はエラーメッセージ中にパラメータの値を表示しなくなったようです。

3. ExternalInterface.call() によるXSS

「ふらだんす」2.1.5未満は以下のようなURLでXSSが起きます。
http://vulnerabledoma.in/fladance_v2-1-1.swf?debug_mode=\%22%29%29}catch%28e%29{};alert%281%29//

debug_modeというパラメータがあった場合にExternalInterface.call()という、FlashからJavaScriptを呼び出す関数を使用していました。ExternalInterface.call()は第1引数に実行するJavaScriptの関数、第2引数にその関数の引数を設定して使用します。
「ふらだんす」では第1引数にconsole.log()、第2引数にURLのクエリ文字列を設定してJavaScriptを実行していました。これだけ聞くとconsole.log()を使ってコンソールにクエリ文字列の値を書きだせるだけで特に問題がなさそうに聞こえるんですが、ExternalInterface.call()には知る人ぞ知るXSSを作りやすい問題があり、今回まさにその問題の影響を受けていました。

ExternalInterface.call()でFlashがどのようにJavaScriptを実行しようとしているかは、このXSSを作りやすい問題によって実行エラーを引き起こしたFirefoxのエラーコンソールから垣間見ることができます。

http://vulnerabledoma.in/fladance_v2-1-1.swf?debug_mode=\%22



FlashがJavaScriptの実行時に内部で生成していると思われるJavaScript中で、「"」は「\"」と処理されて渡されているのに対し、「\」は「\」としてそのまま渡されています。これにより「\"」を引数として渡すことで「\\"」という文字列がこの処理に渡り、「"」のエスケープシーケンスが無効化されて途中で文字列リテラルを区切ることになり、画像のようなエラーとなるという訳です。XSSを起こすときには、最初に示したURLのようにtry-catch文をエラーがでないように適当にあわせて、後ろに任意のスクリプトを書いてしまえばいいだけです。このExternalInterface.call()の実装はあまりにひどいですが、この問題の報告者によるとAdobeは「後方互換性のために変更しない」と返事したと言っており( 報告者のブログ http://lcamtuf.blogspot.jp/2011/03/other-reason-to-beware-of.html または 報告者が原著の「めんどうくさいWebセキュリティ」p178を参照 )、Flashファイルの作成者側で「\」を処理するなどして気をつけるしかなさそうです。

修正後はコード中でExternalInterface.call()を使わなくなったようです。


はい!以上です。
忘れがちだけどFlashもXSSとは無縁ではないので注意が必要ですね。

2013/03/05

各ブラウザがサポートするcharsetのリスト

メジャーブラウザがサポートするcharsetのリストを個人的に調べてまとめたので公開します。

正式名とエイリアスのリスト
http://l0.cm/encodings/list/

表にしたもの
http://l0.cm/encodings/table/

charsetの発見は以下のようにして行いました。

1. charsetとして認識してくれそうな文字列をウェブからかき集める。

2. Content-Typeヘッダのcharsetの値に、集めた文字列から1つ選んで指定し、bobyには、<meta charset="iso-2022-jp">を含んだページを作る。

3. 2で作ったページをフレームに読み込み、親フレームからJavaScriptでフレームに設定されたcharsetの値を読み取る。

4. 取得されたcharsetの値により以下のAかBの判断/処理をする。

A. iso-2022-jp以外が取得された場合:
Content-Typeに指定した値がcharset名として識別された。charsetとして有効な文字列であると判断する。

(注: こう判断する理由として、bodyでの指定よりもヘッダでのcharset指定が優先されることが前提にある。Content-Typeヘッダで有効なcharsetの値が指定されているから、bodyで指定しているiso-2022-jpがスルーされていると判断できる。)

B. iso-2022-jpが取得された場合:
2つの可能性が考えられる。

・Content-Typeに指定した値がiso-2022-jpとして識別された。
・Content-Typeに指定した値はcharset名として識別できない値であり、代わりに<meta charset="iso-2022-jp">指定によりiso-2022-jpが設定された。

 どちらかを判断するために、今度は、Content-Typeのcharsetには同じ文字列を設定するが、bodyには<meta charset="iso-2022-jp">指定がないものをフレームに読み込み、手順3と同じように親フレームからcharsetを取得する。このとき、

iso-2022-jpが取得されれば、Content-Typeに指定した文字列はiso-2022-jpを指している値と判断する。
iso-2022-jpが取得されなければ、Content-Typeに指定した文字列はcharset名として識別できない値と判断する。
  

5. charsetとして識別できた値について、それがエイリアスなのか、正式名なのかを調べる。JavaScriptで取得される値(document.charsetやdocument.characterSet)は、エイリアスでなく正式名で取得されるので、JavaScriptで取得された値とContent-Typeのcharsetに設定した文字列を比較して、同じなら正式名、異なるならエイリアスと判断する。


こんなかんじです。2-5は適当なスクリプトを書いて、チェックする文字列を変えて繰り返しました。これでうまく判別できない例外も一部ありますが、そこは個々に別のテストを行ったりして対処しました。

おそらく、各ブラウザがサポートするエンコーディング・エイリアスをまとめた資料としては、現在ウェブで公開されているものと比べても、情報が新しく、かなり網羅されたものになっていると思います。いろいろな使い道があると思います。どうぞ、研究などにお役立てください。既に僕も、調べたエンコーディングを使って、様々なエンコーディングのテストを行いました。その辺りの結果も近いうちに公開します。
ブラウザのサポートに変更があったり、データの抜けに気付いた場合は、ぜひコメントやTwitterなどで教えてください。