ここ1年で開発が進んだ技術によりバッファ・オーバーフローによるワーム感染の脅威を排除できる。一方で,ボットを筆頭に新しい脅威が登場してきている。犯罪者が悪性プログラムに手を染め続ける限り闘いは終わらない。

(本誌)

図1●脆弱性公開からワーム発生までの日数(2001年~2004年)
図2●仮想メモリーの仕組み
ハードディスクを利用することで,OSに物理メモリー以上のメモリー空間を見せる。
図3●NX(No Execute)の仕組み
プログラムを記述しない場所はメモリー確保の際,ページテーブルの該当するページの場所にマークをしておく。マークがついた部分を読み出し実行しようとした場合,エラーが出てプログラムの実行が強制的に終了する。
表●Windows においてバッファ・オーバーフロー攻撃の上書き対象になる個所
 前回バッファ・オーバーフローのメカニズムと,それを悪用するワームについて説明した。まず,この補足から始めたい。図1[拡大表示]は脆弱性が発見されてから,実際にそれを悪用するワームやウイルスが発生するまでの時間差を示したものである。2年前までは脆弱性が発見されてから悪用されるまでの間に,数カ月から数週間の時間差があったことが分かる。ところが,ここ1年の傾向を見るとその値はゼロになっており,全くタイムラグがなくなっている。

 つまり,「修正プログラムの公開/提供より前に脆弱性を悪用するウイルスが発生する」状況なのだ。前回に述べたバッファ・オーバーフローの脆弱性は見つかりやすいという傾向と合わせて考えれば,今がいかに危機的状況であるかお分かりいただけるだろう。例えば明日,未知のセキュリティ・ホールを突くワームが登場して大被害を与えてもおかしくない状況なのだ。

 そこで求められるのが,修正プログラムが提供されなくても,バッファ・オーバーフロー攻撃をできないようにする手段である。

 その一つとして,「現行のプログラムをJavaやC#などで作り直す」というアプローチがある。C,C++には確保したバッファ量を超えて,データが格納されたときにエラーを出す「境界チェック機能」がない。そのためバッファ・オーバーフローの穴が開きやすい*1。ランタイムがメモリーを管理してくれる言語でプログラムを作れば境界はチェックされる。例えば,Javaではバッファ・オーバーフローが起こる個所でエラーを発する。

 ただ,この方法は現実的とはいえない。多くのソフトウェア資産がC,C++で蓄積されており,これを新しい言語で作り直すには膨大なコストと時間がかかってしまう。

 そこで,考えられるのが,アプリケーション層よりもさらに下層,OSでバッファ・オーバーフローを抑制する技術である。これまで述べたような危機感が後押しし,ここ1年ほどで急速に開発が進んだ。中でも,有名なのがWindows XP Service Pack2に搭載されたDEP(Data Execute Prevention)だろう*2。このほか,Linux用に提供されているPaXやExec-Shieldなどの技術がある*3。以下では,DEPを例にバッファ・オーバーフロー抑制技術を見てみる。

シェルコードの実行を阻止するDEP

 DEPは二つに大別できる。一つはハードウェア(CPU)と連携してバッファ・オーバーフロー攻撃からプログラムを保護する「ハードウェアDEP」。もう一つはソフトウェアのみで保護する「ソフトウェアDEP」である。

 前者は,ハードウェアDEP対応のCPUと,OSのメモリー管理機構を使う。一般的なOSは,ハードディスクの一部領域を利用することで,実際に搭載されているよりも大きなメモリー空間を扱える「仮想メモリー」機構を備えている。例えば,128Mバイトのメモリーしか搭載されていなくても,ハードディスクをいわば「一時保管庫」に使って4Gバイトのメモリー空間を実現する,といった具合だ。仮想メモリー機構は一般的なOSのほとんどに実装されており,ハードディスクに格納される一時保存情報は「ページファイル(あるいはスワップ・ファイル)」と呼ばれる。

 仮想メモリーはメモリー内の情報を数キロバイト単位に分割することで実現している。分割された情報を「ページ」と呼ぶ。ページをハードディスクにページファイルとして保存することを「ページアウト(あるいはスワップアウト)」,その逆を「ページイン(あるいはスワップイン)」と呼ぶ(図2[拡大表示])。

 さて,現在主流のIA-32アーキテクチャに限ってみると,このページ管理機構には「書き込み」と「読み出し」の保護能力しかない。この能力を使うことで,前回説明したように,プログラムを改変から保護しているのだが,「実行」の制御はできない。読み出し可能なページは全て実行可能とみなされる。つまり,Stack領域でもHeap領域でも,読み出し可能な領域であれば,CPUはそこから命令を読み出して実行する。

 ハードウェアDEPは,IA-32アーキテクチャにおけるページ管理機構の改善により実現している。具体的にはページ単位で「実行」の制御が可能になったことを利用する。この技術は「NX(No Execute)」*4と呼ばれる(図3[拡大表示])。具体的には,PAE(Physical Address Extension:物理アドレス拡張)で行われた変更*5を利用し,ページテーブル・エントリ(PTE)に「NXビット」を付加することで実現した。

 実際の動作では,OS(Windows XP SP2)がStack領域およびHeap領域を確保する際に,そのページ領域のNXビットをオンにする。バッファ・オーバーフロー攻撃によってStack領域のリターン・アドレスが書き換わり,シェルコードが挿入されたとしても,シェルコードが書かれている場所は,NXビットがオンになっている領域であり,実行できない。ただし,DEPはバッファ・オーバーフロー攻撃抑止技術であり,バッファ・オーバーフロー自体は止められないことに注意してほしい。

 一方のソフトウェアDEPには,明確に解説されている公の文書はこれといって存在していない。このため,ソフトウェアDEPについては筆者の独自調査であることをご了承いただきたい。[拡大表示]は,バッファ・オーバーフロー攻撃で狙われる個所の一覧である。攻撃者はこれらを上書きし,シェルコードを実行することで,「コマンドシェルを起動する」といったことを実現する。発想を転換すれば,「これらの値を上書きから守れば,バッファ・オーバーフローは悪用できない」ことになる。事実,XP SP2ではこれらの個所のうちのいくつかを保護している。

 ただ筆者の調査によると,表の個所を保護できるようになったのは,ソフトウェアDEPよりもXPSP2の実装の仕方によるところが大きい。ではソフトウェアDEPは何かというと,「例外ハンドリング」というWindows特有の処理機構を使いNXビットをソフトウェア的にエミュレートしているものと考えられる*6。エミュレート分だけオーバーヘッドは生じるが,攻撃されるよりははるかにマシだろう。