バッファオーバフロー(BOF)攻撃とは、CやC++言語で開発されたOSやアプリケーションプログラムの入力データの処理に関するバグをついて、コンピュータのメモリに不正なデータを書き込み、システムへの侵入や管理者権限の取得を試みる攻撃手法である。ここでは、バッファオーバフロー攻撃について、その仕組みと対策を解説する。
2.3.1 BOF攻撃の仕組み
BOF攻撃には、メモリのスタック領域で行われるもの(スタックBOFもしくはスタックベースBOF)、ヒープ領域で行われるもの(ヒープBOFもしくはヒープベースBOF)、静的メモリ領域を対象としたものがある。ここでは、スタックBOFについて解説する(以降、単にBOFという場合はスタックBOFのことを指す)。なお、スタックBOFは、スタック領域を破壊するため、スタック破壊攻撃とも呼ばれる。
スタック領域とは、後述するように、サブルーチンの呼び出しなどによって自動的に確保され、プログラムが一時的に使用するデータを格納するために用いられる。一方ヒープ領域は、必要に応じてmalloc関数、new演算子(C++言語の場合)を用いて動的に確保する。スタック領域は不要となると自動的に解放されるが、ヒープ領域はfree関数、delete演算子(C++言語の場合)を用いて明示的に解放する必要がある。
スタックの概要
BOF攻撃の仕組みを理解するためには、まずプログラムが実行される際のスタックの使われ方について知っておく必要がある。スタックとはデータ記憶構造の一種であり、最後に書き込んだデータが最初に読み出しされる後入れ先出し(Last In Firest Out:LIFO)となっている。
後入れ先出しとは、箱の中に本を一冊ずつ横にして積み上げ、上から一冊ずつ取り出すことをイメージすれば良い。つまり、後で上に積んだ本から先に取り出されることになる。
このようなデータ記憶構造になっているメモリ領域をスタック領域、あるいは単にスタックと呼ぶ。またスタックにデータを書き込むことをPUSH、スタックからデータを取り出すことPOPと呼ぶ。
PUSHとPOPのイメージ |
---|
![]() |
スタックは、プログラム内でサブルーチンを呼び出す際に、その戻り位置(リターンアドレス)を格納するほか、サブルーチン内で定義された変数(内部変数、ローカル変数)の格納など、一時的に使用されるデータを格納する用途に使われる。スタックを用いるとサブルーチンから他のサブルーチンを呼び出すことも、自分自身を呼び出すことも可能となる(recursive call:再起的呼び出し)。
なお、通常プログラムや初期データなどをメモリに格納する場合には、低位のアドレスから使われる。これは、スタックにPUSHするデータの数が増えることによって、メモリに格納されたプログラムデータを破壊してしまうのを防ぐためである。
スタックのイメージ |
---|
![]() |
2.3.4 BOF攻撃への対策
ソフトウェア利用者としての対策
BOF攻撃はソフトウェアのバグが原因となっているため、その対策としては、OSや使用しているソフトウェアのバージョンアップ、バッチの適用を確実に行うことで既知のセキュリティホールを防ぐことに月る。ソフトウェア利用者として取るべき主な対策を次にあげる。
- 予防
- OS及び使用しているソフトウェアのバージョンを最新化し、バッチを適用する
- 脆弱性検査を実施し、BOF攻撃に関するセキュリティホールが塞がれていることを確認する。
- ファイアウォールによって不要なポートへのアクセスを遮断する
- サービス提供しているポートに対するBOF攻撃をIPSによって遮断する(通常のファイアウォールではパケットのデータ部分(ペイロード)を詳細にチェックしていないため、BOF攻撃を検知・遮断することができない)
- DEP(データ実行防止機能)が利用可能なOSを使用し、当該機能を有効に設定する。ただし、この対策を行ったとしても、retusn-to-libcのようにして以外の領域にあるプログラムを起動させるタイプのBOF攻撃や、BOF攻撃の対策となったプログラムが異常終了することを防ぐことはできない
- アドレス空間配置ランダム化(ASLR)技術が実装されたOSを使用する
- setuid/setgid 属性を持つプログラムに次の手順で対策する ①findコマンドを使用して所有者がroootでsetuid/setgid属性を持つプログラムを探す ②上記プログラムの中で、不要なものを削除する ③上記②で削除できないものの中で、setuid/setgid属性が不要なものについてはパーミッションを変更してsetuid/setgid属性を解除する
- 検知・追跡
- ネットワーク監視型IDS、ホスト監視型IDS、IPSを用いて検知する
- ホストのログが改竄・消去などされずに保存されていれば、それを用いて追跡調査を行う
- 回復
- サーバログ、IDSログなどから原因(脆弱性)を特定し、ベンダーが公開している対策手順に従って対処する。
- 不正アクセスを受けたホスト及び、当該ホストからアクセス可能な全てのホストを対象に、データの改竄、不正プログラムの埋め込み、設定変更など有無を徹底的に検証し、問題箇所を修復する(状況によってはOSをクリーンインストールし、サーバ環境を再構築する)
- 予防対策と同様に脆弱性検査を実施し、問題箇所あれば対処する
ソフトウェア開発者としての対策
ソフトウェア開発者としてはBOF攻撃について十分理解し、その原因となるバグを作らないようにすることが求められる。C/C++言語による開発を行う上で考えられる対策の具体例を次に挙げる。
- gets、strcpy、strcatなど、BOFを引き起こす危険性の高い関数を使用しないようにする
- 入力データのレングスチェックを確実に行う
- スタック寿王に埋め込んだ攻撃検知用の値によってBOF攻撃を検知する。これを実現するものとして、GNU Cコンパイラの拡張版であるStackGuardがある。StackGuardでコンパイルされたプログラムはサブルーチンを呼び出す際に、スタック中の変数とリターンアドレスの間に「カナリア(”カナリア値”というもの)」と呼ばれる値を埋め込んでおき、サブルーチン実行後にカナリアの値が変更されているかどうかを書くにすることで、BOF攻撃を検知する。なお、改竄を検知した場合はプログラムを強制的に停止させる。
- StackGuardと同様に、スタック領域に「カナリア」もしくは「guard」と呼ばれる値を埋め込むことにより、BOF攻撃を検知する技術として、SSP(Stack Smashing Protection)がある。StackGuardはアセンブラレベルでコンパイラを拡張していることから特定のCPUのみをサポートしているのに対し、SSPはコンパイラにより生成される中間言語にBOF検出のためのコードを生成するため、様々なCPU環境で利用することが可能である
- BOF防止機能を追加したライブラリを使用する。これを実現する代表的なものとして、Libsafeがある。Libsafeは、プログラム実行時にBOFを引き起こす危険性の高き主な関数の呼び出しを検知すると、ライブラリからの関数の呼び出し順序を変更し、BOFをチェックする関数を先に実行させることで不正なコードの実行を防ぐ。LibsafeはStack Guardとは異なり、コンパイル済みのプログラムに適用できるという特徴がある
- Libsafeと似たBOF防止技術として、GCCバージョン4.0から導入うされたAutomatic Fortificationがある。AutomaticFortificationは、strcpyのようにBOFを引き起こす危険性の高き関数をコンパイル時に別な安全性の高い関数に置換する技術である。
確認問題2
配列を用いてスタックを実現する場合の構成要素として、最低限必要な者はどれか。
ア スタックに最後に入った要素を示す添字の変数
イ スタックに最初に入った要素と最後に入った要素を示す添字の変数
ウ スタックの一つまに入ったよそを示す添字の変数を格納する配列
エ スタックの途中に入っている要素を示す添字の変数
スタックはデータ記憶構造の一種であり、最後に入った要素が最初に読み出される「後入れ先だし(Last In First Out:LIFO)」となっている。そのため、最後に入った要素を示す添字の変数が最低限必要である。
したがってアが正解