ペネトレーションテスト&バグバウンティ
プログラミングでは、コンピュータに「このメモリを使ってね」とお願いして、使い終わったら「もう返すね」と伝える必要があります。
でも、返したのに、また使ってしまうと・・・それはとても危険なのです。
ダングリングポインタとは?
ダングリングポインタとは、すでに無効になったメモリ(使えないメモリ)を指しているポインタのことです。
「その場所にはもう何もないのに、まだそこを見ている」状態です。
たとえば、あるポインタが free()されたメモリをまだ指していたり、関数が終わったあとの変数を指していたりすると、ダングリングポインタになります。
なぜ危険?バグや脆弱性の原因になる理由
ダングリングポインタを使うと
・予期しないデータを読み書きしてしまう
・プログラムがクラッシュする(セグメンテーションフォルト)
・他人のデータを誤って変更する
・攻撃者が細工したメモリを使わせる(エクスプロイト)
など、危険な動作やセキュリティ問題につながります。
難しいですね。簡単に説明すると・・・
1.学校の机を借りました。
2.授業が終わったから返しました。
3.でも、帰る前にまた勝手に使ってたら。
その机はもう誰かが使ってるかもしれないし、中に変なものが入ってるかもしれませんよね。
それと同じように、一度「返したメモリ」は、もう勝手に使ってはいけないのです。
これと同じことが、コンピュータの中でも起きてしまいます。
もっとわかりやすく説明すると
※イメージです。(^^;
発生する主なパターン
1.free()後のポインタを使ってしまう
Use-After-Free の原因にもなる
2.関数内のローカル変数のアドレスを返す
その変数は関数の終了と同時に消える
3.スコープを抜けた変数へのポインタ
有効な範囲(スコープ)を超えて使ってしまう
C言語の簡単な例で理解しょう
1.プログラム
ファイル名はたとえば dangling_pointer.c にします。
dangling_pointer.c
下記のコードを貼り付けて、Ctrl + O → Enter → Ctrl + X で保存します。
#include <stdio.h>
#include <stdlib.h>
int *createPointer() {
int num = 42;
return # // ← ローカル変数のアドレスを返す(危険)
}
int main() {
int *ptr = createPointer();
printf("%d\n", *ptr); // ← ダングリングポインタ
return 0;
}
このコードでは、createPointer()の中で作った変数numは、関数が終わったら消えてしまいます。
でもそのアドレスを返して使っているので、もう存在しない場所を参照しているのです。
2.コンパイル
gcc -o dangling_pointer dangling_pointer.c
※これは 「警告(warning)」 です。「ダングリングポインタの危険性」を GCCが警告しています。コンパイルは出来ています。
3.実行します。
./dangling_pointer
実行結果は、
これは、Segmentation fault
(セグメンテーションフォルト)は、「アクセスしてはいけないメモリにアクセスしたとき」に発生するエラーです。
これは、ダングリングポインタの実行結果として“正常”とも言える現象になります。
悪用(エクスプロイト)の可能性と攻撃例
攻撃者は、ダングリングポインタが指すメモリ領域を再利用させて、そこに悪意あるデータを置くことで、
本来のプログラムの動作を乗っ取ることができます。
例:Use-After-Free + ダングリングポインタ → tcache poisoning で任意の書き込み
攻撃者の目的は、「本来のプログラムの動作を乗っ取って、自分の好きな命令を実行させること」です。
攻撃の流れ(イメージ)
1.プログラムが malloc()でメモリを確保する。
2.free()でメモリを解放する。
※このとき、解放したメモリの情報は tcache(キャッシュ)に保存される。
3.まだポインタが残っている → ダングリングポインタ状態。
4.攻撃者がそのポインタを使って、tcacheの中身を改ざんする。(tcache poisoning)
5.次に malloc()されたとき、改ざんしたアドレスが返ってくる。
6.攻撃者は任意の場所にデータを書き込めるようになる。(任意の書き込み)
※tcache(ティーキャッシュ)とは
tcache は「最近使った小さなメモリのゴミ箱」のような仕組みです。
free()されたメモリの情報がtcacheに残っていて、次に malloc() するとそこからすぐ再利用できるのです。
※tcache poisoning(毒)とは
tcacheには「次はここを使ってね」というアドレス情報(ポインタ)が入っています。
この情報を、ダングリングポインタや、UAFを使って書き換えます。
すると、次のmalloc()が攻撃者が指定した場所のポインタを返すのです。
UAF+ダングリングポインタ→tcache poisoning の関係
・ダングリングポインタは、すでに free()されたメモリをまだ覚えている。
・Use-After-Freeは、そのポインタで実際に書き込みなどをしてしまう。
・tcache poisoningは、tcache の「次に使うアドレス」を悪意ある場所にすり替える。
結果として、次の malloc()で、攻撃者の指定したアドレスに書き込めるのです。
対策方法と安全なプログラムの書き方
・free()後は必ず NULL を代入
もう使えないとわかるようにする
・ローカル変数のポインタを返さない
戻り値で使いたいなら malloc()を使う
・スマートポインタを使う(C++など)
自動でメモリを管理してくれる
・ASAN で検出する
AddressSanitizer を使えば実行時にバグが見える
ハッカーが利用するダングリングポインタとは 解放済みメモリをさまよう危険なポインタのまとめ
ダングリングポインタは、「もう存在しないメモリを使ってしまう」という危険なバグです。
プログラムが突然クラッシュしたり、悪意ある攻撃に利用されることもあります。
安全なコードを書くためには、メモリの寿命を理解し、使い終わったポインタは消すという習慣を身につけることが大切です。