Stack Overflow 簡単説明
はじめに
こんにちは、クラウドエースの第一開発部に所属している申です。
今回は、 Stack Overflow についてご紹介します。
Stack Overflow
プログラミングにおけるバグの一種であり、またこれを利用した攻撃方法です。
プログラムが実行される際に、入力された値がバッファ[1]を満たすだけでなく溢れ出し、バッファ以降の空間を侵害する現象です。簡単に言えば、バケツ(バッファ)に水(値)を入れるとき(入力時)に、水を多く入れすぎて床に溢れてしまうようなものと考えればよいです。
主に、プログラムがユーザーからデータ(主に文字列)を入力される際に、ユーザーが指示通りにせず、すでに準備されたバッファよりも多くのデータを入力したときに発生しますが、ハッカーが逆に利用して任意にプログラムのメモリの値(主にスタック)を改ざんする際にも使われます。
この問題はスタックで主に発生するため、「スタックオーバーフロー(Stack Overflow)」とも呼ばれます。
メモリー構造
まず Stack Overflow を説明する前にメモリ構造について軽く知っておく必要があります。
- stack(スタック)[2]: スタックは後入れ先出しの特性を持つデータ構造で、最初に入ったデータが最後に出てくる構造を持っています。
-
heap(ヒープ): 動的なメモリで、動的割り当ての際に使用されるメモリです。
-
data(データ): 初期化されたデータが位置する領域で、グローバル変数、静的変数などが割り当てられる部分です。
-
code(コード): アセンブリや機械語のような命令が位置する領域で、実際のプログラム実行コードが格納される部分です。
この記事では、stack(スタック)でのバッファオーバーフローを実習します。
Stack Overflowの原理
このように、ユーザーがバッファを超える値を入力すると、バッファ以降の値が変更されることになります。
問題は、これをプログラムが全く認識していない状態であるということです。さらに、バッファ以降の値が変更されても、プログラムはこれをユーザーに通知する手段がありません。
重要ではない 10 行から 50 行程度の小規模な例示プログラムであれば、バッファオーバーフローの問題をあまり気にしなくてもよいかもしれません。しかし、中規模や大規模なプロジェクトでは、この原理を通じてハッキングが可能になるため、注意が必要です。
Stack Overflowで何ができるか
簡単な例として、10 桁のパスワードを入力するシステムがあると仮定しましょう。このとき、パスワードを保存する値のすぐ後ろにログインの成否を判断する値があるとします。(0 は失敗、それ以外の値は成功を意味します。)この状況で、末尾が 0 でない 11 桁のパスワードを入力すると、パスワードが間違っていてもシステムにアクセスできるようになります。
さらに、バッファを超えて入力された値がプログラムのリターンアドレス(RETN)を上書きすると、ユーザーがプログラムの実行フローを制御できるようになります。特定の関数が存在し、その関数のアドレスを知っていて、特定の入力がバッファオーバーフロー攻撃を可能にする場合、「入力された文字列 + 4/8 バイト(SFP 上書き用) + 該当する関数アドレス」を入力値として挿入すると、入力関数が終了したときに望む関数にジャンプできるようになります。
このような理由から、バッファオーバーフローの問題は大規模プロジェクトで特に注意深く扱われるべきです。
実習
目的のバッファのサイズを確認しない strcpy
を活用して、簡単な実習をしてみます。
#include <stdio.h>
int main() {
char var[10];
strcpy(var, "AAAAAAAVVVVVCXCCCCCDDDDDEEEEEFFFFFGGGGGHHHHH\n");
printf("%s", var);
return 0;
}
strcpy
関数を使用して var
配列に文字列をコピーしています。しかし、var
のサイズは 10 バイトであるのに対し、コピーしようとしている文字列はそれよりもはるかに長いです。これにより、バッファオーバーフローが発生します。
メモリ状態
バッファオーバーフローが発生すると、プログラムのメモリ状態は次のように変化します。
- EBP レジスタに「GGGGHHHH」という文字列が入ります。
- 戻りアドレス(ref)がある位置に「HHHH」文字列が挿入されます。
これにより、プログラムは元の位置ではなく、誤ったメモリ位置に移動し、プログラムの異常終了につながります。
結論
バッファオーバーフローは深刻なセキュリティ脆弱性であり、プログラムの安定性とセキュリティを損なう可能性があります。これを防ぐためには、入力データのサイズを厳密に検査し、安全な文字列処理関数を使用することが重要です。
Discussion