どうしても試験勉強に身が入らないのでちょっと気分転換がてら晒してみるテストでございます。来年度以降セキュリティ&プログラミングキャンプに応募しようと思ってる方はどうぞ。こーんなどーしようもない事書いてても大丈夫です。
もくじ
■セキュリティ&プログラミングキャンプ2010の開催を、何で知りましたか?
- 公式ホームページ
- 先生からの紹介(高校時代に高校のサーバ管理者からの紹介を受けました)
■前提質問(どちらかに○をつけてください)
- [A] ソフトウェアの脆弱性、およびそれらによる攻撃・防御の仕組みに興味がありますか[はい]
- [B] Cやアセンブラによるプログラミングに興味はありますか?[ある]
- [C]キャンプの公式Webページの講義科目に記載されたこの組の講義科目の[概要]と[詳細]と[補足]をよく読んで納得できましたか?[できた]
■この組を希望した自分なりの理由を教えてください。また、何を学びたいか教えてください。(選考上もっとも重視します)
今まで逆アセンブラによる解析を行ったり、それを用いたソフトウェアの移植、ゲーム内データのコンバート、自分のさせたいように処理を改変するパッチの作成、コピープロテクト外し(勿論、ちゃんと買った製品でですよ!;起動時に毎回DVDを入れるのが面倒なもので)、簡単なセキュリティホールの発見や攻撃のデモの作成等を行ってきましたが、どれも攻撃一辺倒で防御側の経験が全くありません。
また、基本的に学習は(ネット上で手に入る教材の多い)コピープロテクト外しやゲームの改造を題材に行ったもので行っており、それ以上の応用は難しく、ウイルスや実際のソフトウェアの脆弱性に基づいた攻撃といった、高度な攻撃手法には全く太刀打ちが出来ませんでした。
そこで、このキャンプに参加することで「実際の攻撃で使われる」実用的な攻撃手法について体系的に学ぶとともに、防御側から見たセキュリティについても考えてみたいと思っています。
正直に言えば、その知識を使って社会の役に立ちたいといった立派な目的とか、あるいは逆に銀行のシステムに侵入して自分の口座に大金を送金したい(笑)といった思いは全くなく、純然たる知識欲、あるいは「ハッカーになりたい」という思いで今回応募させていただきました。実際、プログラムを解析したり、脆弱性の突き方を考えるのが楽しくてしょうがないです。
そういった人の方が純粋な探究心は高いでしょうし、歴史的に言えば、そういった純然たる知識欲からセキュリティ上の悪戯をして逮捕されたハッカーが素晴らしいセキュリティ専門家になることもままありましたから、そういう人が居ても良いんじゃないかと思います。
■プログラミング歴を教えて下さい。また、今までに作ったプログラム (特にシステムプログラム†1)があれば、差し障りのない範囲で具体的に教えてください。
プログラミング暦は10年ほど。
アセンブラからシェルスクリプト、ウェブアプリから組み込み系(主にゲームハード用)まで、言語・ジャンルは何でも書きますが、何かしらのパズルを解くような、アルゴリズムが最重視されるようなプログラムは不得意で、ツールやシステムをいじるようなプログラムをよく書きます。
■ASLRが有効なWindos Vista以降でも実行可能なreturn-to-libc攻撃のサンプル
ASLR(Address space layout randomization)によってライブラリの関数のアドレスは変わっても、アプリケーション内に存在する関数のアドレスは変わらないことを利用した、return-to-libcの攻撃コードです。
アプリに含まれる任意のコードがすべて実行可能になります。
原理や攻撃コードの中身については上記のページをご覧ください。
■はづき
コミケで昔頒布した、HTTP over HTTPなトンネリングソフトです。
高校の時、フィルタリングによって高校のネットワークからニコニコ動画に繋ぐ事が出来なかったので作成しました。
(もちろんニコニコ動画以外にもつなげます)
一回自宅のサーバ(私のblogがおいてあるサーバです)を経由することで、フィルタリングを回避します。
[学校のPC]→→[フィルタリングサーバ] (アクセス制限) [ニコニコ動画] ↓(プロキシサーバとしてアクセス) ↑ [はづきクライアント]→(暗号化)→[自宅サーバで走るはづきサーバ]→↑(代理アクセス)
このはづきサーバはLinuxのデーモンとして実装してあります。
当時の自宅サーバは諸事項でカーネルverが2.4台だったのでプレフォーク型サーバとして実装してあります。
この後、自宅サーバへの異常なトラフィックからサーバ管理者(このキャンプを紹介してくれた人)に見破られ、自宅サーバへもアクセス制限が掛けられて結局使用不能になりました(笑)。
CGIとして実装しなおして複数のフリーウェブサーバに分散して配置し、それらをラウンドロビンして使うといった事も考えましたが、そこまで気合がなかったというのに加え、さすがに負荷が高くフリーサーバでそこまでするのはどうかという思いから断念しました。
■さきゅばす
ニコニコ動画の動画を、コメントを動画に焼きこんで(デフォルトでxvidのaviとして)保存するソフトウェアです。
変換部分はffmpegという有名なオープンソースの動画エンコーダに動画フィルタを追加して実装しています。
この動画フィルタは、ffmpeg.exeに追加したDLLローダからnicovideo.dll(実際のフィルタ処理が書いてある)を動的に呼び出して処理しています。
こうした理由は、ffmpeg.exeが余りにも巨大でリンクに5分以上かかるため、頻繁に更新するフィルタ処理部分をdllで分けたほうが開発時間短縮になるからです。
オープンソース化し、そこそこ人気も出ているようです。
■ZERO
昔つくったオセロプログラムです。Javaで書かれていて、一般的なNegaScoutというアルゴリズムで動いていました。
Yahoo!レーティングで1700(結構上級者)くらいまで行きました。
■ポケモンセーブデータエディタ
GBAの「ポケットモンスター ルビー/サファイア/エメラルド/ファイヤーレッド/リーフグリーン」に対応した、セーブデータの書き換えツールです。
実装に当たってはゲームのROMを吸い出してエミュレータ上でセーブデータの保存処理を解析し、チェックサムを正しく書き換えています。
■巫女が死ぬとファイルが消える東方
ゲームの処理の一部を書き加えた上で自分で書いた処理を付け加え、プレイヤがミスをするとマイドキュメントのファイルが一個ずつ消えていくようにしたジョークプログラムです。緊張感が凄いです(笑)。
注意メッセージの表示部分をつぶしてP2Pに流されると非常に危ないので動画しか公開していません。
なお、脆弱性等は一切使っていません。
■証明写真作成工房
Webアプリです。
自分の顔写真をアップロードして、顔の中心・あご下・頭のてっぺんの位置を指定すると、証明写真を印刷するためのPDFが作られて、それを印刷することで自分で証明写真を作れるサービスです。
grails(フレームワーク) + iText(PDF作成ライブラリ)で実装しています。
■UFO大好き霊子さん
同様にウェブサービスです。使用者が余りにも居なかったのでサーバ更新時に廃止してしまいましたが…。
UFOや心霊、廃墟や超心理学に関する場所をGoogleMapを使って登録して共有し、現地の写真を投稿したりコメントがつけられるサービスです。
ストリートビューとも連携していて、ストリートビューに写っている心霊写真も登録されていたりしました。
■成分解析 for CGI written in C
数年前に流行った「成分解析」という占いプログラムを解析して、CによるCGIに実装したウェブサービスです。
■SynFlood攻撃プログラム
システムプログラムと呼べるかどうかは分かりませんが、ioctlとかを使って生パケットを組み立て送信して、synflood攻撃をするプログラムを書いたこともあります。
勿論、外部に向けて送信しようとしてもプロバイダで弾かれるのでLAN内でしか効果が無いのですが。
またちょっと時間が無くて開発は出来ていませんが、以下のようなプログラムを作りかけています。
■強制Portable化ランチャ(win32)
USBなどにアプリを入れて持ち運ぶ「PortableApps」が最近人気ですが、レジストリに設定を書き込むソフトはそのままではPortableに出来ませんし、「<アプリのフォルダ>/ユーザ名/config」に設定を書き込むタイプのアプリも、PCがわかってユーザ名が変わるとやはり設定が引き継がれません(毎回設定ファイルをコピーすればよいのですが、面倒)。
そこで以下の手順でAPIをフックする事で、レジストリや設定ファイルの書き込みを制御し、Portable化するソフトです。
- スペンドした状態でPortable化するアプリをCreateProcess
- エントリーポイントのコードをを無限ループに書き換え
- とりあえず実行して定期的にEIPを監視
- EIPがエントリーポイントまで行ったらプロセスをサスペンド
- 制御用のDLLを注入
- IATを書き換えてRegOpenKeyExやFileOpenのようなファイル操作関数をフック
- CreteProcessもフックし、Portable化するアプリが子プロセスを作るときも1~6を繰り替えし、子プロセスが読み書きするファイル・レジストリも制御する
フックしたRegOpenKeyExやFileOpenでは、同じフォルダにある設定ファイルに基づいてレジストリやファイルの読み書きを制御し、レジストリはファイルに、設定ファイルもユーザ名の部分を適宜変換して読み書きさせ、他のファイルは普通に元のAPIに処理させます。
XPで1/3開発しただけなのでVista以降だともしかするとUACが必要かもしれません…。
■Prolog on FastCGI(マルチプラットフォーム)
Prologでウェブアプリを作ろう、とふと思い立ちProlog用のFastCGIモジュールを作りました。Apache/Lighttpdで動きます。
サンプルプログラムの「成分解析 in Prolog」は動いているのですが、Webアプリにあると便利な様々な述語が実装しきれていないのでまだ未公開です。
■これまでに開発したプログラムで経験したバグ、およびその影響について差し障りのない範囲で具体的に教えてください。
公開はしていないのですが、開発したシューティングゲームで何故か特定の弾(1~2発程度)の速度が異常に速くなるバグがありました。
原因はいわゆるOff-by-oneで、メモリの配置がちょうど弾の構造体の前のほうにあったデータを長さを超えて書き込んでしまい、ちょうどその「書き込みすぎた」データが弾の速度の領域に被っていて、その書いたデータを速度として読み取ると高速になる、というバグでした。
(静的に確保した領域だったので、メモリの配置が毎回ほぼ一緒でした)
デバッガーを使ってメモリの状態を監視することでやっと発見することが出来ました。
他には「成分解析 for CGI written in C」で入力したテキストの<や>を実態参照に変換し忘れて表示していて、XSSが可能になっていたというバグがありましたが、使われる前に気づいたので無事でした。
あとは条件分岐でa == b && (e == c || d == f)の、括弧を付け忘れて分岐が狂ったり、
void** ptr; Object* ptr2 = (Object*)ptr;
と*を付け忘れてクラッシュしたり、malloc(size)としたらsize = 0のときにNULLが帰ってきてクラッシュしたり、といったバグは経験した事がありますが、脆弱性となるようなバグは今のところ経験した事がありません。(たぶん発見されていないだけですが)
このように、全体的に防御する側の経験が不足しています。
■セキュリティホールは放置しておくとなぜ危険なのでしょうか。自分の言葉で説明してください。
それは、コンピュータはプログラマの忠実なしもべであるはずだからだと思います。
つまり、コンピュータはプログラマという主人の命令に忠実に働く、信頼できる最高の奴隷である、と私は考えています。
その信頼関係があるからこそ、勝手にレジのお金を盗むアルバイトと違って大事なデータも預けられるし、大事なお仕事も代行させられるのだと思います。
それが脆弱性によってコンピュータが攻撃者の命令も聞くようになってしまったり、喋ってはいけない情報を無理やり喋らされてしまったりすることで、主人(プログラマやプログラムを使う人)と奴隷の信頼関係の前提が根本から失われてしまうから、ではないでしょうか。
(逆に、だからこそセキュリティホールを突いたりゲームを改造したりコピープロテクトを外したりするのが楽しいと感じる人が多いのだと思います)
■ソフトウェアの脆弱性をなくすには何が必要でしょうか。
短期的には、ソフトウェアを開発するときはできるだけリッチで枯れたライブラリに任せ、”できるだけプログラムを書かない”ことだと思います。
これは車輪の再発明による開発効率の低下を防ぐ意味もありますが、何よりプログラムが短ければそれだけバグも生まれなくなるはずです。
特にソートやデータ構造や文字列操作は自分で書く利点はありませんし(とくにマルチバイト文字列)、絶対にライブラリ任せにした方が良いと思います。
(練習として書いてみる分には悪くないとおもいますが)
■
長期的には、プログラマはミスをする、という事を前提に対策するしかないと思います。
バッファオーバーフローならJavaやC#みたいに毎回配列を超えていないかをチェックする事で完全に防げますし、NXビットを使えば仮にスタックオーバーフローしてもスタック上にシェルコードを置いて実行させる手法は非常に難しくなります。
ハードウェアやカーネル、実行処理系で注意深く対策し、その上で動く大多数のプログラムはバグが発生してもセキュリティ上の問題までは至らない、という方向に持っていくほか無いように思います。
■
これでも防げない攻撃はあると思います。
前調べたあるWebの予約管理システムで、ユーザIDとパスワードのチェックはログイン時にしかしておらず、その上さらセッションIDもなく、GETリクエストにユーザIDを入れてユーザを識別しあとはノーチェック(だからそのGETリクエスト先に直接アクセスすればパスワード無しで他人のアカウントをのっとり放題)という、にわかには信じがたいシステムがありました。
この問題自体は確かにWebアプリのフレームワークを用いれば解決できますが、この問題の本質はフレームワークを使っていない事でも、セッションIDがない事でも、ログイン時にしか認証していない事でもなく、プログラマの想像(この場合は「ログインページで認証したのだから、ユーザの個別ページには入れないはずだ」)を超えた、正規の手段(「別にログインページを通過しなくてもユーザ別のページにアクセスできる」)が実は存在した事なのだと思います。
フレームワークの範疇を超えた範囲でのこういった、プログラマの想像を超えるようなセキュリティホールは無くならないだろうと感じました。
これに関してはまだ解決策が見えていないというのが率直なところです。
■あなたがある程度読み書きできるプログラミング言語を書いてください。(いくつでも可)
手続き型でしたら、他の言語に移植する程度であれば大体読めます。
特にある程度頑張って読み書きした事があるのは以下でしょうか。
アセンブラ:x86 / ARM / H8
Java / C / C++(「何でも出来すぎる」ので機能を絞って利用している) / Objective-C / Ruby / PHP /
Groovy / SQL / JavaScript / ActiveBasic
Prolog
Brainfuck(笑)
ニワン語(現在処理系を実装中)
■そのほかアピールしたいこと、書き足りないことがあれば自由に書いてください。
小さいときに魔法少女アニメを見て魔法使いになりたいと思ったものの、現実世界に魔法は存在しなかったので、変わりに電脳世界の魔法使いだと思ったハッカーになりたいと思い、コンピュータを始めました(笑)。
「電脳コイル」が現実になり、電脳世界と現実世界の境界が曖昧になってくれば私の最初の夢に近づいていくのに。
こういう変り種が居ると面白くなると思いますよ!
- †1: システムプログラムとは、WindowsのDLLやLinuxのデーモン、各種デバイスドライバやカーネルモジュールなどを指します。