バッファオーバーフローについて

バッファオーバーフローについてまとめてみました。

バッファオーバーフロー(Buffer Overflow)とは

 大量のデータをバッファにコピーすると、データがそのバッファのサイズを越えてあふれてしまうことがある。これがバッファオーバーフローである。

 これを利用して、システムをダウンさせたり、不正なプログラムを実行させる攻撃をバッファオーバーフロー攻撃(Buffer overflow attack)という。ここでは、代表的なバッファオーバーフロー攻撃であるReturn-to-libc攻撃(以下バッファオーバーフロー攻撃)について解説する。

スタックフレーム(Stack Frame)

 バッファオーバーフロー攻撃の仕組みを理解するためにはスタックフレームについての知識が必要になる。スタックフレームとは関数を呼び出す際にスタック上に積まれるデータをまとめたものである。(図1)



図1 スタックフレームのイメージ図

C言語のスタックフレームは基本的に図2のような構造をしている。



図2 スタックフレームの構造

ベースポインタは、現在実行中のスタックフレーム(アクティブなフレーム)の底(図2の通り正確には底の少し上)を指すレジスタである。
以前のBPの値というのは、呼出し側の関数のベースポインタの値で、関数終了時にベースポインタにコピーされる。
また、リターンアドレスとは、関数の処理終了後に次に実行するプログラムのアドレスのことである。

バッファオーバーフロー攻撃の基本的な仕組み

 例として以下のような関数funcを考える。

void func (char *s1) {
    char s2[16];
    strcpy(s2,s1);
}

 funcはchar型のポインタ変数s1を引数として受け取り、char型の配列s2にs1が指す文字列をコピーする。ここで、s1の指す文字列のサイズがs2のサイズを超えていた場合、3行目のstrcpy(s2,s1)でバッファオーバーフローが発生する。バッファオーバーフローが発生するとあふれたデータによってスタックが破壊(書き換え)されてしまう。(図3)



図3 バッファオーバーフロー

ここで最も問題となるのは、リターンアドレスが書き換わってしまうことである。悪意のある第三者が発生させたバッファオーバーフローによって、リターンアドレスを悪意のあるコードの先頭アドレスに書き換えられた場合、悪意のあるコードが実行されてしまう。



図4 バッファオーバーフロー攻撃

対策

 C言語C++は仕様上、バッファオーバーフローが起こりやすいため、コーディングの際には十分に気をつける必要がある。

具体的には、バッファオーバフローの発生の原因となりうる関数の使用はなるべく避け、入力される文字列の長さは常にチェックすることが大切である。