CSAPP LAB之a(chǎn)ttacklab,緩沖區(qū)溢出、ROP、CI

此lab針對的是原書3.10.3和3.10.4的內(nèi)容,利用緩沖區(qū)溢出改變原系統(tǒng)的執(zhí)行路徑,實現(xiàn)系統(tǒng)入侵,有點黑客的意思了。通過這個lab可以對系統(tǒng)漏洞有更直觀的認識,并且了解系統(tǒng)入侵的基本思想和思路,也能對程序的機器級表示有更加深入的理解。
Phase1
通過插入字符串,讓getbuf函數(shù)返回后執(zhí)行touch1函數(shù)。這個比較簡單,我們知道函數(shù)返回會從棧中彈出返回后下一條指令的地址,而且這個地址是調(diào)用該函數(shù)時壓入棧的,在該函數(shù)調(diào)用棧的最頂端,所以我們只要改變這個地址為touch1函數(shù)的入口地址即可。
1、 反匯編ctarget
objdump -d ctarget > ctarget.d
2、 找到getbuf函數(shù)

? ? ? ?它將棧指針減了0x28(40),第2、3條表示將棧指針作為參數(shù)調(diào)用Gets函數(shù),將得到的字符串放到棧上,由于只有0x28大小,所以超過這個數(shù)就會溢出,緊挨著的就是返回地址,所以只要在剛好溢出的地方放touch1的地址就可以。

touch1的地址是0x4017c0,

前0x28個字符可以是任意普通字符(不能是0a),最后8字節(jié)填入c0 17 40 00 00 00 00 00即可(實測高32位的0不填也行)。注意字節(jié)順序,棧是從低到高存的,所以touch1地址也要從低到高排列。

Phase2
通過插入字符串,讓getbuf函數(shù)返回后執(zhí)行touch2函數(shù),并以cookie值作為參數(shù)。此題相對1多個參數(shù)傳入,傳入?yún)?shù)也就是將cookie值放到%rdi寄存器中,所以這里需要一條mov指令,所以整體思路是getbuf返回地址是棧上的某個地址,這個地址的內(nèi)容是mov指令,將cookie值放到%rdi中,然后將touch2的地址push入棧,再ret返回到touch2函數(shù)。(push將值放入棧頂,ret將棧頂彈出作為返回地址)

指令的機器碼可以通過gcc -c exploit.s先編譯為exploit.o,再用objdump -d exploit.o反匯編得到。

注釋部分是另一種實現(xiàn),可以取代5、6兩行的指令。
Phase3
同Phase2類似,只是這次傳入的參數(shù)是字符串指針,cookie作為字符串。此題的難點在于字符串放的位置,因為touch3在使用cookie前會調(diào)用其他函數(shù),這個過程會對棧產(chǎn)生影響,有可能把字符串覆蓋掉,所以字符串放的位置要注意。因為棧是向低地址生長的,所以把字符串放在高地址處,也就是getbuf返回地址的棧區(qū)之上。

其他跟2一樣,只是mov的不是cookie了,而是cookie字符串的地址。

Phase4
任務(wù)跟Phase2一樣,只是這次的目標文件是rtarget,它不僅實現(xiàn)了棧隨機化,而且代碼不能在棧區(qū)運行,所以之前的方法就失效了。這次用的方法是Return-Oriented Programming(面向返回編程),利用程序已有的代碼實現(xiàn)自己的目的。
我們的思路可以有多種,比如
1、 把cookie的值放到棧上,pop到rdi中;
2、 把cookie的值放到棧上,pop到rax中,再mov到rdi中;
3、 把cookie的值放到棧上,rsp+偏移得到cookie地址,mov到rdi中;
4、 把cookie的值放到棧上,rsp+偏移得到cookie地址,mov到rax,再mov到rdi中;
還有n多思路,之所以要搞這么多是因為目標代碼不一定正好有我們需要的指令,比如此例中在規(guī)定的范圍內(nèi)就沒有popq %rdi,所以1就排除了,然后官方說兩個gadgets就能搞定,那很可能是2。(3、4涉及到加法,比較復(fù)雜,phase5會用到)
這里我剛開始理解錯了,認為必須用反匯編后的完整指令,比如下面這個

我以為必須以40199a為起始地址,用這個完整的指令,后來才知道可以任意選取起始地址,比如上面78 90 90就可以組成一個指令,地址是40199c。
OK,我們找找看有沒有popq %rax和mov %rax,%rdi。下面的58和48 89 c7剛好就是,地址分別是0x4019ab和0x4019c5。

所以最終的路徑是getbuf->popq->mov->touch2

Phase5
跟Phase3的任務(wù)一樣,但是要用Return-Oriented Programming。基本思路很簡單,得到rsp的值,加上cookie的位置偏移,放到rdi中,調(diào)用touch3。實現(xiàn)路徑也是有很多,難點是能不能在目標代碼中找到對應(yīng)的機器碼。有一點要注意,因為棧隨機,64位棧地址高32位不一定是0,所以mov時只能用movq。
這里關(guān)鍵是處理加法,仔細的小伙伴會發(fā)現(xiàn)目標代碼中有個add_xy函數(shù),這個可以利用;還可以找add和lea的機器碼,最后找到addb的04指令,不過它直接加了0x37,而且巧合的是它剛好在add_xy函數(shù)里。

所以有兩個思路,一個是準備好rsi和rdi調(diào)用add_xy,一個是將rsp放到rax,加0x37,所以要把cookie字符串放到rsp后0x37的地址處。
方法1:實現(xiàn)路徑
????????rsp->rax->rdi,
????????popq %rax
????????eax->edx->ecx->esi
????????add_xy
????????rax->rdi
????????touch3
具體怎么找到的,就是一個個試,比如esi/rsi那一列的機器碼一個個搜,就能找到哪個寄存器能給esi/rsi賦值,然后繼續(xù)直到eax/rax,或者能用popq D得到值。這個剛好符合官方的8個gadget。

方法2:
????????rsp->rax
????????rax+=0x37???? 這里雖然只加低8位,但不影響高24位
?????? ?rax->rdi
????????touch3
這個是我網(wǎng)上找的,更簡單,0x37的位置也OK,沒有給程序帶來崩潰、段錯誤等副作用。

OK,以上就是attacklab的5個Phase解答,這個lab說簡單也簡單,理論和思路不難,說復(fù)雜也復(fù)雜,需要找合適的gadget,尤其是Phase5,非常需要耐心。希望本文對大家有所幫助,歡迎大家討論交流。