PR

戻りアドレスの書き換え検知や,メモリー配置のランダム化で守る

 関数の戻りアドレスをライブラリに書き換える攻撃を防ぐ方法はいくつかある。一つが,特殊なコンパイラを用いて,戻りアドレスの書き換えを検知する機能をプログラムに付加する方法である。一般には,書き換え検知用の数値を戻りアドレスの直前に書き込んでおき,これが変化するかどうかで書き換えの有無を判断する機能をプログラムに付加する。プログラムは実行時に書き換えの有無を検査し,書き換えがあればプログラム停止などの措置を取る。

 Linuxが標準採用するコンパイラ「GCC」(GNU Compiler Collection)では,Stack Smashing Protector(ssp)StackGuardなどのパッチを適用することで,戻りアドレスの書き換え検知機能を付加できるようになる。sspではさらに,アドレス格納に使う「ポインタ変数」を他の変数よりも下位に配置することで,戻りアドレス以外のアドレスの書き換えも難しくする。

 Windowsの開発環境であるVisual C++にも,戻りアドレス書き換え検知機能を付加する/GSオプションが用意されている。Windows XP SP2のコア・コンポーネントは,同オプションを付加してビルドされている。

 もう一つが,ライブラリや実行プログラムのメモリー配置をプログラムごとに変更する方法である。ただ変更するだけでなく,できるだけランダムに(規則性無く)配置するのが望ましい。これにより,攻撃者が目的とする呼び出し先が分かりにくくなり,攻撃が成功する可能性を低下できる。

図2●Adamantixでのライブラリ配置のランダム化
catコマンドの実行プロセスのメモリー・マップを調べてみた。コマンドを起動するたびにライブラリ配置が変化しているのが分かる
 Linuxでは,PaXと呼ばれるパッチをカーネルやローダーに適用することで,ライブラリ配置のランダム化を実現できる。PaXには,データ記憶領域でのプログラム実行を禁止する機能もある。当初「Trusted Debian」という名前でリリースされた,セキュリティ強化版のDebian GNU/Linuxである「Adamantix」は,このPaXの成果を取り入れたディストリビューションである。Adamandixにおける,catコマンドの実行プロセスのメモリー・マップを図2[拡大表示]に挙げた。実行のたびにライブラリの配置が変更されているのが分かる。

 なお,Exec-Shieldにもランダム化の機能はあるが,これはスタック領域の配置だけをランダム化するものである。スタック中の変数を書き換えるような攻撃をしにくくする効果はあるが,return-into-lib攻撃にはほとんど効果はない。

Linuxも標準で対策してほしい

 データ記憶領域でのプログラム実行禁止に加え,これらの対策を施せば,バッファ・オーバーフローを悪用した攻撃をある程度防御できる。Windows XP SP2では,ライブラリ配置のランダム化を除く,2つの対策が標準で施されている。

 ひるがえってLinuxはどうだろうか。

 前述したAdamantixのようなディストリビューションがあり,過去には,ssp対応GCCでシステム全体をビルドした「LASER5 Secure Server 6.9」のような製品もあった。しかし現在一般に利用されているディストリビューションでの対策は十分とは言えない。Exec-Shieldを標準装備するディストリビューションも,Red Hat LinuxやFedora Coreなど一部のディストリビューションに限られる。

 Windows XPのような「クライアント向け」のOSがここまでの対応を迫られている現状で,サーバー用に利用されることが多いLinuxでは,より進んだ対策を標準で施しておく必要があるのではないだろうか。

 もちろんこれらの対策には,システム処理速度の低下や互換性の問題がある。

 例えば,コンパイラによるアドレス書き換え検知機能の付加では,書き換えの有無をプログラムの実行時に検査するため,処理時間が余分にかかる。sspは処理速度も考慮して設計されているが,4~8%程度は余分に処理時間がかかるという。ライブラリ配置のランダム化も処理速度を低下させる。というのも,あらかじめリンク作業を済ませておくことでプログラムの起動を高速にする「prelink」という仕組みが働かなくなるためである。これは実行時のリンク処理の負担が大きいC++アプリケーションの処理速度を低下させる。また,Exec-Shield環境下では,スタックでのプログラム実行を前提に開発されたプログラムなどは動作しなくなる可能性がある。

 しかしコンピュータの性能が日増しに向上し,低価格化が進む現在,ほとんどの場合処理速度は大きな問題ではないだろう。また,互換性の問題があるから対策しない,というのもおかしな話だ。問題があるアプリケーションだけチェックを緩くするなどの方法が有り得るし,実際にWindows XP SP2ではそのような手段を提供している。Linuxディストリビュータには一考を願いたい。

 もちろん,標準対応こそしていないが,ユーザーの側で対策を施すのは十分に可能だ。また,バッファ・オーバーフロー対策以前に実施すべきセキュリティ対策にもさまざまなものがある。日経Linux 2004年10月号で「カーネル2.6時代のセキュリティ強化マニュアル」と題した特集記事を掲載している。こちらも参考にしていただければ幸いである。

(末安 泰三=日経Linux)

(2004年9月8日 12:00 補足)
Exec-Shieldでも,バージョン2.15以降のbinutilsを使っている環境(例えば,Fedora Core2)では,スタックだけでなくライブラリ配置等もランダム化できる。ただし,あらかじめバイナリを-fPIE(-pie)オプションを付けてビルドしておかねばならない。なお,PaXの場合も,バイナリは-fPICオプションを付けて位置独立に実行できるようにしておく必要がある。(末安)

(2004年9月10日 12:00補足)
DEPをData Execution Protectionの略としていましたが,正しくはData Execution Preventionの略でした。お詫びして訂正します。