Cプログラマへの道 #9 - バッファオーバーフロー

Last Edited: 8/9/2024

このブログ記事では、バッファオーバーフローについて紹介します。

C Buffer Overflow

NULL終端文字列

C言語で文字列を初期化するとき、文字列の終わりを示すために自動的に\0(またはASCIIで0)が文字列の末尾に追加されます。そのため、5文字を格納したい場合は、 サイズ6のバッファを用意する必要があります。

int main () {
    char buffer[6];
 
    buffer[0] = "1";
    buffer[1] = "2";
    buffer[2] = "3";
    buffer[3] = "4";
    buffer[4] = "5";
    buffer[5] = "\0"; // または0
 
    return 0;
}

この方法は、文字列の長さを格納する必要がなく、4バイトを節約できるため、文字列を実装するのに便利です。しかし、 これは重大なセキュリティ上の脆弱性を引き起こす原因でもあります。

バッファオーバーフロー

次に、NULL終端文字を忘れた場合に何が起こるかを見てみましょう。

#include <string.h>
 
int main() {
    char buffer[6];
 
    buffer[0] = "1";
    buffer[1] = "2";
    buffer[2] = "3";
    buffer[3] = "4";
    buffer[4] = "5";
    // buffer[5] = "\0"; // または0
 
    printf("len: %d", strlen(buffer)); // 正常に動作しません
 
    return 0;
}

上記のstrlen操作は、\0が検出されるまで続行するため、バッファ内に\0が存在しないと正常に動作しません。 これは、strcpyでバッファにより大きな文字列を割り当てようとしたときにも発生します。strcpy\0が見つかるまで文字をコピーし続け、 バッファ外の値が変更される原因となります。これがバッファオーバーフローと呼ばれるもので、ハッカーはこれを利用して様々な 攻撃を行うことができます。

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

次に、main関数が以下のようにユーザー入力の文字列を受け取ると仮定しましょう。

int main (int argc, char *argv[]) {
    // argc: 引数の数
    // argv: 引数の値
 
    char buffer[500];
    strcpy(buffer, argv);
    printf("%s", buffer);
 
    return 0;
}

この関数はユーザー入力の文字列を受け取り、その文字列をサイズ500のバッファにコピーし、そのバッファを表示します。ここで、バッファオーバーフローを使用して、 バッファが受け入れられる容量を超えて文字を割り当てることで、メモリの任意の部分を変更することが可能になります。これにより、戻りアドレスにオーバーフロー するように文字列を挿入し、文字列に埋め込まれた悪意のあるコードを指すようにすることができます(これにより、ファイルへのスーパーユーザーアクセスを取得し、 情報を盗むことも可能になります)。詳細について興味がある方は下のリソース欄にあるComputerphileのビデオを見ることをお勧めします。

C言語におけるNULL終端文字列によるバッファオーバーフローの悪用は、バッファオーバーフロー攻撃と呼ばれ、Cプログラマーはこれに注意する必要があります。

対策

幸いなことに、このような攻撃に対抗するために、ユーザー入力文字列を安全に処理する対策を講じることができます。例えば、strcpyの代わりにstrncpyを使用し、 バッファ内の文字だけにアクセスできるようにします。

int main (int argc, char *argv[]) {
 
    char buffer[500];
    strncpy(buffer, argv, 499); // 500文字目まで(\0までではない)
    buffer[499] = '\0'; // バッファの最後にNULL終端を明示的に追加
    printf("%s", buffer);
 
    return 0;
}

しかし、現実的に考えると、ヒープの安全性を管理するのが難しいのと同様に、これらの対策を常に忘れずに実装することは難しいです。これが、 今日多くのプログラミング言語が異なる方法で文字列を実装し、多くのプログラマーがC以外の言語を選ぶ理由でもあります。

クイズ

この記事では、学習した内容を確認するためのクイズを設けます。記事のメイン部分を読んだ後に、ぜひ自分で問題を解いてみることを強くお勧めします。各問題をクリックすると答えが表示されます。

リソース