今日は、Daily AlpacaHack の Day 6 である Buffer Overflow の問題を解きました!難易度は Easy と言うことで得く手順はとても簡単でしたが、忘れていた Buffer Overflow 関連の知識についておさらいできたので良い機会でした。
問題
与えられている情報
- Buffer Overflow の脆弱性があるCプログラム
- Docker関連のファイル
- 攻撃する際であるIPアドレス
方向性
Buffer Overflow によって is_admin という boolean 変数を上書きすることで、攻撃先の環境にある flag.txt の内容を見ることができるという内容です。
コード
問題がある部分は以下でした:
int main() {
char buf[10] = {0};
int is_admin = 0;
printf("name:");
read(0, buf, 0x10);
ここで read はシステムコールで、仕様は以下です
ssize_t read(int fd, void* buf, size_t count)
引数:
- fd: file descriptor. 入力をどこから読むか (0=stdin, 1=stdout, 2=stderr など)
- buf: 読み込んだデータを格納するバッファの先頭アドレス
- size_t: データを読み込む(コピーする)サイズ (単位はバイト)
戻り値:
- ssize_t: もし正の整数なら実際に読み込んだバイト数、0ならファイルの終端という目印、負の整数ならエラー
つまり、readは「入力情報が何であるにも関わらず、入力からcount分のメモリをbufにコピーする」ということです。
ここで問題なのが、ローカル変数bufのサイズが10であるにも関わらず、readの入力countが 0x10=16 であることです。つまり、もし入力文字列が10バイトを (正確には new line (Enter) が勝手に最後につくので9バイトを) 超えた場合は、ローカル変数の buf の範囲を超えてメモリに値がコピーされてしまうということです。
x86では通常ローカル変数は宣言されている順番に低いアドレスから高いアドレスへとメモリが割り当てられるので、bufのすぐ後にはis_adminが続きます。C言語では、0がFalseでそれ以外がTrueなので、「入力として何かしらの長さ10以上の文字列を書き込めば」is_admin が True に更新されて flag が得られるということです。
まとめ
今日はここまでです。難易度としては簡単めの問題でしたが、read関数の挙動などについて改めて復習できてよかったです。