セキュリティセンターTOP > セキュアプログラミング講座 > C/C++言語編 > 著名な脆弱性対策 > バッファオーバーフロー: #3 ソースコードの静的検査

第10章 著名な脆弱性対策
バッファオーバーフロー: #3 ソースコードの静的検査

ソースコードを検査することは、さまざまな脆弱性を検出する有用な手段のひとつである。バッファオーバーフロー脆弱性に関しても例外ではない。

ソースコードからの兆候の見いだし

プログラムがバッファオーバーフロー脆弱性をもつという兆候を、特定の観点でソースコードを検査することによって見いだすことができる。

例えば、ソースコードが次の傾向をもつとき、領域がオーバーフローするバグの存在が疑われる。

  1. strcpy, sprintf 等、データ領域長を意識しないライブラリ関数の呼び出しがある
  2. strncpy, strncat 等、データ領域長を取り扱う関数の、領域長の算出式が誤っているおそれがある
  3. 文字列の収容領域長の算出の際に、終端のナル文字を考慮に入れていない
  4. インデックス変数がとるであろう最大値が、配列の要素数よりも大きい 等

上記に加えて次の特徴がある場合、バッファオーバーフロー脆弱性が疑われる。

  1. 外部からの入力値そのものや、入力文字列長を表す値が上記 1 〜 4 の箇所に伝搬している

また、次のような特徴にも注意が必要である。

  1. malloc/free, new/delete が多用されている
    → ヒープオーバーフローへの用心が必要
  2. 関数ポインタが多用されている
    → 近くの領域があふれれば、関数ポインタの書き変えが起こる
  3. 領域に入りきらないデータを切り捨てている
    → 入力検査の前にデータ末尾の切り捨てが起こると、攻撃パターンを見逃すおそれがある

ツールによるソースコード検査

脆弱性を生じるおそれのあるソースコード上の箇所の検出を試みるツールがある。あらゆる脆弱性を検出できるツールが存在するわけではないが、特定の種類の脆弱性については効率よく短時間で問題を検出してくれるものは存在するため、人手によるソースコード点検の負担の一部を軽減できる。

ツールによるソースコード検査
図10-3: ツールによるソースコード検査

(1) 関数名照合型検査ツール

strcpy等、取り扱いに注意を要するC言語のライブラリ関数を使用していると警告してくれるタイプの検査ツール(無償で提供されているもの)として下記のものが知られている。

(2) Coverity Prevent

C/C++ のソースコード検査ツール。Coverity Inc. の製品である。

このツールの下でプログラムのビルド手順を動作させることによって、コンパイラの構文解析結果を収集し、プログラムのロジックを静的に解析する。このツールは、関数呼び出し、変数の伝搬、ポインタの使用等を追跡し、問題のありそうなソースコード上の箇所を指摘する

http://www.coverity.com/

(3) HP Fortify Static Code Analyzer (SCA)

C, C++ のみならず、Java, C#, VB.NET, ASP.NET, JSP 等18の開発言語を対象とした、ソースコード検査ツール。FORTIFY SOFTWARE INC. の製品である。

このツールも、ツールの下でプログラムのビルド手順を動作させることによってコンパイラの構文解析情報を収集する。バッファオーバーフロー等の検査に用いるのみならず、スクリプト注入脆弱性、SQL注入脆弱性等、Webアプリケーションを検査する機能ももつ。

https://www.fortify.com/products/hpfssc/source-code-analyzer.html

(4) Visual Studio Team System の /analyze オプション

C, C++ のソースコードを検査するツール。Microsoft Corporation の製品である。

このツールは、Visual C++ のコンパイルオプションとしてはたらき、ソースコード上の問題を検査する。使用するにあたっては、標準的な Visual C++ のほかにVisual Studio Team System が必要である。

コンパイルオプションに /analyze を付けることによって、バッファオーバーフロー等の問題を指摘させることができる。

例 問題のあるソースコード foo.c
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4
 5 void main(void) {
 6    int  k;
 7    char buf[256];
 8    char work[8];
 9
10    gets(buf);
11    strcpy (work, buf);
12    for (k = 0; k < 12; k++) {
13       work[k] = 'A';
14    }
15 }
例 /analyze を指定してコンパイルしたときの警告メッセージ
  ------ ビルド開始: プロジェクト: foo, 構成: Debug Win32 ------
  コンパイルしています...
  foo.c
  c:\foo.c(10) : warning C4996: 'gets': This function or variable may be unsafe. Consider using gets_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
  c:\foo.c(11) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
※ c:\foo.c(10) : warning C6202: 'buf' のバッファ オーバーランです。'gets' への呼び出しでスタックが割り当てられた可能性があります: 長さ '4294967295' はバッファ サイズ '256' を超えています
※ c:\foo.c(11) : warning C6202: 'work' のバッファ オーバーランです。'strcpy' への呼び出しでスタックが割り当てられた可能性があります: 長さ '256' はバッファ サイズ '8' を超えています
※ c:\foo.c(13) : warning C6201: インデックス '11' は、有効なインデックスの範囲 '0' から '7' (スタックが割り当てられた可能性のあるバッファ 'work') を超えています
※ c:\foo.c(10) : warning C6031: 戻り値が無視されました: 'gets'
※ c:\foo.c(10) : warning C6386: バッファ オーバーランです: '引数 1' へアクセスしています。書き込み可能なサイズは '256' バイトですが、'4294967295' バイトを書き込む可能性があります: Lines: 6, 7, 8, 10
  ビルドログは "file://c:\Debug\BuildLog.htm" に保存されました。
  foo - エラー 0、警告 7

行頭に ※ のついた箇所が /analyze オプションによって出力された警告メッセージである。

まとめ

ソースコード丹念に調べれば、プログラムの動作の外見からは分かりにくい脆弱性の検出が可能である。しかしながら、人間の注意力のみに頼ってソースコードを読むやり方には多くの人員と長い時間が必要となる。すべてのものを検出できるわけではないが、ソース コード検査ツールを用いると、短い時間の中で効率的に問題を検出でき、ソースコード検査の助けとなる。