と言うわけで、ここでは、Macintosh上でバッファオーバーフローが起きたとき、どうやって確認すればいいか、そして、そのオーバーフローが、セキュリティホールとして利用可能かどうか簡便に判断する方法、についてメモしておきます。全然詳しくないけど:-P
このような記事を書く発端は、2001/12月に公表したOutlook express for Macintoshのバッファオーバーフロー脆弱性について、「実はISPは知っていたけど、セキュリティホールになり得ることに気づいていなかった」と言う事実(もしくは可能性)を知ったからです。
さらに言えば、その昔、某ソフト(まだ公開していないので内緒)のバッファオーバーフローをチェックしたとき、ShadowPenguinSecurityのUNYUNさんに教えてもらった様な内容を日本語で探すのってけっこうつらそう、と感じたからです。
この情報が、マカーな方々の役に立てばいいな、と考えています。あ、MacOSXは範疇外です。念のため。
で、用意するものは、MacOSの入ったMacintoshとMacsBugです。
入手方法ですが、まず、Macintoshはお店に売っています。MacsBugはAppleのサイトからダウンロードします。で、MacsBugをsystem Folder直下にコピーしてリスタートすれば準備完了です。
ちなみに、MacsBugを入れると不安定になる場合がありますが、多くの場合、元々不安定な状態だったのを知らずにいれて、不安定な事実が発覚する、というパターンのようです。
後は、いつもの通り使い続けます。そのうち、何かの拍子でMacintoshの画面が壊れ、中央に白わくが現れ、テキストが表示されます。ここで、「stdlog(リターン)」と入力するとテキストが出力されます。そのテキストはこんな感じです。
MacsBug 6.6.1, Copyright Apple Computer, Inc. 1981-2000
PowerPC unmapped memory exception at 4F505150
4-Oct-2001 7:18:25 PM (since boot = 12 minutes)
Current application is ふがほげ
Machine = #68 (PowerMac7500), System $0810, sysu = $01008000
ROM version $077D, $28F2, $0001 (ROMBase $FFC00000)
VM is on; paging is currently safe (and it probably isn't VM's fault)
NIL^ = $FFC10000
Stack space used = +77270178
Address 4F505150 is not in RAM or ROM
PowerPC 604 Registers
CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR7
PC = 4F505150 CR 1000 0010 0000 0000 0000 0000 0100 0010
LR = 4F505152 <>=O XEVO
CTR = 001EB4E4
MSR = 00000000 SOC Compare Count
Int = 0 XER 000 00 00 MQ = 65666768
R0 = 4F505152 R8 = 000000AB R16 = 00000000 R24 = 61626364
SP = 032AA230 R9 = 00000001 R17 = 00000000 R25 = 20656667
TOC = 0323CDA0 R10 = 00000000 R18 = 00000000 R26 = 68696A6B
R3 = 00000001 R11 = 0028F53C R19 = 00000000 R27 = 6C6D6E6F
R4 = FFFFFFFF R12 = 05326EA8 R20 = 00000016 R28 = 70717273
R5 = 00000000 R13 = 00000000 R21 = 00000000 R29 = 74757677
R6 = 00000000 R14 = 00000000 R22 = 33343536 R30 = 78797A41
R7 = 00000000 R15 = 00000000 R23 = 37383930 R31 = 42434445
Unable to access that address
・・・・・・(等幅フォントで見た方がいいかと思います。)
これが、典型的なバッファオーバーフローを起こした状態です。
ちなみに、このような状態になったとき、キーボードが効けば、「es(リターン)」で何事もなかったようにMacOSに戻ります。気分が悪いなぁ、という場合には「rs(リターン)」で再起動を行うことができます。ほかにも当然いろいろなコマンドがありますが、上記2つだけは知っていた方がいいです。
この画面になったときは、上下カーソルキー(使えない場合は完全に死んでます)でテキストを閲覧できますので、眺めてみてください。ここに、セキュリティホールとして悪用可能かどうかの情報があります。
まず、「PowerPC unmapped memory exception at 4F505150」とありますが、これは「4F505150というメモリの場所に行こうとしたはいいが、そこにはメモリがないじゃん」、と言っています。つまり、プログラムがメモリがない場所に行こうとしてこけた、と言うことを示しています。
なんでそんなところ(メモリのない場所)に行こうとしたか、と言うと、プログラムに「行け」と言われたからです。その証拠が、「PC = 4F505150」です。PCはプログラムカウンタ、つまり、CPUが今実行しようとしている命令の書かれた場所(番地)を保存しています。これが「4F505150」になっているので、プログラムはここに行け、とCPUに命令した、と言うことになります。
本来なら、ここでバッファオーバーフローについてきちんと記述しなければならないのですが、決して分かりやすいものではないので、じわじわと説明しつつ、先に進みます。
なぜ、プログラムはメモリがない様な場所(番地)に行ってしまったのでしょうか。
それは、このような背後関係があるからです。
(ざっくり言ってしまうと)プログラムは、メモリ上におかれますが、そのプログラムが実行されるとき、広いメモリ上のあっちに行ったり、こっちに行ったり、と非常にバラバラな場所で実行されます。上から順番に流れるように実行される場合はまれだと思って構いません。
で、あっちいったあと、こっちに戻らなきゃならない場合も当然出てきます。この時、プログラムはあっちに行く前に、こっち(帰ってくるべき場所)がどこか、をメモリ上に保存しておきます。その保存領域をスタック、と呼びます。そのスタックのすぐとなりには、バッファ、と呼ばれる領域があります。バッファは、一次情報保管所の様なものです。
この辺からややこしくなってくるんで、ゆっくりいきましょう。(^^)
バッファは保管場所ですが、無限の大きさを保管できるわけではありません。大きさは有限で、基本的にプログラマーが「これだけ確保してね」と指定することで確保されます。これがバッファサイズです。
たとえば、1から255まで数字のうち、どれか一つを保管する必要が生じた場合、1バイト(場合によって異なりますけど)必要となります。最大128文字(アルファベット)を保管したい場合、129バイト(128文字+文字の終端を表すNull文字1つ)確保する必要があります。
さてここで問題です、上記の128文字保存のために確保したバッファに200文字保管させたらどうなるでしょうか?
ちょっと考えると、「128文字しか保存できないんだから、『保存できません』っていわれるんじゃないの?」って思いますよね。そうだったらいいんですけど、実は、そんなこといわれなかったりします。
何も考えず、200文字+終端のnull文字を保管します。そうすると、129文字のバッファからあふれますよね。これがバッファオーバーフローです。
じゃぁ、あふれた分(この場合は200文字+Null文字−129文字分のバッファ=72文字)はどこに行ってしまうのでしょう。
答えはお隣のスタック領域。つまり、プログラムが戻るためにわざわざ保管しておいた場所の情報を書き換えてしまうのです。
そうなると、プログラムはたまったものではないですよね。全然違う場所の情報に書き換えられちゃうんですから。全然違う場所に戻ろうとして、たとえばメモリがないじゃん、といって落ちてしまう事になっちゃいます。
さて、私はすでに「プログラムが戻るために保管した情報を書き換える」と書きました。また、バッファにはデータが保存されます。このデータは、多くの場合、ユーザの入力やファイルの入力などが入ります。
じゃぁ、バッファにプログラムを入力してもいいんですよね。で、先ほどのプログラムの戻る場所、ってのをバッファの場所に書き換えてもよさそうです。そう言う入力をされてしまうと、どうなるか。
バッファにはプログラムが入力され、バッファがあふれて、戻るための情報が書き換えられ、戻るところがバッファにためられたプログラムを指している、と言う状態ですから、戻った途端にバッファにおかれたプログラムが実行されることになります。
もし、このプログラムが、「ファイルをみんな消去」ってものだったら・・・・・。これがバッファオーバーフローがセキュリティホールと呼ばれる所以です。
さて、先に示したMacsBugの出力に戻りましょう。
先に述べたとおり、PCが4F505150(本当は4F505152の予定なんですけどね)に書き変わっています。この時、バッファに送り込まれた文字列は、と言うと、以下のとおりです。
1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ
1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ
1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ
1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ.tst(実際には一行)
で、4F505152をascii文字列にすると、「OPQR」になります。上記文字列中には4ヶ所にこの文字列が存在していますので、この4ヶ所のうち、いずれかの場所をうまく書き換えてあげると、戻る場所を自由に選ぶことが可能となります。
因みに、戻る場所を書き換えるためには入力の何文字目を書き換えなければならないか、と言うのを特定しなければならないのですが、これは入力をいろいろ変えて試してみると確認できます。
また、MacsBugが出力するリストの最後の方を見ると、このような記述があります。
Displaying memory from sp
032AA230 4647 4849 4A4C 4D4E 4F50 5152 5354 5556 FGHIJLMNOPQRSTUV
032AA240 5758 595A 3132 3334 3536 3738 3930 6162 WXYZ1234567890ab
032AA250 6364 6566 6768 696A 6B6C 6D6E 6F70 7172 cdefghijklmnopqr
032AA260 2073 7475 7677 7879 7A41 4243 4445 4647 stuvwxyzABCDEFG
032AA270 4849 4A4C 4D4E 4F50 5152 5354 5556 5758 HIJLMNOPQRSTUVWX
032AA280 595A 3132 3334 3536 3738 3930 6162 6364 YZ1234567890abcd
032AA290 6566 6768 696A 6B6C 6D6E 6F70 7172 7374 efghijklmnopqrst
032AA2A0 7576 7778 797A 4155 5657 5859 5A31 3233 uvwxyzAUVWXYZ123
これは、スタックがどの様な文字列で埋められているか、を確認するためのメモリダンプ(メモリの中身をリストアップすること)、と呼ばれるものです。見ての通り、先に示した文字列で埋め尽くされていることが分かりますね。もしここにかかれているものが文字列ではなく、プログラムだったら、大変なことになってしまうわけです。
因みに、上記ダンプの行の先頭(例:032AA230)はスタックの置き場所(番地)です。そのあとの8ブロックはスタックに保存されたデータのバイナリで最後のブロックはデータをascii文字に直したもの、となっています。
と言うわけで、上記の状態の場合、1.戻る場所を変更可能、2.スタックに任意のプログラムを入力可能、という事になるので、セキュリティホールになりうる、という判断ができます。
じゃぁ、だめな場合はどうか、と言うと、入力された文字列の一部がPCに反映されていない、という場合なのですが、実際問題、これがセキュリティホールになるかどうか判断が難しいところです。しいて言えば、プログラムに対するDoS攻撃が可能、というレベルでしょうか。
ただし、これはあくまで可能性の問題です。つまり、セキュリティホールになる、と証明するためには実際にコードを書いて、事実を見せない限りはできると言いきれません。
また、いくら文字列を入力可能、と言っても、使えない文字があるなどの制約条件がありますので、それを迂回するテクニックも必要となります。念のため。
そういった制限事項があるとは言え、上記のように戻り場所を書き換えられる上、スタックにプログラムが置ける、というのはセキュリティホールの可能性が高い、と言うことは自明かと思います。