午前I問題

C言語・C++等で動的に確保されるメモリ(ヒープ領域)の管理に関する記述として、適切なものはどれか。

ア)動的に確保したメモリ領域は、free()(またはそれに相当する解放処理)を呼び出した時点でOSに返却され、以後そのメモリ領域を指すポインタ(ダングリングポインタ)を経由してアクセスすると、未定義の動作(既に別の目的で再利用されたメモリへのアクセス等)を引き起こす可能性がある。

イ)動的に確保したメモリは、プログラム終了まで自動的に有効であり続けるため、解放処理を意識する必要は一切ない。

ウ)ガベージコレクション(GC)を持たない言語であっても、コンパイラが全てのメモリ解放漏れ・二重解放を実行前に検出し、自動的に修正するため、開発者が意識する必要はない。

エ)解放済みメモリへのアクセスは、必ずプログラムのクラッシュという形で即座に検知されるため、セキュリティ上の実害にはつながらない。

午前I の解答・解説を見る

正解: ア

解説:

  • ア)正解。free() はメモリをアロケータに返却するだけで、ポインタ変数自体は自動的にNULL化されない。解放後もそのポインタ(ダングリングポインタ)を使い続けると、既に別の用途で再利用されたメモリ領域を読み書きしてしまう「Use-After-Free(UAF、解放後使用)」と呼ばれる未定義動作を引き起こす。
  • イ)不正解。手動でメモリ管理を行う言語(C/C++等)では、確保したメモリは明示的に解放しなければメモリリークが発生する。
  • ウ)不正解。コンパイラの静的解析には限界があり、全ての解放漏れ・二重解放を実行前に検出・自動修正することは一般に不可能である(検出を補助する静的解析ツールは存在するが完全ではない)。
  • エ)不正解。解放済みメモリへのアクセスは、クラッシュに至らず「たまたま」有効なデータが読めてしまう、あるいは攻撃者が制御可能な内容で上書きされたメモリを読み書きしてしまうことがあり、情報漏えいや任意コード実行につながる深刻なセキュリティ上の実害となり得る。

午前II問題

Use-After-Free(UAF)脆弱性および整数オーバーフローに関する記述のうち、最も適切なものはどれか。

ア)Use-After-Freeは、解放済みのメモリ領域へのポインタ(ダングリングポインタ)を通じたアクセスを悪用する脆弱性であり、攻撃者は解放されたメモリ領域を狙って別の攻撃者制御可能なデータで再確保(ヒープスプレー等)させることで、解放前のオブジェクトが持っていた関数ポインタ等を書き換え、制御フローを乗っ取ることがある。

イ)整数オーバーフローは、浮動小数点数の丸め誤差のみを指す用語であり、境界チェックの回避や意図しないバッファサイズ計算とは無関係である。

ウ)Use-After-Freeはガベージコレクションを持つ言語(Java、Go等)では原理的に発生し得ない一方、参照カウント方式やGCを持たないC/C++でのみ発生する脆弱性であるため、GC言語では一切のメモリ安全性対策は不要である。

エ)整数オーバーフローは符号なし整数(unsigned int)でのみ発生し、符号付き整数では発生しない。

午前II の解答・解説を見る

正解: ア

解説:

  • ア)正解。UAFの典型的な悪用パターンは、解放されたメモリ領域が再利用される前に、攻撃者が制御可能なデータで意図的に同じ領域を再確保させ(ヒープグルーミング/ヒープスプレー)、元のオブジェクトが持っていた仮想関数テーブルへのポインタ等を偽の値で上書きすることで、任意のコード実行につなげる手法である。ブラウザのJavaScriptエンジンの脆弱性として頻出する。
  • イ)不正解。整数オーバーフロー(アンダーフロー含む)は整数型の表現可能な範囲を超えた演算結果が折り返される現象であり、例えば符号なし整数の減算結果が負になる場合に非常に大きな正の値へラップアラウンドし、その値がバッファサイズやループ回数の計算に使われることで、境界チェックの回避やバッファオーバーフローを誘発する典型的な脆弱性原因となる。
  • ウ)不正解。GC言語ではオブジェクトそのものの解放後アクセスというC/C++的なUAFは起こりにくいが、unsafe コードブロックの利用や、GCと連携しない外部リソース(ファイルハンドル等)の扱い、あるいは並行処理に起因する類似のバグ(use-after-close等)は依然として起こり得るため、メモリ安全性への配慮が完全に不要になるわけではない。
  • エ)不正解。符号付き整数のオーバーフローも発生し得る(C言語では未定義動作となる)。符号なし・符号付きいずれでも発生し得る問題である。

午後問題

L社は画像処理を行うC++製のライブラリを自社製品に組み込んでいる。セキュリティ診断で以下の2つの問題が指摘された。

指摘①(Use-After-Free)

  • 画像デコード処理で使用する ImageBuffer オブジェクトについて、エラー発生時の例外処理パスで delete により解放されるが、呼び出し元の関数では解放後もそのポインタを使って後続の処理(ログ出力のためのメンバ変数アクセス)を継続してしまうコードパスが発見された。
  • 診断者はこの解放後アクセスの直前に、サイズや内容を制御した別のオブジェクトを大量に確保させることで、解放されたメモリ領域を意図した内容で再利用させることに成功し、後続処理で読み出される値を攻撃者の望む値に置き換えられることを実証した。

