ペネトレーションテスト&バグバウンティ
「バッファオーバーフロー」は聞いたことがある人もいるかもしれません。
「ヒープオーバーフロー」はその仲間で、ちょっとレベルアップしたメモリのバグなんです。
ヒープとは
プログラムが動くとき、データはメモリという場所に入ります。
このメモリには「スタック」と「ヒープ」という2つの場所があります。
ヒープとは、プログラムが実行中に必要になったメモリを動的に確保するための領域です。
C言語では malloc() や free() を使って、ヒープ領域を管理します。
ヒープとスタックの違いについて
比較項目 |
ヒープ |
スタック |
用途 |
実行中に動的に確保 |
関数内の一時的な変数 |
メモリ管理方法 |
手動(malloc/free) |
自動(関数の呼び出し・終了で管理) |
プログラムがメモリ(RAM)を使うときに、どの場所を使っているか |
低いアドレスから上に向かって使われる |
高いアドレスから下に向かって使われる |
ヒープオーバーフローとは
確保したヒープ領域を超えてメモリを書き込んでしまうバグのこと。
たとえば、malloc(16) で16バイトのメモリを確保したのに、
strcpy()などで32バイト以上のデータを書き込むと、隣のヒープチャンクや管理データが破壊されます。
これが「ヒープオーバーフロー」です。
※チャンクとは
ヒープの中で使われる、メモリの「ひとかたまり(ブロック)」のことです。
たとえば、お弁当箱で考えてみますと、
ヒープは、「お弁当箱」みたいな大きな入れ物です。
その中に「おかずを入れる小さい容器(チャンク)」をいくつも並べて使います。
・ヒープ:お弁当箱(全体のメモリ領域)
・チャンク:中に入っている小さいタッパー(確保したメモリのブロック)
となります。
プログラムが、malloc(32)をすると、ヒープの中に「32バイト分のチャンク」が作られます。
でも実際には、プログラムが使う「データの領域」だけでなく、その前後に管理情報(メタデータ)がくっついています。
もしヒープオーバーフローで「となりのチャンクのメタデータ」を書き換えてしまうと
解放されたときにメモリの管理がおかしくなって、攻撃者が「好きな場所にデータを書き込める」ようになってしまいます。
ヒープオーバーフローの発生原因
・strcpy(), memcpy(), strcat() などの境界を確認しない関数。
・malloc() で確保したサイズよりも多くのデータを操作。
・自前のバッファサイズチェックが甘いコード。
ヒープオーバーフローの簡単な例(C言語)
1.プログラム
ファイル名はたとえば heap_overflow.c にします。
nano heap_overflow.c
下記のコードを貼り付けて、Ctrl + O → Enter → Ctrl + X で保存します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *a = malloc(16); // 16バイトのメモリを借りる
char *b = malloc(16); // もう1つ借りる
strcpy(a, "AAAAAAAAAAAAAAAAAAAAAAAAAAAA"); // 長すぎる情報(28文字)
printf("a: %s\n", a);
printf("b: %s\n", b); // b の中まで書きかわってしまうかも
free(a);
free(b);
return 0;
}
このコードでは、
a に16文字以上を入れることで、
b の内容や、ヒープを管理する情報まで壊してしまいます。
2.コンパイル
gcc -o heap_overflow heap_overflow.c -no-pie -fno-stack-protector
これは コンパイルエラーではなく、警告 なので、コンパイルは成功しています。作成された実行ファイルは ./heap_overflow
です。
3.実行
./heap_overflow
メッセージが表示されていますが、
ひとことで言えば、ヒープオーバーフローの実験は成功です。
メッセージ内容
a: AAAAAAAAAAAAAAAAAAAAAAAAAAAA
・a: のあとに「AAAA...」 strcpy()で入力した文字列が入っている
b:
・b: の表示がない bのチャンク構造(メタデータ)が壊れている可能性大
double free or corruption (out)
・ free(b); のときに、ヒープの管理情報(チャンク)がおかしくて、エラーを検出
zsh: IOT instruction ./heap_overflow
・ヒープの異常により、意図的にプログラムが強制終了(abort)されました。
つまり、a に28文字書き込んだことで、
隣にあった b のメタデータ(チャンク情報)が壊れ、
free(b) のときにヒープ管理機構が「これはおかしいぞ!」と検出した。
ということになります。
エクスプロイト手法について
・safe unlink 攻撃
古典的な攻撃で、解放時の双方向ポインタを使って任意書き換えします。
・fastbin attack
free()後の再利用ポインタを悪用します。
・tcache poisoning
tcacheという高速キャッシュを使った攻撃です。
ヒープオーバーフローの対策について
・Heap metadata hardening(チャンク構造の保護)
・Safe unlink(安全な解放処理)
・ASLR, NX(メモリ位置のランダム化・非実行化)
・使用後即解放・ゼロ初期化(安全なmalloc/freeの習慣)
ハッカーが使うヒープオーバーフローとは。しくみ、攻撃例、エクスプロイト手法までやさしく解説のまとめ
ヒープオーバーフローとは、プログラムが動的に確保したメモリ(ヒープ領域)に、予定より多くのデータを書き込んでしまうバグです。
これにより、隣接するメモリブロック(チャンク)の管理情報を上書きし、メモリの不正な操作や乗っ取りが可能になる危険性があります。
スタックと違い、ヒープはmalloc()などで必要なサイズを動的に確保し、free()で解放します。
しかし、strcpy()やmemcpy()など境界チェックのない関数で過剰に書き込むと、チャンクのサイズ情報やリンク構造が壊れます。
攻撃者はこの仕組みを利用して、tcache poisoningやfastbin attackなどの手法で任意のアドレスを上書きします。
古いシステムの環境では依然として有効な脆弱性になります。