バッファオーバーフロー ばっふぁおーばーふろー
簡単に言うとこんな感じ!
コップに水を入れすぎてあふれちゃうイメージだよ!プログラムが「ここに10文字分のデータを置いておく」って決めた場所に、100文字のデータを無理やり押し込むと、はみ出したデータが隣の大事な領域を上書きしちゃうんだ。それを悪用して攻撃者が「好きなコードを実行させる」ことができる怖い脆弱性なんだよ!
バッファオーバーフローとは
バッファオーバーフロー(Buffer Overflow)とは、プログラムが確保したメモリ領域(バッファ)の境界を超えてデータを書き込んでしまう脆弱性、およびそれを悪用した攻撃手法のことです。C言語やC++など、メモリ管理を手動で行う言語で書かれたプログラムに多く見られます。
バッファとは「一時的にデータを置いておく箱」のようなもので、たとえば「ユーザー名は最大20文字まで」と決めた領域がそれにあたります。プログラマーがこの境界チェックを怠ると、20文字を超えた入力が隣接するメモリ領域を上書きしてしまいます。この「はみ出し」によって、攻撃者が意図した任意のコードを実行させる(任意コード実行) ことが可能になります。
1988年のMorrisワームが初めてこの脆弱性を大規模に悪用して以来、数十年にわたって重大なセキュリティインシデントの原因であり続けています。現在でもCVE(共通脆弱性識別子)データベースの上位常連であり、システム発注側も「使用言語・フレームワークのセキュリティ対策」として認識すべき重要な概念です。
バッファオーバーフローの仕組み
メモリレイアウトと何が起きるか
プログラムが動作するとき、メモリは大きく分けて以下の領域に分かれています。
| 領域 | 役割 | 攻撃との関係 |
|---|---|---|
| スタック | 関数の引数・ローカル変数・戻りアドレスを置く | 最も狙われやすい(スタックオーバーフロー) |
| ヒープ | 動的に確保されるデータを置く | ヒープオーバーフローとして悪用される |
| テキスト領域 | プログラムの命令コード | 通常は書き込み不可 |
| データ領域 | グローバル変数など | BSS/データセグメントオーバーフロー |
最も古典的な攻撃はスタックオーバーフローです。スタック上にある「関数の戻りアドレス(処理が終わったらどこに戻るか)」を攻撃者が用意した悪意あるコード(シェルコード)のアドレスで上書きすることで、プログラムが攻撃者の意図した処理を実行してしまいます。
通常時のスタック:
┌────────────────────┐ ← 高位アドレス
│ 戻りアドレス │ ← 関数を呼び出した場所に戻るためのアドレス
├────────────────────┤
│ 保存済みレジスタ │
├────────────────────┤
│ ローカル変数 │
│ [buf: 16バイト] │ ← ここに入力データを格納
└────────────────────┘ ← 低位アドレス(書き込みはここから上方向)
攻撃時(20バイト以上の入力を流し込む):
┌────────────────────┐
│ ★悪意のアドレス★ │ ← 戻りアドレスが上書きされた!
├────────────────────┤
│ (上書きされた) │
├────────────────────┤
│ AAAAAAAAAAAAAAAAA │ ← bufを超えてあふれた入力データ
│ AAAA...シェルコード│
└────────────────────┘
覚え方
「バッファ(箱)にオーバーフロー(あふれ)させてリターン(戻り先)を乗っ取る」——箱・あふれ・乗っ取りの3ステップで覚えよう!
攻撃の種類
| 攻撃の種類 | 標的 | 特徴 |
|---|---|---|
| スタックバッファオーバーフロー | スタック上の戻りアドレス | 古典的・最も有名 |
| ヒープバッファオーバーフロー | ヒープの管理構造 | 現代的なブラウザ攻撃に多い |
| 整数オーバーフロー起因 | バッファサイズ計算 | サイズ計算が誤ることでバッファを小さく確保させる |
| フォーマット文字列攻撃 | printfなどの書式 | 厳密にはオーバーフローではないが同系統の危険 |
歴史と背景
- 1972年 — 米国防総省のCSCレポートで「バッファオーバーフロー」の危険性が初めて文書化される
- 1988年 — Morrisワームがfingerdの脆弱性(スタックオーバーフロー)を悪用。インターネット上のマシンの約10%(約6,000台)に感染し、初の大規模インターネットワームとして歴史に刻まれる
- 1996年 — Aleph One(Elias Levy)が雑誌Phrackに「Smashing the Stack for Fun and Profit」を発表。攻撃手法を体系的に解説し、セキュリティ研究の転換点となる
- 1998〜2003年 — WindowsのIIS・sendmail・OpenSSHなど主要サーバーソフトで相次いで発見、Code Red・Slammerワームが猛威を振るう
- 2000年代以降 — コンパイラ・OSレベルの緩和策(後述)が普及。単純なスタックオーバーフローは成功しにくくなるが、ヒープオーバーフローやROP(Return-Oriented Programming)などより高度な手法に進化
- 現在 — ブラウザ・スマートフォンアプリ・IoT機器でも継続して発見。CWE(共通脆弱性タイプ)のCWE-119/CWE-121/CWE-122として分類・管理されている
防御策と緩和技術
現代のOSやコンパイラには、バッファオーバーフロー攻撃を困難にする複数の防衛レイヤーが組み込まれています。
| 防御技術 | 正式名称 | 効果 | 限界 |
|---|---|---|---|
| ASLR | Address Space Layout Randomization | アドレス予測を困難に | 情報リークと組み合わせると回避される |
| スタックカナリア | Stack Canary / Stack Cookie | 改ざん検知 | 番兵値が漏洩すると無効化される |
| DEP/NX | Data Execution Prevention / No-eXecute | シェルコード実行を防止 | ROPによって回避される |
| SafeStack | LLVM SafeStack | スタックを2つに分離 | コンパイラサポートが必要 |
| ROP対策(CFI) | Control Flow Integrity | 制御フローの整合性を検証 | オーバーヘッドが発生 |
ROPとは?(進化した攻撃)
DEP/NXによって「新しいコードを注入して実行」が難しくなると、攻撃者はROP(Return-Oriented Programming)という手法を開発しました。これはプログラム内にもともと存在する小さなコード断片(「ガジェット」と呼ぶ)をつなぎ合わせて、任意の処理を実現するというパズルのような攻撃です。DEP/NXでは防げないため、CFI(制御フロー整合性)が重要になっています。
関連する規格・RFC
| 規格・番号 | 内容 |
|---|---|
| CWE-119 | Improper Restriction of Operations within the Bounds of a Memory Buffer(バッファ境界外操作の不適切な制限) |
| CWE-121 | Stack-based Buffer Overflow(スタックベースのバッファオーバーフロー) |
| CWE-122 | Heap-based Buffer Overflow(ヒープベースのバッファオーバーフロー) |
| CVE共通識別子 | NVD(National Vulnerability Database)で個別の脆弱性を追跡・管理する仕組み |
関連用語
- 任意コード実行(ACE) — 攻撃者が任意のプログラムコードを標的システム上で実行できる状態
- スタックスマッシング — スタック領域を意図的に破壊するバッファオーバーフロー攻撃の別称
- ASLR — アドレス空間をランダム化することでバッファオーバーフロー攻撃を困難にする防御技術
- DEP(データ実行防止) — メモリ領域に「実行不可」フラグを立ててシェルコードの実行を防ぐ仕組み
- CVE — 公開された脆弱性に一意のID番号を付与して管理する共通識別システム
- ゼロデイ脆弱性 — パッチが提供される前に悪用される未知の脆弱性
- ペネトレーションテスト — 擬似的に攻撃を仕掛けてシステムの脆弱性を発見するセキュリティ検査
- メモリセーフ言語 — RustやGoのようにバッファオーバーフローをコンパイラレベルで防ぐ設計の言語