ソフトウエアの内部で入力データのチェックが十分ではない原因はいくつか考えられる。最も単純なのは、ソフトの開発者がチェックの実装を間違えてしまった場合だ。いわゆるソフトのバグである。

 例えば、ある入力データが32ビット以下でなければならないソフトがあったとする。ソフト開発者が誤って64ビット以下が正しいデータだと判定するようなコードを書いていた場合、攻撃者が32ビットよりも大きいデータを送っても、64ビット以下であれば正しいデータだとみなされてしまう。このようなデータを送られるとソフトが異常動作を起こす場合は、脆弱性になる。対策するには、誤った実装の部分を修正する必要がある。

データチェックの実装ミスで脆弱性が発生
データチェックの実装ミスで脆弱性が発生
ソフトの脆弱性は、不正なデータを不正だと判定できないために起こる。例えば、チェックの実装が誤っている場合、それを悪用して攻撃できる可能性がある。
[画像のクリックで拡大表示]

 こうしたサイズチェックの誤りがリモートコード実行の脆弱性を引き起こす場合もある。典型的なのが「バッファオーバーフロー」だ。

バッファオーバーフローで不正なプログラムが実行される仕組み
バッファオーバーフローで不正なプログラムが実行される仕組み
パソコンの内部では、関数の呼び出し時に「戻りアドレス」「ローカル変数領域」「バッファ領域」がスタックに確保される。バッファオーバーフローの脆弱性がある場合、攻撃者はバッファよりも大きいデータを送り込んでデータをあふれさせることでバッファの外のメモリー領域を書き換えられる。データに攻撃用プログラムを含ませておき、戻りアドレスをそのプログラムの先頭アドレスに書き換えると、攻撃用プログラムが実行されてしまう。
[画像のクリックで拡大表示]

 あるソフトで関数を呼び出した場合、パソコンの内部では、「戻りアドレス」「ローカル変数領域」「バッファ領域」がメモリー上の「スタック」という領域に確保される。これらは、メモリーのアドレスが大きいほうから小さいほうに向かって順番に配置される。

 バッファ領域よりも大きいデータをバッファに読み込ませないようにソフトがチェックしていれば問題ない。ところが、そうしたチェックがなかったり誤っていたりした場合には、攻撃者がバッファよりも大きいデータを送り込んでデータをあふれさせることで、バッファの外のメモリー領域を書き換えられる。

 戻りアドレスが書き込まれた箇所とバッファ領域の間の距離は、ローカル変数の大きさと個数がわかれば割り出せる。攻撃者はこの情報をコード実行に悪用する。送り込むデータに攻撃用プログラムを含ませておき、戻りアドレスがちょうど攻撃用プログラムの先頭アドレスに書き換わるようにスペーサーを挿入する。これにより、関数から呼び出し元に処理が戻る際に、書き換えられた戻りアドレスにジャンプしてしまい、攻撃用プログラムが実行される。