バッファオーバーフローとは

ばっふぁおーばーふろー

配列などの領域(バッファ)に、その大きさを超えるデータを書き込み、隣のメモリを壊してしまうこと。C言語では、書き込み先の大きさを知らない strcpy や gets、範囲を確かめずに添字を使うループなどで起こりやすく、未定義動作になる。スタック上のバッファがあふれると、局所変数や関数の戻り先の番地が書き換えられ、外から与えた入力で任意のコードを実行させる攻撃に悪用されることがある。大きさを指定できる関数や範囲の確認で防ぐ。

「バッファオーバーフロー」は、2分野の3問の練習問題に出てきます(リンカ・ローダと実行形式, C言語の基礎など)。

この用語の分野: C言語の基礎

よくある原因

終端の '\0' の1バイトを数え忘れて char name[8] に8文字を strcpy する、入力の長さを確かめずに gets や scanf("%s") で読む、for (i = 0; i <= N; i++) のように1つ多く書き込む、といった誤りが典型です。書き込み先の大きさを受け取らない関数では、どれだけ書くかを入力のデータが決めてしまいます。

攻撃への悪用と対策の仕組み

スタック上のバッファの近くには、関数の戻り先の番地が保存されています。攻撃者は長い入力でそこを書き換え、用意したコードやライブラリの関数に処理を移します。OSやコンパイラは、戻り先の手前に置いた値の変化を調べるスタック保護(カナリア)、書き込みと実行の分離(W^X)、番地のランダム化(ASLR)などで、悪用を難しくしています。

プログラムでの防ぎ方

strcpy の代わりに snprintf のような書き込む大きさを指定できる関数を使い、入力の長さと添字の範囲を必ず確かめます。開発中は -fsanitize=address(AddressSanitizer)を付けると、範囲外の書き込みを実行時に検出できます。MMUを持たないマイコンでは、あふれてもすぐには止まらずに隣のデータを壊すので、特に注意が必要です。

バッファオーバーフローの練習問題に挑戦

ASLR(アドレス空間配置のランダム化)の目的として正しいものはどれか。

  1. Aスタックやヒープ、ライブラリなどの番地を実行のたびに変え、攻撃者が狙う番地を予測しにくくする
  2. Bメモリの番地をランダムに選んで、キャッシュのヒット率を上げる
  3. C使っていないメモリをランダムに解放して、空き容量を増やす
答えと解説を見る

正解:A. スタックやヒープ、ライブラリなどの番地を実行のたびに変え、攻撃者が狙う番地を予測しにくくする

バッファオーバーフローなどを悪用する攻撃では、ライブラリの関数やスタック上のデータの番地を知っていることが重要です。ASLRは、プロセスを起動するたびにスタック、ヒープ、共有ライブラリ、実行ファイルを置く番地をずらし、攻撃者が番地を決め打ちできないようにします。単独で完全に防げるわけではなく、書き込みと実行の分離などほかの対策と組み合わせて使います。

メモリのページに「書き込み可能」と「実行可能」を同時には許さない(W^X、書き込みと実行の分離)ことで防ぎやすくなる攻撃はどれか。

  1. Aパスワードを総当たりで試す攻撃
  2. B大量の通信を送ってサーバを止める攻撃
  3. Cスタックなどのデータ領域に攻撃用の機械語を書き込み、そこへ飛ばして実行させる攻撃
答えと解説を見る

正解:C. スタックなどのデータ領域に攻撃用の機械語を書き込み、そこへ飛ばして実行させる攻撃

昔の攻撃では、バッファオーバーフローでスタックに機械語を書き込み、戻り先をそこへ向けて実行させる方法がよく使われました。CPUのページテーブルには実行禁止のビット(NXビットなど)があり、OSがスタックやヒープ、.dataを実行禁止に、.textを書き込み禁止にすれば、この方法は使えなくなります。JITコンパイラのように実行中にコードを作る場合は、書き込みと実行の権限を切り替えて使います。

よくある質問

バッファオーバーフローは必ずプログラムを止めますか?

止まるとは限りません。はみ出した書き込みが使われていない領域に当たれば何も起きないように見え、別の変数を壊せば離れた場所で誤った結果になります。戻り先の番地を壊したときやスタック保護が働いたときに、初めて異常終了することもあります。

strncpy を使えば安全ですか?

strncpy は指定した数の文字までしか写しませんが、元の文字列が長いと終端の '\0' を付けないので、その後の処理で範囲外を読むおそれがあります。大きさを指定して必ず終端を付ける snprintf を使うか、strncpy の後に自分で終端を書き込みます。

解説の中の「バッファオーバーフロー」

「バッファオーバーフロー」が出てくる問題(3問)

  1. ASLR(アドレス空間配置のランダム化)の目的として正しいものはどれか。
  2. メモリのページに「書き込み可能」と「実行可能」を同時には許さない(W^X、書き込みと実行の分離)ことで防ぎやすくなる攻撃はどれか。
  3. 上の関数 save に、8文字の文字列 "ABCDEFGH" を渡した。起こることとして正しいものはどれか。

C言語の基礎の参考書を探す PR

Amazonの検索結果へのリンクです。Amazonのアソシエイトとして、半導体教室は適格販売により収入を得ています。

関連する用語

スタック ヒープ リターンアドレス ASLR 共有ライブラリ ページテーブル 変数 アライメントとパディング 関数ポインタ 共用体

用語集の一覧へ