指摘②(整数オーバーフロー)

  • 画像ヘッダに含まれる「幅」「高さ」の値(ともに符号なし32ビット整数、unsigned int)を乗算してピクセルバッファのサイズを計算する処理 size_t bufSize = width * height * 4; が存在した。
  • 診断者が非常に大きな width と height の値を含む画像ファイルを与えたところ、乗算結果が32ビット整数の範囲を超えてラップアラウンド(オーバーフロー)し、実際に必要なバッファサイズよりはるかに小さい bufSize が確保される一方、後続のピクセル書き込み処理は元の width × height に基づいて行われるため、確保領域を超えて書き込みが行われる(ヒープバッファオーバーフロー)ことを確認した。

設問1

指摘①について、攻撃者が「解放されたメモリ領域を意図した内容で再利用させる」ために行う手法は一般に何と呼ばれるか。また、この手法がUAFの実害を「情報漏えい」や「制御フロー乗っ取り」に発展させる理由を50字以内で述べよ。

設問1の解答・解説を見る

正解例:

  • 手法の名称:ヒープグルーミング(ヒープフェンシング/ヒープスプレーとも呼ばれる、ヒープレイアウトの制御手法)
  • 発展する理由:解放領域を攻撃者が用意した任意データで埋めることで、後続の解放済みポインタ経由のアクセスが攻撃者制御下のデータを読み書きすることになるため(48字)。

解説: ヒープグルーミングは、メモリアロケータの再利用挙動を利用し、解放されたメモリ領域が次に何によって再確保されるかを攻撃者が制御する技術である。UAF単体では「たまたま」不定な値を読むだけだが、ヒープグルーミングと組み合わせることで、読み出される値・書き込まれる値の両方を攻撃者が制御できるようになり、情報漏えいや、対象がC++オブジェクトであれば仮想関数テーブル(vtable)ポインタの書き換えによる制御フロー乗っ取り(RCE)にまで発展し得る。

解説・採点基準(計15点):

採点項目キーワード配点
手法の名称にヒープグルーミング(類する用語)への言及ヒープグルーミング、ヒープスプレー5点
発展理由に「攻撃者制御下のデータで再確保」への言及攻撃者制御、任意データで埋める5点
発展理由に「読み書きが攻撃者の意図した値になる」旨読み書き制御、vtable書き換え5点

設問2

指摘②について、(1) このバッファオーバーフローが発生する根本原因を「整数オーバーフロー」という語を用いて50字以内で説明せよ。(2) 指摘①・②それぞれに対する恒久的な対策を1つずつ述べよ。

設問2の解答・解説を見る

正解例:

(1) 根本原因:width * height * 4 の乗算結果が32ビット整数の表現範囲を超えて整数オーバーフローし、実サイズより小さい値がバッファサイズとして確保されるため(49字)。

(2) 恒久対策:

  • 指摘①(UAF):オブジェクト解放後は速やかにポインタを nullptr に設定する、またはスマートポインタ(std::unique_ptr 等)を用いて所有権と生存期間をコンパイラに管理させ、解放後アクセスが構造的に発生しない設計にする。
  • 指摘②(整数オーバーフロー):サイズ計算の前にオーバーフローが発生しないことを検証する(オーバーフローチェック付きの演算関数を使用する、または計算前に上限値を設けて過大な width・height を拒否する)、あるいはより大きな整数型(size_t や64ビット型)にキャストしてから乗算する。

解説: UAF対策の本質は「解放とアクセスの分離を構造的に防ぐこと」であり、スマートポインタによる所有権管理はモダンC++における標準的な対策である。整数オーバーフロー対策は「演算前に範囲チェックを行う」「より大きな型で計算する」「言語・コンパイラのオーバーフロー検出機能(サニタイザ等)を活用する」ことが基本となる。いずれも根本原因はメモリ安全性・型安全性の欠如にあり、Rust等のメモリ安全言語への移行や、ASan/UBSanのようなサニタイザを用いた開発時検出も併せて有効な対策として挙げられる。

解説・採点基準(計15点):

採点項目キーワード配点
(1) 「乗算結果が範囲を超えてラップアラウンド」への言及整数オーバーフロー、範囲超過5点
(2) UAF対策にスマートポインタ/nullptr代入への言及スマートポインタ、nullptr5点
(2) 整数オーバーフロー対策にオーバーフローチェック/型拡大への言及オーバーフローチェック、size_t、上限検証5点

重要キーワード

用語説明
Use-After-Free(UAF)解放済みメモリ領域へのポインタ(ダングリングポインタ)を通じたアクセスによって発生する脆弱性
ヒープグルーミング解放されたメモリ領域を攻撃者が制御可能なデータで再確保させ、UAFの実害を拡大する手法
整数オーバーフロー整数型の表現可能範囲を超えた演算結果がラップアラウンドし、意図しない値になる現象
ダングリングポインタ解放済みで無効になったメモリ領域を指し続けているポインタ
スマートポインタオブジェクトの所有権と生存期間を自動管理し、UAFや二重解放を構造的に防ぐC++の仕組み
サニタイザ(ASan/UBSan)メモリ安全性・未定義動作をビルド・実行時に検出する開発支援ツール

まとめ

  • 午前I視点: 動的メモリ確保・解放の基本と、解放後もポインタが有効な値を保持し続けるためUAFが発生し得るという前提を理解する
  • 午前II視点: UAFの悪用にはヒープグルーミングが伴うこと、整数オーバーフローは符号の有無を問わず発生しバッファサイズ計算等に混入すると危険であることを押さえる
  • 午後視点: UAFはスマートポインタによる所有権管理、整数オーバーフローは演算前チェックや型拡大といった、それぞれの根本原因に対応した恒久対策を具体的に説明できるようにする