[-]=======================================================================[-] Wizard Bible vol.34 (2007,6,12) [-]=======================================================================[-] x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ---- 第0章:目次 --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ○第1章: XHRのリバースエンジニアリング 金床 著 ○第2章: チームチドリのチャレンジCTF2007! 〜超速報版〜 tessy 著 ○第3章: はじめてのハッキング 〜ハードウェアの基礎〜 Defolos 著 ○第4章: デフラグさんの作り方 Kains 著 ○第5章: ハニーポットを作ろう(連載第13回) Narusase 著 ○第6章: 基礎暗号学講座 〜 第10回 〜 IPUSIRON 著 ○第7章: お知らせ ○第8章: 著者プロフィール x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第1章: XHRのリバースエンジニアリング --- 著者:金床 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  XHRとはXMLHttpRequestのことである。これを使うと、ウェブページ中に埋め込 まれた次のようなJavaScriptのコードにより、比較的自由度の高いHTTP通信を行 うことができる(このコードはIEでのみ動作する)。 ----- var request1 = new ActiveXObject("Microsoft.XMLHTTP"); request1.open( 'GET', 'http://www.jumperz.net/index.php',false ); request1.send( null ); alert( request1.responseText ); -----  しかしXHRが存在することで、ウェブアプリケーションにXSS脆弱性が存在する 場合、XHRにTRACEメソッドを送信させることでXST(Cross Site Tracing)攻撃が 可能となる。この場合、Basic認証の情報やHttpOnlyで発行されたCookieが攻撃者 に奪われる可能性がある。そのためFirefoxやOperaの最近のバージョンではXHRを 使用する際にメソッドとしてTRACEは指定できないようになっている。IEでも同様 に比較的新しいバージョンではTRACEが禁止されている。  また、メソッドと同様に、XHRの送信先となるポート番号もセキュリティ制限の 対象とすべきだ。例えば25番ポートに接続できてしまうと、XHRを悪用してスパム メールを送信されてしまう(ユーザのブラウザにスパムメールを送信させる)可 能性が考えられる。つまり次のようなコードは失敗するべきと考えられる。 ----- request1.open( 'GET', 'http://www.jumperz.net:25/index.php',false ); -----  さてこのように ・TRACEメソッドは禁止 ・ポート番号について、例えば25番などは禁止 というセキュリティ制限がかけられているXHRだが、どうもIEについてはこの制限 のかけ方がお粗末であるように思える。そこで今回はリバースエンジニアリング 祭りをおこない、IEのXHR実装がどこでどのように行われているのかを調べてみた。 ■0x02.) メソッドの制限  TRACEメソッドを禁止するべき場所はopen関数の第1引数だ。この引数はずばり HTTPリクエストのメソッドを指定するもので、普通はGETやPOSTが指定される。H TTPのメソッドというのはアルファベットの大文字と相場が決まっているので(よ い子は相場じゃなくてRFCを見てくだちい)、とりあえずまともなプログラマーな ら[A-Z]{1,20}のような感じで入力をチェックし、その上で「TRACE」ではないこ とを確認するだろう。  しかし、さすがマイクロソフト様。なんと次のようなおどろきのコードでTRAC Eが飛んでしまうのだ。 ----- request1.open( '\nTRACE', 'http://www.jumperz.net/index.php',false ); -----  この場合、送信されるTCPのデータストリームの内容は最初に余分な1バイト( 0x0D)が付いたTRACEメソッドのHTTPリクエストとなる。しかしApacheやIISはこ れを受け付けてしまうため、XSTは成立してしまう。つまりこのIEのXHRにおける TRACEの禁止は、簡単に回避されてしまうのだ。  さらにひどいことに、次のようなコードさえ動いてしまう。 ----- var method = "GET\x09/index.php\x09HTTP/1.0\r\nHost:hogehoge\r\nX-Foo:"; request1.open( method, 'http://www.jumperz.net/index.php',true ); request1.send( null ); -----  このテクニックを使うとクライアントサイドでのHRSをはじめ、様々な問題が引 き起こされるだろう。 ■0x03.) ポートの制限  FirefoxやOperaではXHRで接続可能なポートについても厳しく制限しており、ス クリプトを含むページと同じポートにのみ接続可能のようだ。しかしIEではこの 実装も奇妙であり、21番ポートや25番ポートには接続できないのだが、22番ポー トや23番ポートには接続できてしまう。接続できたからといってそれほど深刻な 問題が発生するわけではないのだが、メソッドの禁止の実装と同じく、どのよう に実装されているのかが気になるところである。 ■0x04.) 祭り開始  まずはIEにおけるXHRの実装がどのDLLで行われているのかを調べてみることに した。system32ディレクトリにおいて「grep -i xmlhttprequest *.dll」として みると、msxml3.dllなどのいくつかのDLLファイルがヒットする。  TRACEの禁止が明示的に行われているようであれば「grep -i trace msxml3.dl l」でヒットしそうに思えたが、これはヒットしない。またTRACEというのはよく 使われる単語なので、「grep TRACE *.dll」などとしてしまうと大量のDLLファ イルがヒットしてしまい、結局どのDLLにおいてTRACEの禁止が実装されているの かはわからない。  そこでDependency Walkerというツールを使ってmsxml3.dllが依存しているDLL をリストアップしてみることにした。リストアップされた中で、まずはwinhttp. dllというファイルが怪しいように思えた。しかしこのファイルの中身をTRACEで 検索してみても「ERROR_SYSTEM_TRACE」という文字列がヒットするだけで、TRAC Eメソッドの制限が行われているわけではないようだ。そこで、次に怪しいと思わ れるwininet.dllを調べてみた。するとHttpOpenRequestという関数の中で、それ らしい箇所を見つけることができた。 ----- 7667421E 8B35 B4136676 MOV ESI,DWORD PTR DS:[<&SHLWAPI.StrCmpNIA>] ; SHLWAPI.StrCmpNIA 76674224 6A 05 PUSH 5 76674226 68 58426776 PUSH WININET.76674258 ; ASCII "TRACE" 7667422B 53 PUSH EBX 7667422C FFD6 CALL ESI 7667422E 85C0 TEST EAX,EAX 76674230 0F84 DBC30100 JE WININET.76690611 76674236 6A 05 PUSH 5 76674238 68 50426776 PUSH WININET.76674250 ; ASCII "TRACK" 7667423D 53 PUSH EBX 7667423E FFD6 CALL ESI 76674240 85C0 TEST EAX,EAX 76674242 ^0F85 09F5FFFF JNZ WININET.76673751 76674248 E9 C4C30100 JMP WININET.76690611 -----  このように、StrCmpNIAというAPIを使って何か(おそらくユーザが指定したメ ソッド)と「TRACE」という文字列を比べているのである。「ビンゴ!」というや つだ。  さて「これは何だ?」と思ったのは「TRACK」の部分である。TRACEと同様に、 TRACKというメソッドも禁止しているのだ。そこでウェブを検索してみると、どう やらIISのオリジナル実装で、TRACEと同様の働きをするHTTPのメソッドというこ とである。XSTではTRACEと同様にTRACKも問題になる、と指摘している文章を見つ けることができた。TRACKというメソッドの存在は知らなかったので、これは勉強 になった。  ここでStrCmpNIAの第3引数として「5」を指定している(PUSH 5の部分)ので、 文字列の比較は5文字目までしか行われない。そのため面白いことに、ユーザが「 TRACEAAAA」や「TRACKBBBB」のような文字列を指定した場合にも、これは禁止さ れる。 ■0x05.) 一般の開発者を無視した実装  さて鋭い読者なら同様の疑問を持っているかと思うが、この実装には大きな問 題が存在している。TRACEとTRACKの禁止は明らかにXST対策である。XST対策はIE のXHRの実装に対して行われるべきだが、実際にはwininet.dllの中で行われてし まっている。  wininet.dllというのはIE以外のソフトウェアからも利用されるライブラリであ り、一般のアプリケーション開発者がHTTPクライアントを作る際にも利用する可 能性が高い。これは例えば次のようなコード(本稿を書く際に使ったもの)で行 われる。 ----- #include #include #include int main( int argc, char* argv[] ) { HINTERNET hInternet; HINTERNET hSession; HINTERNET hReq; hInternet = InternetOpen( "TEST", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 ); hSession = InternetConnect( hInternet, "www.jumperz.net", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 ); hReq = HttpOpenRequest( hSession, "TRACE", "/index.php", NULL, NULL, NULL, 0, NULL ); if( hReq == NULL ) { printf( "null" ); } InternetCloseHandle( hInternet ); InternetCloseHandle( hSession ); InternetCloseHandle( hReq ); return 0; } -----  wininet.dllの中でTRACEとTRACKが禁止されてしまったため、一般の開発者が作 成するIEとは関係のないHTTPクライアントアプリケーションも影響を受けてしま う。つまりこれらのアプリケーションからもTRACEやTRACKの送出が禁止されてし まうのだ。これは開発者を無視した暴挙であるように感じる。TRACEを送出するよ うな専用のクライアントアプリケーションがそれほど多く存在しているとは思わ ないが、本来ならばmsxml3.dll内などで実装すべき処理である。 ■0x06.) ポートの制限  ポートの制限についても同様にwininet.dll内で行われていることがわかった。 これは以下の箇所である(ちなみにこちらは少し古いマシンで調査したので、0x 04で示したリストとはDLLのバージョンが異なる)。 ----- 7020DDAA 0FB74424 04 MOVZX EAX,WORD PTR SS:[ESP+4] 7020DDAF 83E8 00 SUB EAX,0 7020DDB2 74 1E JE SHORT WININET.7020DDD2 7020DDB4 83E8 15 SUB EAX,15 7020DDB7 74 19 JE SHORT WININET.7020DDD2 7020DDB9 83E8 04 SUB EAX,4 7020DDBC 74 14 JE SHORT WININET.7020DDD2 7020DDBE 83E8 55 SUB EAX,55 7020DDC1 74 0F JE SHORT WININET.7020DDD2 7020DDC3 83E8 09 SUB EAX,9 7020DDC6 74 0A JE SHORT WININET.7020DDD2 7020DDC8 83E8 18 SUB EAX,18 7020DDCB 74 05 JE SHORT WININET.7020DDD2 7020DDCD 33C0 XOR EAX,EAX 7020DDCF C2 0400 RETN 4 -----  7020DDB4の15は10進数で21である。EAXにはユーザが指定したポートが入ってお り、まず21を減算してそれが0であるかどうかを調べている。つまりユーザがFTP のポートである21を指定した場合にはここで引っかかる。つぎにさらに4を減算し てそれが0であるかどうかを調べている。つまりSMTPのポートである25を指定した 場合にはここで引っかかる。以下同様に比較が行われており、結果として禁止さ れているポートは21/25/110/119/143(FTP/SMTP/POP3/NNTP/IMAP)であることが わかった。  ちなみにこの箇所については、0x05で示したソースコードの80の部分(ポート 番号)を接続可能なポート(22番など)と接続が禁止されているポート(21番な ど)に変更したexeをそれぞれOllyDbgでトレースしてログを取り、ログの内容を 比較することで特定することができた。メソッドの制限はただ単に「TRACE」とい う文字列を検索するだけで見つけることができたが、こちらは少々手間がかかっ た。  このように、ポートについてもメソッドの場合と同じようにwininet.dll内に直 接制限が設けられている。しかしHTTPクライアントが21番ポートなどに接続した い場合というのはあまり考えられないので、メソッドとは異なり、こちらの副作 用はほとんどないと考えられる。 ■0x07.) 祭りの後のまとめ  今回はIEのXHRの挙動について、実装を行っている箇所をひとりリバースエンジ ニアリング祭りによって特定し、実際に読んでみることで、どのようにセキュリ ティ制限が行われているのか、またその影響などを把握することができた。開発 者を無視して強引に(しかも不完全に)TRACEを禁止するというマイクロソフトの 手法は衝撃的ですらある。筆者は元々WININETのようなMS依存のライブラリの利用 は避けているが、これはやはり正解であったと思うことになった。  ところでKG先生主催のリバースエンジニアリング祭りが秋にも開催されるとの ことなので、国内最高レベルのリバースエンジニアリング関連情報を提供するWi zard Bibleの読者・著者の皆様にはふるって参加していただきたい。筆者は今回 ついにOllyDbgでのトレースログの取り方を覚え、また本稿のネタを調べるのに丸 一晩かかったほどのハイスキルなので、参加しても学ぶべきことがあるか疑問だ が、いちおう参加しようと思っている。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第2章: チームチドリのチャレンジCTF2007! 〜超速報版〜 --- 著者:tessy x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  チームチドリのtessyです。  今年もチームチドリでDEFCONで開催されるCTF(Capture The Flag)の予選に参 加しました。今年の問題の傾向や、感想などを簡単に速報版としてご紹介したい と思います。  昨年の参加の模様はチームチドリのサイトで公開しています。競技ルールの基 本的な部分はこちらを参考にしてみてください。 http://www.t-dori.net/modules/bwiki/index.php?ctf2006%20qualification%20report ■0x02.) 予選の状況と結果  今年の予選期間は2007/6/1 22:00(EST)〜2007/6/3 22:00(EST)。日本時間では 6/2の12:00(土)〜6/4 12:00(月)になります。普通は月曜は学校や仕事があるので 日本から参加するにはちょっと不利ですね。  今年のチームチドリの成績は、最終的に3900点を獲得し27位でした。予選参加 のために登録されたアカウントは200以上あったみたいですが、実際にゲームに参 加したのは160アカウントほど。また、その中の捨てアカウントと思われる分を差 し引いても参加チームの中では半分よりは上位になっていたかな?と思っていま す。予選通過の7位まではまだまだ遠いですが…  また今年は参加チームが多かったためか、競技の開始時間になってもスコアボ ードサーバにログインできない状態になっていました。ようやくログイン画面に たどりつくも、事前に登録したアカウントが無いと言われる状態。開始早々に「 アカウントが無くて敗退」となりかけたのですが、メンバーが取得しておいたい くつかのアカウントのうち1つだけが使えて事なきを得ました。競技開始から4時 間ほどで、サーバのほうも安定し無事に正規なアカウントを取得することができ ました。 ■0x03.) 今年の問題傾向  出題された問題は去年と同様に5ジャンルあり、各ジャンルことに100〜500点の 5つの問題が用意されています。基本的なルールは昨年と同じですが、今年は一部 ルールが改正され、回答できない問題や問題を放棄した際に減点されることがな くなりました。また複数の問題が同時に見ることができるようになりました。何 人かで集まってやっている際に、各自が得意な問題に取り組むことができるため、 効率的に問題を解くことができます。本当は自分の不得手な分野の問題を選んだ ときに退屈しなくていいというのが大きいです。  また、今年は問題の選択方法に趣向が凝らしてありました。競技開始時にはWe b Hackingの100の1問だけが選択可能な状態になっており、これに一番最初に解答 したチームが次の問題を選択できるようになっていました。以後新しく選択され た問題がリード問題となり、それを解答したチームが次の問題を選択する権利を 得ていきます。上位チームはリード問題を取り合ったりとアツイ攻防があったと 思われます。まあ、実際には上位チームでも選択した問題の難度が高いとなかな か問題が進んでいかないという状態であり、Potent Pwnablesは後半になるまで1 00の問題すら選択できない状態でした。結局、今年はすべての問題を正解したチ ームがいなかったようで、昨年より難易度が上がっていたのではないかと思われ ます。  以下に、各ジャンルごと簡単な解説と感想などを紹介したいと思います。 ●Trivia  ハッキング、ネットなどの雑学問題。昨年は意味のわからない問題ばかりでほ とんど回答できない問題ばかりでした。今年は検索などを活用すれば解ける問題 ばかりで、このジャンルについては難易度は下がったかなと思います。100〜500 まですべて解くことができました。 ●Web Hacking  Webに関する問題。今年は仮想ショッピングサイトのようなところから答えを得 る問題でした。解答に必要な技術もセッションハイジャック、Blind SQL inject ion、MySQLのハックと多岐に渡っており確実に昨年より難易度が上がったと思わ れる分野でした。昨年は全問正解をしたのですが、今年は100・200・400しか解け ませんでした。 ●Forensics  ファイルをもとに解答を探す問題。昨年は音声データの解析問題で皆目が点に なった分野ですが、今年は画像、ファイル、ディスクイメージの解析、暗号解読、 メモリデータ解析と比較的素直な出題でした。出題の意図が読めないものを除い て、100・200・400・500を解くことができました。 ●Binary Leetness  バイナリ解析の問題。与えられたファイルの中から答えを探します。なかなか 選択できるようにならかったというのもありますし、400を解答できたのが5チー ム、500はどのチームも解答できなかった点からみて、難易度が高かった分野だと 思います。100と300だけ解答できました。 ●Potent Pwnables  リモートexploitの問題。サービスとして稼働するファイルが提供され、それを 解析しながら実際に攻撃を行い答えを得ます。今年は時代の流れかIntel Macで稼 働するサービスを攻撃する問題もありました。このジャンルは問題が選択できる ようになったのが遅かったこともありますが、結局100だけしか解答できませんで した。 ■0x04.) まとめ  2回目の挑戦で昨年の予選参加によってコツをつかんでいてスムーズに進めた部 分もありますが、Binary LeetnessやPotent Pwnablesなど課題となっている弱い 部分がそのままだったのはやはり反省点でした。そのほか今年は暗号に関する問 題がいくつか見られました。こちらの方面なども知識としては広げていかなけれ ばと思った次第です。  実際に出題された問題や解説は以下のサイトで公開されています。この文章を 執筆している時点では解説はまだ途中までしか公開されていない状態ですが、そ のうち全部の解説が公開されると思います。実際に問題で使用したファイルも公 開されていますので、手を動かして問題を解いてみると面白いと思います。 http://nopsr.us/ctf2007prequal/  競技時間の48時間という限られた中で、集い合った仲間同士で寝食を忘れて取 り組み、世界中のハッカー達と腕を競い合えるというのは非常に刺激的です。来 年は是非とも皆さんが体験してみてください。 ■0x05.) おまけ  競技期間中のチャットサーバに「orz」「iiyama」とちょっと気になるアカウン トを見つけました。もしかして我々以外にも日本人の参加者がいたのかも? も しこれ読んでいたら是非とも連絡ください(笑)。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第3章: はじめてのハッキング 〜ハードウェアの基礎〜 --- 著者:Defolos x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  今回も基礎知識の確認を行います。プログラムの動作を物理的に実現するハー ドウェアの基礎知識を確認します。バッファオーバフローやその他のハッキング 技術と特に関係性の深いメモリとCPU(演算装置)の動作を中心に説明します。  ハッキングというとソフトウェアの話であって、ハードウェアとはまったく関 係が無いと思われがちです。しかし、実際にはハードウェアの特性を知った上で、 その設計上のミスをうまく利用する必要があります。ゆえに、ハードウェアに対 する理解は決して軽視するべきものではありません。  ですので、今回はハードウェアについて簡単におさらいしてみましょう。 ■0x02.) コンピュータの5大装置  コンピュータはいくつかの機能を持つ装置が寄り集まってできています。コン ピュータには主に入力機能、記憶機能、演算機能、出力機能、制御機能の5つの機 能が備わっており、それぞれの装置が機能を実現しています。 +--------+ +^^^^^^^^^|制御装置|^^^^+^^^^^^^^^+ ^ +--------+ ^ ^ ^ ^ ↑ ^ ^ +---^----+ +--^-----+ ^ +----^---+ |入力装置|-→|記憶装置|-----^--→|出力装置| +--------+ +--------+ ^ +--------+ ↓ ↑ ^ +--------+ ^ |演算装置|^^^^^+ +--------+ * ------ :データの流れ * ^^^^^^ :制御の流れ ●入力装置  データやプログラムを取り込むための装置です。キーボードやマウスとしてユ ーザからの命令を受付たり、ハードディスクからプログラムを読み込むための装 置です。 ●記憶装置  記憶装置は主記憶装置と補助記憶装置に分けられます。主記憶装置はメインメ モリと呼ばれ、プログラムを一時的に記憶してCPUへ引き渡す役割を持ちます。主 記憶装置は値段の問題や容量、電源を切るとデータが消える(発揮性)ために補 助記憶装置とあわせて使用する必要があります。補助記憶装置はHDDやCD-R、フラ ッシュメモリなどが挙げられます。人に例えるなら、CPUが脳の考える部分、メイ ンメモリが脳の記憶部分、補助記憶装置がノート・メモに例えられます。 ●演算装置  CPU(Central Professing Unit)と呼ばれる装置です。実際の演算を行う装置 であり、計算・比較・判断などを行います。演算装置には情報を保持しておく機 能はないので、記憶装置を用いて演算する情報を保持します。 ●出力装置  計算結果などをユーザに通知する装置です。ディスプレイやプリンターなどが 挙げられます。 ●制御装置  他のすべての装置に働きかけ、データの流れの制御などを行います。CPUとして 実装されていることが多い装置です。  これらの機能を理解するには、人に置き換えて考えると分かりやすいです。算 数の授業で「5+4はいくつか」という命題が黒板に書かれて与えられたとします。 まず、私たちは黒板を目で見て問題を脳に取り込みます。目が入力装置の役割を 果たしたことになります。次に、脳に命題を記録するのは命題が長くなるにつれ、 あやふやになりかねないのでノートに「5+4=」と書き写します。このノートが主 記憶装置の役割を果たすことになります。次に、頭の中に5と4という数字を記憶 し、その2つの数字を足すという操作を頭の中で行います。ここで、脳が演算装置 の役割を果たしました。演算結果として得られた9という数字をノートに書き写し ます。最後に、前に出て黒板に9と書くことで命題を解いたことになります。黒板 に書くという動作が出力装置の役割を果たしたことになります。  このように、コンピュータは人が普段から行っている動作を高速で行っている に過ぎません。 ■0x03.) メモリの概要  メモリはコンピュータの5大機能のうち、記憶機能を担うハードウェアです。H DDなどの補助記憶装置に保存されているプログラムは、必ず一度メモリ上に展開 されてから実行されます。メモリの構造とバッファオーバフローは非常に関連性 が強いため、メモリの構造を理解した後にバッファオーバフローの解説を読むこ とをおすすめします。  メモリは先述の例でも挙げたように、データや命令を一時的に記憶しておく装 置です。すべてのデータ・命令は一端メモリに格納され、どのような順番でどの ような命令を実行するかが展開されます。メモリの内容を書き換えることで任意 のプログラムを実行し、権限を取得するのがハッキングの目的です。 ●ノイマンアーキテクチャ  コンピュータ科学で最も有名な人物を挙げるとしたら、まずはじめに名が上が るほど有名なジョン・フォン・ノイマンという人物がいます。ノイマンアーキテ クチャとは、このノイマンが考え出したコンピュータハードの設計概念です。現 在のコンピュータは少数の例外を除いてはすべてノイマンアーキテクチャを採用 しています。  ノイマンアーキテクチャはプログラム記憶型とも呼ばれ、プログラムをメモリ に格納して実行するタイプのアーキテクチャを指します。このアーキテクチャが 考案されるまではプログラムはコンピュータの物理的配線によってしか書き換え ることができませんでした。これでは、違う処理をさせるごとに配線を変えなけ ればならず面倒です。  ノイマンアーキテクチャの特徴として、バッファオーバフローを考える場合に 注目すべき特徴があります。ノイマンアーキテクチャでは、メモリに格納された 命令とデータを区別しないというバッファオーバフローによる権限奪取に好都合 な特徴をもっています。例えば、「20+5の計算結果を表示する」という命令を12 34と定義したとします。もしデータを読み出す命令によって「1234」が参照され たとすると、1234は千ニ百三十四という値として扱われます。一方、命令として 「1234」が参照されると、これは「20+5の計算結果を表示する」という命令だと 解釈され画面に25が表示されます。つまり、データを格納する場所に命令として 意味のある数値を格納し、この数値を命令として参照することで任意の命令を実 行することができます。 ●メモリの構造  ノイマンアーキテクチャではメモリに格納された命令とデータは区別しないと 書きましたが、メモリはデータと命令を一緒くたに記憶しているわけではありま せん。データはデータを格納する場所に置かれ、命令は命令を格納する場所に置 くというように、ものによって格納する場所を変えています。命令とデータの扱 いは同等であっても、格納する場所は分けられているということです。この場所 のことをセグメントと呼び、Intel x86アーキテクチャではテキストセグメント、 データセグメント、bssセグメント、ヒープセグメント、スタックセグメントの5 つのセグメントが存在します。 +------------------+ 0x00000000 | | | Text Segment | | | +------------------+ | | | Data Segment | | | +------------------+ | dss Segment | +------------------+ | Heap Segment | : : ↓ ↓ +------------------+ ↑ : : ↑ | Satck Segment | +------------------+ 0xffffffff  それぞれのセグメントの役割は次の通りです。 ○テキストセグメント  コードセグメントとも呼ばれます。テキストセグメントは命令を格納するため のメモリ領域です。例えば「a=3; b=5; x=a+b;」というプログラムがあったとし ます。3や5といった数字はデータであり、別の領域に格納されますので、3が格納 されている場所をADDRESS_3と置きます。テキストセグメントには「aにADDRESS_3 を移動させる」、「bにADDRESS_5を移動させる」、「b+cを計算する」、「xにそ の結果を移動させる」といった命令自体が格納されます。命令が操作するデータ は他の領域に格納されるため、ここに格納されるのはデータを抜きにした命令の 流れだけです。  テキストセグメントに格納された命令は、OS以外が書き換える必要はありませ ん。初めにOSが命令を格納し、実行がすべて終わったら格納された命令をクリア する以外にテキストセグメントの内容に触る必要はないため、このセグメントへ 格納された内容をプログラムによって書き換えることはできません。書き換えが 行われないため、テキストセグメントのサイズは固定長です。 ○データセグメント  データセグメントには初期化済みのグローバル変数や静的変数、文字列や定数 などのリテラルが格納されます。変数の中でもプログラムの実行を通して変化す ることのない、定数的な変数または定数を格納するのがこのセグメントです。定 数を格納するのセグメントですので、プログラムによるセグメント内の書き換え は禁止されています。書き換えが発生しないため、このセグメントも固定長のサ イズです。 ○bssセグメント  bssセグメントは初期化されていないブローバル変数や静的変数などが格納され ます。 ○ヒープセグメント  プログラム内で動的にデータ領域が確保される場合に利用されます。C言語では malloc()などで確保される領域がヒープセグメントにあたります。必要に応じて プログラム内で領域確保・解放されるため、ヒープセグメントは確保量にあわせ て増減します。後述するスタックも同じような性質を持ちますが、ヒープセグメ ントはメモリの低位アドレスから高位アドレス方向へ伸びていきます。 ○スタックセグメント  スタックセグメントはバッファオーバフローで最も狙われるセグメントです。 スタックについては後述しますが、スタックセグメントはメモリ上にスタック構 造を実装した領域です。C言語で書かれたAuto変数(デフォルトの変数)や関数呼 びだし時の戻りアドレス、関数内で宣言した変数などはすべてスタックセグメン ト上に確保されていきます。  スタックセグメントはプログラムの実行に伴って書き換えられる可能性がある ため、サイズは非固定長です。先述のヒープセグメントと同じように増減します が、スタックセグメントはメモリの高位アドレスから低位アドレスへ徐々に伸び て増加します。 ●メモリのアドレス  メモリは1バイトごとに番号が振られています。これは駅のロッカーを想像して もらうと分かりやすいと思います。ロッカーには通常、ロッカー番号がつけられ ています。荷物をいれたロッカーの番号を覚えているので、私達は後で預けた荷 物を取り出すことができます。メモリはロッカーひとつに1バイトの荷物をいれる ことができるロッカースペースだと思ってもらえればよいです。 +-[1]-----+-[2]----+-[3]----+-[4]----+-[5]----+ | | | | | | +-[6]-----+-[7]----+-[8]----+-[9]----+-[10]---+ | | | | | | +---------+--------+--------+--------+--------+  このロッカーにデータを格納する時の事を考えてみます。C言語のint型データ は4バイトの大きさだと定義されていますので、int型データひとつをメモリに格 納するには4アドレスが必要となります。駅のロッカーの例では、ロッカーひとつ では入り切らないほどの荷物を預けたい場合、入り切らなかった分を隣のロッカ ーに預けます。これと同じことをやっています。 +-[1]-----+-[2]----+-[3]----+-[4]----+-[5]----+ | int型の荷物(ロッカーを4つ使う) | | +-[6]-----+-[7]----+-[8]----+-[9]----+-[10]---+ | | | | | | +---------+--------+--------+--------+--------+ ■0x04.) 演算装置の概要  演算装置は本来、CPUの算術論理演算ユニット(Arithmetic and Logic Unit: ALU)が担当する、計算だけを行う機能のことを指しますが、ここでは制御装置も 含めたCPUとしての演算装置について言及します。 ●演算装置の構造  演算装置は複数の機能を実現する部品が組み合わされて構成されています。こ こでは代表的な部品について説明します。 ○算術論理演算ユニット  数値演算および論理演算を行うだけの装置です。演算に使うデータや「足す」、 「引く」などの操作や計算結果を記憶しておくことはできません。例えば、私達 も「2+4」の計算をする時、まず頭の中に2と4を記憶します。その後に加算という 概念を2と4に適応することで6が出てきます。結果として6を頭の中に覚えておく ことで計算を終えます。  つまり、計算をするためには一時的に数値を記憶する仕組みが必要です。次に 挙げるレジスタという装置がその役割を果たします。 ○レジスタ  一時的な数値の記憶を行います。メモリとは違い、非常に高速ですが容量を多 くすることはできませんし、記憶容量当たりの単価も高価です。そのため、通常 は32ビットのレジスタが10個ほどしか用意されていません。  このレジスタは役割があらかじめ決められています。 ・EIS:次に実行すべき命令の場所を保存 ・ESP:スタックセグメントの端の場所を保持 ・EAX:システムコール番号を格納 ・EBX:システムコールに渡す第1引数を格納 ・ECX:システムコールに渡す第2引数を格納 ・EDX:システムコールに渡す第3引数を格納 ・命令レジスタ:解釈した命令を一時保存  このうち、EIPの中身は命令が実行されるたびに次の命令のアドレスに置き換わ り、ESPの内容は後述するスタックのプッシュ・ポップの状況似合わせて増減しま す。レジスタの名前や機能、個数はCPUメーカーによって様々ですが、本レポート ではIntelのx86系のCPUを対象としています。CPUの種類によってはEISをプログラ ムカウンタと呼んだりします。 ○キャッシュ  メモリより高速ですが高価な記憶素子を使った一時記憶装置です。最近使われ たデータはもう一度使われる可能性が高いので、一度使われたデータはメモリよ り高速なキャッシュに保存されます。  演算装置内に実装するキャッシュは容量が多いほど不良品が出やすいので、CP Uの価格の差のほとんどがキャッシュの容量に左右されます。 ○内部バス  レジスタと算術論理演算ユニットの間のデータのやり取りを行うための通信線 です。コンピュータの動作速度に大きく関与します。 ●マシン語の命令実行  プログラムは全てマシン語で表現され、メモリに格納されることはすでに述べ ました。CPUはメモリから順次機械語命令を読み出し、その通りに実行します。正 確には、CPUは、レジスタとしてCPU内部に存在するプログラムカウンタ(Intelx 86ではEIP)内に保持されたメモリアドレスにある命令を次の実行すべき命令とし て取り扱います。例えば、次の図ではプログラムカウンタ内には「0x00ffffa0」 という値が保持されています。次の命令実行時には、このプログラムカウンタを 一度読み出し、内部に格納されている「0x00ffffa0」のメモリアドレスに格納さ れている「0x00ffffa3」という機械語を命令として実行します。 +---[ProgramCounter]---+ +---[Memoly]---+ | 0x00ffffa0 |--+ | 0x00f1120f | 0x00ffff9f +----------------------+ | +--------------+ +-→| 0x00ffffa3 | 0x00ffffa0 ---+ +--------------+ | | 0x004ca300 | 0x00ffffa1 | +--------------+ | +--------[ALU]---------+ | 0x00cf8880 | 0x00ffffa2 | | | . . | | 0x00ffffa3 |←-----------------------------------+ +----------------------+  正確に言うなら、プログラムカウンタから読み出した命令は算術論理演算ユニ ットで実行される前に、デコーダという装置で解釈されます。これは命令が足し 算なのか引き算なのか何なのかを判断し、演算対象となるデータがどこにあるの かを計算します。命令自体は命令レジスタに格納されているので、そこから読み 出します。 +---[Instaction Registor]---+ | 0x00ffffa3 | +---------------------------+ | | | +=============+ +==[Decoder]==+ .....targer1=eax; target2=ebx; +=============+ .....a3 is additional | | | +------[ALU]------+ | x = x + y | .....location of x: eax +-----------------+ .....location of y: ebx  上図では0x00ffffa3をデコーダが解釈し、a3が足し算であることを知り、ffff がeaxにebxとの計算結果を格納すると知ります。次に足し算の実行が行われます が、算術論理演算ユニットはデコーダで得られたデータの場所へデータを取得し に行きます。ここではeaxとebxレジスタを参照します。 ■0x05.) スタック  スタックとは情報科学の分野でよく用いられるデータの構造概念です。この構 造をCPU内に実装したものをスタックセグメントと呼びます。 ●スタック構造  スタックはショッピングセンターのカートのようなもので、後にいれたものか ら順番に取り出すデータ構造です。最後にいれたものから取り出すという性質か らLIFO(Fast In First Out)またはFILO(First In Last Out)型のデータ構造 だと言われます。カートの例で説明しますと、まずカートはレジ横の設置場所に 数台設置されいるとします。 [設置場所] <<<<<  買い物をするときはカートをひとつ取り出して商品をカートにいれて行きます が、通常カートは一番上(最後い入れられたカート)から取り出します。真ん中 のカートを無理やり取り出す人は極少数派なはずです。「●(黒丸)」を消費者 だとします。左に向けてカートが積まれるとしますと、消費者は一番右にあるカ ートをつかんで持って行きます。 [設置場所] <<<<<●← [設置場所] <<<< →<●  もう一人消費者が来たとしたら、同じように一番右にあるカートを持って行き ます。このようにスタックからデータ(カート)を取り出すことをポップ(Pop) と言います。 [設置場所] <<< →<●  一方、買い物が終わってカートを返す時のことを考えて見ましょう。これも普 通の人は一番右にいれて行くはずです。よほどポリシーを持った人でなければ、 真ん中の方に無理やり挿入することは考えにくいです。 [設置場所] <<< <●← [設置場所] <<<<●←  このようにスタックにデータを挿入する動作をプッシュ(Push)と言います。 これをより一般的に書くと次のような図として書き表すことができます。 [Stack] [Pop] [Push] +------------+ | 2 | +------------+ ↑ ↓ + + + ↑ + + ↓ + | | | ↑ | | ↓ | +--------------+ + ↑ + +--------------+ | 2 | | ↑ | | 3 | +--------------+ +--------------+ +--------------+ | 1 | | 1 | | 1 | +--------------+ +--------------+ +--------------+  一番左が初期状態です。1と2の値が入っています。このスタックに対して左か ら2つ目のようにポップ作業を行うと、一番上にある2が取り出されます。次に一 番右のように3をプッシュすると、前回の操作で2が取り出されたので、残った1の 上に3が入れられます。 ●関数呼び出しとスタック  関数を呼び出す時には、OSはいくつかの作業を行ってプログラムの制御を呼び 出される関数へ変更します。関数の処理が終わった場合にもいくつか作業を行い、 以前実行していた場所に制御を戻します。このときにスタックを大いに活用して います。  実際に行っている作業は次のステップに分けられます。 1:ESPの場所へスタックフレームをプッシュする 2:EIPの値を、呼び出す関数の開始アドレスに変更 3:EIPにあるアドレスを解釈し順次実行する 4:関数が終わりに達したらスタックフレーム内のRETをEIPに変更 5:一番上にあるスタックフレームの除去 ●スタックフレーム  スタックフレームは関数を呼び出して利用する時に必要となる情報をひとまと めにしたものです。スタックフレームは戻りアドレスや引き数などで構成されて います。構成は次の図のようになっています。 +----------------------------+ | ローカル変数 | +----------------------------+ | 退避済みフレームポインタ | +----------------------------+ | 戻りアドレス | +----------------------------+ | 引数 | +----------------------------+ ○引数  関数への引数はスタックフレームの一番下に位置します。また、スタック構造 であるため、最も後に宣言した引数ほど先にスタックフレームに格納されます。 ○戻りアドレス  関数の処理が終了した場合に制御を移すべきアドレスです。関数呼び出し時の EIPの値です。関数が終わりに達したら、この戻りアドレスを参照しEIPに格納し ます。その結果、制御が関数を呼び出す前の場所に戻ってくるわけです。 ○退避済みフレームポインタ  関数呼びだし前のEBPの値です。関数の終了時にEBPの値を元に戻すのに利用さ れます。EBの値がスタックにプッシュされた後には、この関数のフレームポイン タを設定するために現在のESPの値がEBPに設定されます。EBPとのオフセットを減 算することでローカル変数を参照することができ、逆に加算することで引数を参 照することができます。 ○ローカル変数  ローカル変数は関数内で宣言される変数のことです。ローカル変数はスタック フレームの最も上に格納されます。引数と同じように、スタック構造であるため、 後に宣言した変数ほど先に格納されます。ローカル変数はEBPを用いて参照されま す。具体的にはEBPとどれだけ離れているかを計算することでアクセスが可能とな るのです。  次のプログラムでは、main関数内から4行目でfunc関数を呼び出しています。呼 び出した後に元の場所に制御を戻すということは、func関数が実行された後にma in関数の5行目のreturn命令を実行することになります。 ----- int main(void){ int x, y; y = func(x, 2); return 0; } int func(int x, int y){ char test; test = x + y; return x * test * y; } -----  この場合、次のようなスタックフレームがスタックセグメントにプッシュされ ます。スタックセグメントは高位アドレスから低位アドレスへ伸びるので、デー タは0xffffffffから0x00000000の方向へ積まれていきます。ESPはスタックセグメ ントの最も小さい方の端のアドレスを保持するレジスタなので、スタックフレー ムがプッシュされると、そのサイズ分だけ低位アドレスに移動します。 +-----------------------------+0x00000000 : : : : +-----------------------------+0xfffffff9 ← content of ESP | | +-----------------------------+0xfffffffa | test | +-----------------------------+0xfffffffb | | +-----------------------------+0xfffffffc | RET | +-----------------------------+0xfffffffd | x | +-----------------------------+0xfffffffe | y | +-----------------------------+0xffffffff  EIPの値や引き数、ベースポインタの値などをスタックに一時保存することで、 以前実行していた命令の場所を覚えておくことができます。つまり、関数による 構造化プログラミングのような近代的プログラミングテクニックを活用するのに 当たって、スタックセグメントは必要不可欠です。しかし、Intelのx86アーキテ クチャはスタックへ格納される情報の順番に問題があるため、バッファオーバフ ローの危険性が存在するのです。この危険性については次回のレポートでハッキ ングの実例を挙げて解説します。 ■0x06.) 参考文献 ・「Hacking:美しき策謀」 Jon Erickson著 村上 雅章訳 ISBN4-87311-230-3  http://www.oreilly.co.jp/books/4873112303/ ・「ハッキング対策マニュアル」ISBN4-7973-2145-8 ・「セキュリティ夜話 バッファオーバーフロー(BO)系列 (1)Aleph Oneに よるスタック破壊の楽しみと恩恵」  http://www.asahi-net.or.jp/~vp5m-snd/sec/tech/Phrack49-14.html ・初心者のためのポイント学習C言語  http://www9.plala.or.jp/sgwr-t/ ■0x07.) さいごに  今回は前回に引き続き、前提知識の確認を行いました。ハッキングにおいて特 に本質となるプログラミングを重点にC言語とアセンブリ言語について解説をしま した。次回はハードウェアについての基礎部分を解説し、前提知識の確認を終え ます。まだ、いかにもハッキングといった内容の解説は出てきませんが、前提と なる知識を詰めることがハッキングの理解を助けるのだと考えています。  それでは、またお会いしましょう。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第4章: デフラグさんの作り方 --- 著者:Kains x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  今回は私が自分のホームページ上に設置したデフラグさんというPHPで書いたプ ログラムの作成過程を書いてみようと思う。この手のものは珍しいようで、狭い 見識ではあるが私の知る限りでは日経ソフトウェアの特集「誰も教えてくれない プログラムの創り方」だけである。ちなみにデフラグさんとは、2ちゃんねるで使 われるアスキーアートである。「デフラグしました」が口癖で、人の発言を綺麗 に(意味のない言葉の並びに)並び替えてくれるのである。使用した言語はPHP。 私はUTF-8環境で試しているので、Shift-JIS等の環境の方は文字コードを指定す る引数を適時変えてほしい。  作成過程としたが、説明のため若干の順序の違いなどがあると思われる。  2ちゃんねるを見ていると、たまに「入門書は読み終えたが何を作ればいいかわ からない」という書き込みを見かける。私もそうだった。具体的に何かを作りた いわけでもない。当然、アイデアもないので悩む。いつかすごいものを作れたら いいなあ。 ■0x02.) 並び替え基準  まずどのように並び替えるかが肝である。やはり50音順かそれに近い精度が欲 しいところだ。しかし、まさかifやswitchでひとつひとつ条件分岐を書いていく わけにもいかない。  そこで、文字コードに目をつけた。文字コード、つまり文字に割り当てられた 番号を利用するのである。重複する文字コードはひとつもないので一意性が保た れる。  文字コードを使うアイデアが出たので試してみる。文字を引数にして、その文 字の文字コードを返すordという関数がPHPには備わっている。しかし、これには 問題がある。ord('あ')とord('い')を表示してみて欲しい。どちらも227と表示さ れるのである(筆者はUTF-8環境で試している)。違う文字が同じ文字コードであ ることはないので、ここはプログラマ側のミスかord関数あるいはPHPを疑うのが 妥当だろう。  ところでPHPの関数を見ていると、文字列処理の関数に比べてマルチバイトに対 応した関数の少なさが目に付く。そこから、PHPはマルチバイトに弱いのではない かという憶測がたつ。つまり、ord関数はマルチバイト文字には使えないのではな いかと考える。そこで、$a="あ"; echo ord($a[0]).":".ord($a[1]); を試して欲 しい。私の環境では、227:129と出力された。227はord('あ')のそれと一致してい る。どうやら2バイト目も文字コードを取得できているようだ。  しかし、UTF-8はどうやら文字によってバイト数が違って一定ではないらしい。 どうにか手っ取り早い方法はないだろうか。そこで以下の関数は、マルチバイト 対応版ord関数である。ただし、私は文字コードの知識がないのでこの関数が返す 値を文字コードと呼んでいいのかはわからない。この数字を基準にソートをかけ る。幸いにして、この自作ord関数では「あ」の次の文字コードは「ぁ」、その次 は「い」、その次は「ぃ」となる(UTF-8の環境)ので、50音順の並びが期待でき る。 ----- function ord($n) { $sec = 0; $c = mb_substr($s, $n, 1, "UTF-8"); $sec = ord($c); for ($i=1; $i