CTFのバッファオーバーフローを解く機会があったのでまとめてみました。
問題にアクセスすると2つのファイルがダウンロードできる。

vulnは32bitのelfであり、実行するとflag.txtを作れと言われる。指示に従い次のようにflag.txtを作成し、Hello Worldという文字列を格納する(格納する文字列は何でもOK!)。
echo "Hello world" > flag.txt
改めてvulnを実行すると、入力を求められるので適当な文字を入力するとプログラムが終了する。

この動きとタイトルから入力を工夫してバッファオーバーフローを起こす問題と推測できる。
適当に入力しオーバーフローが起こるか見てみる(今回は33文字とした)。

すると、flag.txtに格納した文字列であるHello Worldを表示することができた。
同様の入力をpicoのサーバーに送ってみる。

ローカル環境と同様にflagが表示される。
ここから、何が起こっていたかの解析に入る。動作は全てCコードに書いているので中身を確認する。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#define FLAGSIZE_MAX 64
char flag[FLAGSIZE_MAX];
void sigsegv_handler(int sig) {
printf("%s\n", flag);
fflush(stdout);
exit(1);
}
void vuln(char *input){
char buf2[16];
strcpy(buf2, input);
}
int main(int argc, char **argv){
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(flag,FLAGSIZE_MAX,f);
signal(SIGSEGV, sigsegv_handler); // Set up signal handler
gid_t gid = getegid();
setresgid(gid, gid, gid);
printf("Input: ");
fflush(stdout);
char buf1[100];
gets(buf1);
vuln(buf1);
printf("The program will exit now\n");
return 0;
}
動作を順に追っていく。
まずはmain関数から。
- flag.txtから文字列を読み取る
- flag.txtがない場合はPlease create 'flag.txt' in ...を表示する
- flag.txtから読み込んだ文字列をflagという変数に格納する
- セグメンテーション違反が発生した場合、sigsegv_handler関数を実行するようイベントを登録
- 安全に操作を実行できるよう権限を編集
- Inputという文字列を出力
- Inputという文字列を画面に即時表示
- 100文字分の領域を持つbuf1という変数を定義
- 入力された文字列(画面に表示されたInputの後に入力した文字列)を変数buf1に格納する
- buf1を引数にvuln関数を実行する
- The program will exit nowを画面に表示する
次にmain関数で出たvuln関数とsigsegv_handler関数を見ていく。
vuln関数は受け取った引数を変数buf2にコピーしている。
この時使用するbuf2は16文字分の領域しか確保していないので入力した文字列が長い場合、オーバーフローを起こす。そして、このオーバーフローによりセグメンテーション違反が検知されsigsegv_handler関数が実行される。
sigsegv_hundler関数ではmain関数で取得されたflagを画面に出力する。
冒頭では適当に33文字入力したが、実際に必要な文字数は何文字なのかを確認してみる。
pwngdbでvuln関数のアセンブラを見てみる。

すると、アドレス0x00001358<+5>でスタック領域を初期化(ebpとespの参照アドレスを同一に)しアドレス0x0000135b<+8>で0x14だけスタック領域を広げていることが分かる。0x14は10進数に変換すると20なのでvuln関数では20文字分の領域を確保しているということ。つまり、入力した文字列が20文字を超えるとセグメンテーション違反を起こすはず。
確認してみる。

20文字はダメで21文字ならうまくいくと予想していたが、結果は20文字ならOK、19文字ならNGと1文字ずれてしまった。おそらくだが、改行を意味するヌルバイトが最後に入るため20文字入力でも1バイト分加算され条件をクリアしたのだろう。
簡単にではあるがbuffer overflow 0について解説してみた。
この記事が誰かの役に立てば幸いです。