第10章 著名な脆弱性対策
バッファオーバーフロー: #1 概要
バッファオーバーフロー
C言語/C++言語で書かれたプログラムを最も悩ませる問題のひとつが、いわゆる「バッファオーバーフロー」問題である。いわゆるバッファオーバーフロー攻撃は、実行中のプログラムのメモリ内に攻撃者の手による機械語プログラムが送り込まれて実行され、最悪の場合、コンピュータ全体の制御が奪われることになる。

まずは「バッファオーバーフローを理解するための基礎知識」を確認していただきたい。
参考: 「CWE-119 Weakness ID:119(Weakness Class) Status: Draft バッファエラー 」
バッファオーバーフロー攻撃の種類
バッファオーバーフロー攻撃には次の種類がある。
- スタックを標的とした攻撃
- ヒープを標的とした攻撃
- 静的領域を標的とした攻撃
(1) スタックを標的とした攻撃
複数の種類の攻撃のうち、これまで最も実行が容易とされてきたのがスタックを標的としたバッファオーバーフロー攻撃である。これは「スタック破壊攻撃」(Stack Smashing Attack)とも呼ばれる。
スタックには、C言語/C++言語の関数のローカル変数(自動変数)と、その関数からのリターンアドレスの両方が置かれる。ローカル変数の領域あふれがおこることによって、容易にリターンアドレスの書き変えがおきる。
この病理メカニズムを悪用し、コンピュータを操るための機械語バイト列を入力データとして送り込むと同時に領域をあふれさせて関数リターンアドレスを辻褄が合うよう書き換え、送り込んだ機械語プログラムに制御を移させるのがこのタイプの攻撃である。
(2) ヒープを標的とした攻撃
ヒープ領域を標的としたバッファオーバーフロー攻撃も存在する。これは「ヒープ破壊攻撃」と呼ばれることがある。
ヒープ領域におけるバッファオーバーフロー攻撃は多くの場合、ヒープの未使用ブロックの管理に双方向リストと呼ばれるデータ構造が用いられていることを悪用するものである。この双方向リスト構造は、順序付けられたデータの集まりであって、そこに項目を追加したり削除する操作をポインタのつなぎ替えのみで素早く行う仕組みである。
双方向リストを操作してヒープを管理するライブラリの実装によっては、このポインタのつなぎかえのアルゴリズムが無防備であり、メモリ上の任意の箇所への任意の値の書き込みに悪用できるものがある。
攻撃者は、この方法でプログラム内のジャンプアドレスを書き換えて、送り込んだ侵入コードに制御を移す。書き換えの標的となるジャンプアドレスには、関数のリターンアドレス、例外ハンドラアドレス、関数ポインタ変数等がある。
(3) 静的領域を標的とした攻撃
静的領域を標的としたバッファオーバーフロー攻撃は、あふれさせることのできる変数の後方(アドレスが大きくなる方向)の比較的近くに、書き換えてプログラムの制御を奪うことのできるジャンプアドレスが置かれている場合に仕掛けられる。
(4) 対象プログラムを解析して攻撃プランを練る
攻撃を成功させるには、上記3種類の手口とも、プログラムのおおよその動きとメモリ配置がどのようになっているかを攻撃者が把握する必要がある。
広く配布されている製品ソフトウェアのバイナリコードの入手は困難でなく、リバースエンジニアリングに使うことのできるデバッガソフトウェアも多くのものが出回っている。
バッファオーバーフロー対策
バッファオーバーフロー攻撃への対策は次のようなものである。
(1) 攻撃成功要因の阻害
バッファオーバーフロー攻撃は、次のすべてが成立した場合に成功する。
- 要因A.
プログラムの内部に侵入用の機械語コードを送り込むことができる - 要因B.
領域あふれ等によってジャンプアドレスの書き換えができる - 要因C.
実際にジャンプアドレスの先へプログラムの制御を移すことができる - 要因D.
侵入用の機械語コードがプロセッサによって実行される
対策は、これらの要因の成立をひとつ以上阻害することによって、攻撃を失敗に終わらせることである。これらに対する阻害手段として次のものが考えられる。(なお、どの手段も100%完璧ではあり得ないことにご注意いただきたい)
- 阻害手段A. (要因A の阻害)
ソフトウェアの仕様によっては入力データの正当性検査を厳しく行うことによって、機械語コードが入り込む余地をなくすことができる場合がある - 阻害手段B. (要因B の阻害)
プログラムを堅固に記述することにより領域あふれをおこさないようにする。(ただし、プログラムミスをゼロにすることはできないと考えるべきである) - 阻害手段C. (要因C の阻害)
事後であっても領域あふれがおこったことを検知できれば、その時点でプログラムを止める等によって、ジャンプアドレスへのプログラム制御の移行を行わないようにすることができる - 阻害手段D. (要因D の阻害)
外部から送られてきたデータを受け取る領域、スタック、ヒープ、静的変数領域等におかれたバイト列を機械語命令として実行することを禁ずる仕組みがあれば、侵入コードは動作しない
(2) 工程別の対策
バッファオーバーフロー脆弱性対策には多くのものが考案されている。開発工程の中のタイミング別に見ると、次のようになる。
- ソースコード記述時の対策
領域あふれを未然に防ぐべく配慮してソースコードを記述する対策である。 その中には、コード記述時に領域長とデータ長を常に意識することと、 場合によっては動的に領域を確保すること、 対策されたランタイムライブラリを利用すること等が含まれる。
→ これは前述の 阻害手段B. のひとつである。 - ソースコードの静的検査
記述済のソースコードを領域あふれ等の観点から検査し、 造り込まれた脆弱性を最も早期に見つけ出すものである。 その中には、目視によるチェックと、 短時間に問題を見つけ出すことのできるソースコード検査ツールの利用が含まれる。
→ これも前述の 阻害手段B. のひとつである。 - あふれを検出するデバッグ
プログラムのデバッグの際に領域あふれの問題を見つけるものである。 その中には、領域あふれを検出できるデバッガや、 領域あふれを報告してくれるランタイムライブラリの使用が含まれる。
→ これも前述の 阻害手段B. のひとつである。 - 運用環境における防御
プログラムのリリース後に、 ソフトウェアの運用環境の機能を利用してバッファオーバーフロー攻撃を阻止するものである。 その中には、コンパイラを利用したスタック破壊検出、 オペレーティングシステムの機能を利用したアドレス空間レイアウトのランダマイズ、 CPUの機能を利用したデータ実行防止が含まれる。
→ スタック破壊検出とアドレス空間レイアウトのランダマイズは前述の 阻害手段C、 データ実行防止は 阻害手段D. にそれぞれ該当する。
これらの具体的な内容については、後続の次の記事を見られたい。