我是如何發(fā)現(xiàn)CCProxy遠(yuǎn)程溢出漏洞的
更新時(shí)間:2007年01月16日 00:00:00 作者:
CCProxy是一個(gè)國(guó)產(chǎn)的支持HTTP、FTP、Gopher、SOCKS4/5、Telnet、Secure(HTTPS)、News(NNTP)、 RTSP、MMS等代理協(xié)議的代理服務(wù)器軟件。因?yàn)槠浜?jiǎn)單易用、界面友好,非常適合在對(duì)流量要求不高的網(wǎng)絡(luò)環(huán)境中使用,所以在國(guó)內(nèi)有很多初級(jí)的網(wǎng)管喜歡用這個(gè)軟件,有時(shí)候我在公司上網(wǎng)也要用它做代理。前些日子我測(cè)試發(fā)現(xiàn)CCProxy 6.0版本存在多處緩沖區(qū)溢出漏洞,可以導(dǎo)致攻擊者遠(yuǎn)程執(zhí)行任意代碼。
TIPS:什么是Gopher、RTSP、MMS?
Gopher是Internet上一個(gè)非常有名的信息查找系統(tǒng),它將Internet上的文件組織成某種索引,很方便地將用戶從Internet的一處帶到另一處。允許用戶使用層疊結(jié)構(gòu)的菜單與文件,以發(fā)現(xiàn)和檢索信息,它擁有世界上最大、最神奇的編目。
RTSP是Real Tranfer Stream Protocol的縮寫,翻譯為實(shí)時(shí)傳輸流協(xié)議,用來(lái)傳輸網(wǎng)絡(luò)上的流媒體文件,如RM電影文件等,它的下載方法請(qǐng)看后文《悄悄下載流媒體》。
MMS是Multimedia Messaging Service的縮寫,中文譯為多媒體信息服務(wù),它最大的特色就是支持多媒體功能,可以在GPRS、CDMA 1X的支持下,以WAP無(wú)線應(yīng)用協(xié)議為載體傳送視頻短片、圖片、聲音和文字,彩信就算MMS協(xié)議中的一種。
漏洞發(fā)現(xiàn)過(guò)程
其實(shí)發(fā)現(xiàn)這個(gè)漏洞是很偶然的,當(dāng)時(shí)在考慮公司產(chǎn)品的黑盒測(cè)試方案的時(shí)候,我想使用模板+測(cè)試用例的方式來(lái)進(jìn)行網(wǎng)絡(luò)部分的邊界測(cè)試。這是比較傳統(tǒng)的黑盒測(cè)試方法,其核心內(nèi)容就是把網(wǎng)絡(luò)協(xié)議包分塊,然后制定出對(duì)各個(gè)塊的測(cè)試策略,最后按照策略對(duì)所有塊逐步進(jìn)行測(cè)試。這種測(cè)試方法的好處在于可以有效的控制測(cè)試進(jìn)度,以及可以比較詳細(xì)地測(cè)試一個(gè)網(wǎng)絡(luò)協(xié)議的所有部分,而且在測(cè)試過(guò)程中還可以不斷地加入新的測(cè)試用例,以完善測(cè)試計(jì)劃。測(cè)試程序的編寫則可以使用腳本語(yǔ)言或C來(lái)完成。
TIPS:什么是黑盒測(cè)試?
黑盒測(cè)試法把程序看成一個(gè)黑盒子,完全不考慮程序的內(nèi)部結(jié)構(gòu)和處理過(guò)程。黑盒測(cè)試是在程序接口進(jìn)行的測(cè)試,它只檢查程序功能是否能按照規(guī)格說(shuō)明書的規(guī)定正常使用,程序是否能適當(dāng)?shù)亟邮蛰斎霐?shù)據(jù)產(chǎn)生正確的輸出信息,并且保持外部信息的完整性。黑盒測(cè)試又稱為功能測(cè)試。
我就是用這種方法測(cè)試公司的產(chǎn)品的時(shí)候,恰好當(dāng)時(shí)在公司內(nèi)部網(wǎng)之間使用CCProxy做代理服務(wù)器,因?yàn)闇y(cè)試HTTP協(xié)議要通過(guò)這個(gè)代理,所以測(cè)試過(guò)程中發(fā)現(xiàn)CCProxy崩潰了,也因此發(fā)現(xiàn)了這個(gè)漏洞,算是偶然吧。
漏洞分析過(guò)程
CCProxy的HTTP代理端口默認(rèn)是808,這個(gè)端口可以在其界面中進(jìn)行更改。漏洞的原理很簡(jiǎn)單,就是對(duì)CCProxy的 HTTP代理端口發(fā)送URL超過(guò)4056字節(jié)的畸形請(qǐng)求,CCProxy就會(huì)發(fā)生堆棧溢出。后來(lái)發(fā)現(xiàn),不僅僅是GET請(qǐng)求存在此問(wèn)題,所有POST、 HEAD等請(qǐng)求也都會(huì)導(dǎo)致溢出。在分析其原理后又發(fā)現(xiàn)CCProxy的Telnet代理也存在該問(wèn)題。
現(xiàn)在來(lái)詳細(xì)介紹一下我分析這個(gè)漏洞的過(guò)程。在發(fā)現(xiàn)了發(fā)送超長(zhǎng)請(qǐng)求可以導(dǎo)致CCProxy出錯(cuò)以后,就開始分析溢出點(diǎn)以及利用限制。所要用到的工具是SOFTICE調(diào)試器和IDA反匯編工具。
TIPS:很多人都知道使用WINDASM反匯編,但經(jīng)過(guò)它反匯編出來(lái)的代碼非常簡(jiǎn)單,很不容易看明白,但I(xiàn)DA就不一樣了,它不但會(huì)反匯編程序,并會(huì)盡量分析程序,并加上相應(yīng)的注釋。正因?yàn)檫@樣,IDA反匯編一個(gè)大的程序會(huì)花非常長(zhǎng)的時(shí)間。
整個(gè)調(diào)試分析漏洞的過(guò)程如下:首先在SOFTICE中下斷點(diǎn):Bpx ntdll!KiUserExceptionDispatcher,這個(gè)命令的意思就是程序運(yùn)行到Ntdll.dll中的 KiUserExceptionDispatcher就停下來(lái),交給SOFTICE進(jìn)行處理。KiUserExceptionDispatcher這個(gè)函數(shù)是Windows的異常處理過(guò)程中的很重要的一個(gè)步驟,它負(fù)責(zé)派發(fā)用戶層空間發(fā)生的所有異常到異常鏈中的異常處理函數(shù)地址,每當(dāng)在用戶層空間發(fā)生異常的時(shí)候就會(huì)調(diào)用這個(gè)函數(shù)。SOFTICE默認(rèn)是沒(méi)有加載Ntdll.dll的,所以我們可以通過(guò)DriverStudio套件中的一個(gè)叫做“Symbol Loader”的工具的Load Exports來(lái)加載這個(gè)DLL文件。
設(shè)好斷點(diǎn)后,就用一個(gè)簡(jiǎn)單的程序向808端口發(fā)送“GET /AAAA[...4056 bytes] HTTP/1.0<回車><回車>”這樣的超長(zhǎng)字符串,其中包含4056個(gè)A的超長(zhǎng)URL。發(fā)送之后SOFTICE會(huì)跳出來(lái)并停在KiUserExceptionDispatcher斷點(diǎn)上,這時(shí)候用“dd (*(esp+4))+b8”命令來(lái)查看出錯(cuò)時(shí)的EIP地址,這是因?yàn)镵iUserExceptionDispatcher的函數(shù)參數(shù)是一個(gè)指向保存異常發(fā)生時(shí)的寄存器的結(jié)構(gòu),該結(jié)構(gòu)從偏移0x8c的位置開始保存寄存器值,其具體保存寄存器值如下:
0x08c Gs
0x090 Fs
0x094 Es
0x098 Ds
0x09c Edi
0x0a0 Esi
0x0a4 Ebx
0x0a8 Edx
0x0ac Ecx
0x0b0 Eax
0x0b4 Ebp
0x0b8 Eip
0x0bc Cs
0x0c0 EFlags
0x0c4 Esp
0x0c8 Ss
用“dd (*(esp+4))+b8”命令發(fā)現(xiàn)出現(xiàn)異常的EIP是0x41414141,我們知道0x41就是A的ASCII碼,所以現(xiàn)在已經(jīng)證實(shí)我們發(fā)送的超長(zhǎng)字符串已經(jīng)覆蓋了某個(gè)函數(shù)的返回地址,導(dǎo)致該函數(shù)返回的時(shí)候返回到0x41414141這樣的地址。此時(shí)退出SOFTICE就會(huì)彈出 “0x41414141指令引用0x41414141的內(nèi)存。該內(nèi)存不能read?!边@樣的應(yīng)用程序錯(cuò)誤對(duì)話框。
TIPS:“0x41414141指令引用0x41414141的內(nèi)存。該內(nèi)存不能read?!边@種是典型的溢出提示,明確告訴我們溢出的地址和錯(cuò)誤,對(duì)進(jìn)一步分析溢出很有好處。
接下來(lái),我們還需要知道究竟是什么地方導(dǎo)致函數(shù)返回地址被覆蓋的。因此我們逐漸減少發(fā)送的字符串長(zhǎng)度,發(fā)現(xiàn)當(dāng)發(fā)送4039字節(jié)時(shí)就不會(huì)導(dǎo)致出錯(cuò)了。由于堆棧和返回地址被覆蓋,我們無(wú)法看到導(dǎo)致溢出的地址到底是哪里,但是根據(jù)經(jīng)驗(yàn)推測(cè),這可能是一個(gè)由Strcpy、Strcat或Sprintf等函數(shù)導(dǎo)致的溢出。因此我們?cè)谶@些函數(shù)下斷點(diǎn),然后再次發(fā)送4056字節(jié)的長(zhǎng)URL命令。但是發(fā)現(xiàn)沒(méi)有在這些函數(shù)中斷下來(lái),證明溢出過(guò)程并沒(méi)有調(diào)用這些函數(shù)。
到了這里似乎沒(méi)有好的辦法能夠確定溢出位置了,但是通過(guò)觀察發(fā)生溢出后的堆棧內(nèi)容,可以看到根據(jù)當(dāng)時(shí)的堆棧中的連續(xù)大片的“AAAA……”和開頭的時(shí)間和 “unknown Web”字符串等信息得知,當(dāng)對(duì)堆棧中對(duì)這些地址寫入內(nèi)容的時(shí)候會(huì)導(dǎo)致覆蓋返回地址,所以我們直接對(duì)堆棧地址設(shè)寫斷點(diǎn),使用命令“bpmd 01977908 w”來(lái)對(duì)0x01977908的地址設(shè)一個(gè)寫操作斷點(diǎn),這個(gè)地址是我們通過(guò)觀察溢出發(fā)生后的ESP來(lái)得到的,因?yàn)檫@應(yīng)該就是函數(shù)返回之后的ESP,即棧頂?shù)刂贰5沁@個(gè)地址是不固定的,可能不同的系統(tǒng)上這個(gè)地址也不一樣,即使在同一個(gè)系統(tǒng)上,這個(gè)地址也隨每次CCProxy進(jìn)程的啟動(dòng)而不同。但是在同一個(gè)系統(tǒng)上,一般試幾次就會(huì)使用同樣的地址,所以我們只需要多試幾次就肯定能夠中斷下來(lái)了。在設(shè)斷點(diǎn)之前首先要用Addr ccproxy來(lái)進(jìn)入CCProxy的進(jìn)程地址空間。
經(jīng)過(guò)仔細(xì)分析發(fā)現(xiàn),當(dāng)調(diào)用0040A410這個(gè)函數(shù)之前,會(huì)進(jìn)行壓棧操作,這個(gè)壓棧恰好會(huì)把函數(shù)返回地址寫入到堆棧01977908的位置,所以我們有理由相信就是調(diào)用這個(gè)0040A410這個(gè)函數(shù)的過(guò)程當(dāng)中導(dǎo)致了溢出。在0040A410函數(shù)入口出設(shè)斷點(diǎn),然后發(fā)送溢出字符串,中斷后按F12(即執(zhí)行到函數(shù)返回),可以看到恰好返回到0x41414141的地址,這就印證了我們的推測(cè),溢出確實(shí)發(fā)生在0040A410函數(shù)當(dāng)中。
然后我們用IDA來(lái)反匯編CCProxy.exe來(lái)看看0040A410函數(shù)到底進(jìn)行了哪些操作。反匯編的代碼如下:
text:0040A410 sub_40A410 proc near ; CODE XREF: sub_408A10+114 p
.text:0040A410 ; sub_408A10+262 p ...
.text:0040A410 mov eax, 280Ch
.text:0040A415 call __alloca_probe ;分配0x280c大小的緩沖區(qū)
.text:0040A41A mov eax, dword_501D04
.text:0040A41F push ebp
.text:0040A420 mov ebp, [esp+2814h] ;這是要記錄的內(nèi)容,作為參數(shù)傳入
可以看到這個(gè)函數(shù)調(diào)用“__alloca_probe”函數(shù)來(lái)進(jìn)行緩沖區(qū)分配,它和普通函數(shù)調(diào)用Sub esp,xxx的方式來(lái)分配緩沖區(qū)有點(diǎn)不同,這是因?yàn)樾枰峙涞木彌_區(qū)太大,直接減ESP可能會(huì)導(dǎo)致直接到達(dá)未分配的地址空間,所以需要用 “__alloca_probe“來(lái)分配這個(gè)大緩沖區(qū)。
我們?cè)倮^續(xù)跟蹤這個(gè)函數(shù),發(fā)現(xiàn)到0040A607的指令時(shí)覆蓋了函數(shù)的返回地址。代碼如下:
.text:0040A5F1 lea ecx, [esp+414h]
.text:0040A5F8 push ebp
.text:0040A5F9 push ecx
.text:0040A5FA lea edx, [esp+1820h]
.text:0040A601 push offset aSS_0 ; "[%s] %s"
.text:0040A606 push edx
.text:0040A607 call _sprintf
在這個(gè)調(diào)用了“_sprintf“函數(shù),按照“[日期] 內(nèi)容”的格式存入0x1820大小的局部字符串緩沖區(qū)中,由于沒(méi)有限制長(zhǎng)度,所以導(dǎo)致了緩沖區(qū)溢出。再仔細(xì)查看發(fā)現(xiàn)“_sprintf”函數(shù)是在 CCProxy自己的代碼段里面實(shí)現(xiàn)的,而沒(méi)有調(diào)用“msvcrt.dll”導(dǎo)出的Sprintf函數(shù),難怪我們前面在Sprintf函數(shù)下斷點(diǎn)沒(méi)有攔截到!
說(shuō)句題外話,現(xiàn)在市場(chǎng)上有些防溢出軟件產(chǎn)品是利用攔截系統(tǒng)的字符串拷貝函數(shù)然后回溯堆棧的方法,并宣稱從根本上解決了系統(tǒng)緩沖區(qū)溢出的問(wèn)題。這根本就是無(wú)稽之談,因?yàn)楹芏嘁绯龆际擒浖约旱拇a實(shí)現(xiàn)導(dǎo)致溢出的,例如這個(gè)CCProxy溢出這樣,根本就不調(diào)用任何系統(tǒng)函數(shù),所以那種保護(hù)方法并不能從根本上解決溢出的問(wèn)題。
在0040A410函數(shù)返回的時(shí)候,就會(huì)返回到被覆蓋的地址去。代碼如下:
.text:0040A700 add esp, 280Ch ;恢復(fù)堆棧
.text:0040A706 retn ;返回
到這里我們已經(jīng)可以看出,0040A410這個(gè)函數(shù)其實(shí)是一個(gè)記錄CCProxy日志的函數(shù),它按照“[日期] 內(nèi)容”的格式來(lái)記錄日志,但是在構(gòu)造日志字符串的時(shí)候沒(méi)有限制長(zhǎng)度,所以導(dǎo)致了緩沖區(qū)溢出。我們已經(jīng)找到了導(dǎo)致溢出的位置,接下來(lái)就要看看如何利用這個(gè)漏洞了。
漏洞利用
要利用漏洞,就要找到覆蓋返回地址的字符串偏移。我們可以通過(guò)發(fā)送AAAABBBBCCCCDDD……這樣的組合字符串看到底是哪里覆蓋了返回地址。經(jīng)過(guò)一番分析,得知在4056的偏移處恰好覆蓋了函數(shù)返回地址。所以我們這樣來(lái)設(shè)計(jì)溢出字符串:
GET /AAAA….|shellcode|jmp esp|jmp back| HTTP/1.0
其中“AAAA……”這樣的字符串是為了在執(zhí)行ShellCode之前騰出足夠的空間,因?yàn)樽帜窤所對(duì)應(yīng)的CPU指令是INC ECX,即一條無(wú)實(shí)際作用的指令,相當(dāng)于傳統(tǒng)的NOP指令,但是它比NOP指令的好處在于它是可顯示的字符,不易導(dǎo)致錯(cuò)誤。而ShellCode是一個(gè)普通開端口的ShellCode,對(duì)其中的字符無(wú)任何特殊要求。Jmp esp是一個(gè)包含Jmp esp指令的地址,把它作為覆蓋函數(shù)的返回地址,這樣當(dāng)函數(shù)返回的時(shí)候就會(huì)跳到這個(gè)地址去執(zhí)行Jmp esp指令,因?yàn)榇藭r(shí)的ESP恰好指向函數(shù)返回地址后面的地址,即隨后的Jmp back指令。這個(gè)指令是一串跳轉(zhuǎn)指令,用來(lái)跳過(guò)Jmp esp地址和ShellCcode,執(zhí)行到前面的AAAA……,即NOP指令,以便最后執(zhí)行到shellcode當(dāng)中。這里我們要選用一個(gè)比較通用的 jmp esp地址,如果是系統(tǒng)DLL中的Jmp esp地址,可能會(huì)隨系統(tǒng)打了不同的SP而有不同的地址,所以我們選擇0x7ffa54cd這樣的地址,它在同一類Windows系統(tǒng)(例如中文版 Windows 2000)當(dāng)中是固定的。Jmp Back指令我們用這樣的匯編指令:
mov ecx,25414141h ;把ECX設(shè)為0x25414141
shr ecx,14h ;把ECX右移0x14位,讓ECX變?yōu)?x254
sub esp,ecx ;把ESP減去0x254
jmp esp ;跳到此時(shí)的ESP去
這樣把ESP減去0x254就可以跳過(guò)前面的返回地址和ShellCode,這樣一來(lái)就能夠恰好跳到shellcode前面的NOP指令去執(zhí)行了。
這樣設(shè)計(jì)好溢出串,并編寫程序保證jmp esp恰好覆蓋返回地址,發(fā)送,果然溢出成功,并開出了shellcode指定的端口。這樣exploit是不是就算是完成了呢?于是我到外網(wǎng)找了一個(gè)安裝了CCProxy的肉雞試了一下,可是沒(méi)有成功。奇怪了,問(wèn)題究竟出在哪里呢?
經(jīng)過(guò)仔細(xì)分析發(fā)現(xiàn),由于溢出是按照“[日期] 內(nèi)容”的格式拷貝到字符串當(dāng)中導(dǎo)致的,其中“內(nèi)容”部分的格式是這樣的:
客戶端IP地址<空格>unknown<空格>Web<空格>HTTP請(qǐng)求
其中unknown和Web都是固定長(zhǎng)度的字符串,HTTP請(qǐng)求是我們所能控制的字符串。但是這里存在一個(gè)問(wèn)題,就是客戶端IP地址是我們無(wú)法控制的字符串,它的長(zhǎng)度是不固定的,這樣一來(lái),不同長(zhǎng)度的客戶端IP地址就會(huì)導(dǎo)致不同的溢出點(diǎn),這樣也就可能無(wú)法成功的溢出了。怎樣解決這個(gè)問(wèn)題呢?我們雖然無(wú)法控制客戶端IP地址的字符串長(zhǎng)度,但是我們可以得到這個(gè)字符串的長(zhǎng)度,并且在我們所能控制的HTTP請(qǐng)求當(dāng)中補(bǔ)齊這個(gè)長(zhǎng)度,讓我們發(fā)送的Jmp esp地址始終覆蓋在函數(shù)返回地址上面。
而客戶端IP地址可能根據(jù)不同網(wǎng)絡(luò)結(jié)構(gòu)而分為三種情況:
? 如果攻擊者和攻擊目標(biāo)在同一個(gè)網(wǎng)段(即中間不經(jīng)過(guò)網(wǎng)關(guān)),那么客戶端IP地址就是攻擊者主機(jī)的IP地址。
? 如果攻擊者和攻擊目標(biāo)不在同一個(gè)網(wǎng)段上(即中間經(jīng)過(guò)網(wǎng)關(guān)),但是攻擊者的主機(jī)有真實(shí)的IP地址。那么客戶端IP地址也是攻擊者主機(jī)的IP地址。
? 如果攻擊者和攻擊目標(biāo)不在同一個(gè)網(wǎng)段上(即中間經(jīng)過(guò)網(wǎng)關(guān)),而且攻擊者的主機(jī)沒(méi)有真實(shí)的IP地址。例如攻擊者在內(nèi)網(wǎng),而攻擊目標(biāo)主機(jī)在外網(wǎng),那么客戶端IP地址就是攻擊者的網(wǎng)關(guān)的外部IP地址。
知道了這三種情況之后,我們就可以動(dòng)手改進(jìn)剛才的Exploit程序了。首先要取出本機(jī)的IP地址,可以通過(guò)調(diào)用Socket函數(shù)Gethostname ()先取得獲取本機(jī)名,然后通過(guò)調(diào)用Gethostbyname()來(lái)得到本機(jī)IP地址的十六進(jìn)制數(shù)值,最后利用Inet_ntoa()把這個(gè)數(shù)值轉(zhuǎn)換為字符串。這樣就解決了前兩種情況的客戶端IP地址,那么對(duì)于第三種本機(jī)和目標(biāo)主機(jī)不在同一網(wǎng)段的情況又怎么辦呢?用程序?qū)崿F(xiàn)自動(dòng)取網(wǎng)關(guān)外部IP地址好像稍微麻煩了點(diǎn),我懶得寫這樣的程序了,干脆由用戶自己來(lái)輸入算了,怎么得到你的網(wǎng)關(guān)外部IP地址就不用我來(lái)教了吧,應(yīng)該是不難的,有些網(wǎng)站的論壇甚至都會(huì)直接顯示出你的IP地址,那就是你網(wǎng)關(guān)的IP地址。
TIPS:利用網(wǎng)關(guān)實(shí)現(xiàn)溢出攻擊還是第一次看到具體的例子,它們的網(wǎng)絡(luò)通訊是如何建立的?數(shù)據(jù)傳輸是怎么進(jìn)行的?有興趣的朋友可以考慮一下,嘗試?yán)眠@個(gè)過(guò)程做點(diǎn)事情,相信你會(huì)有更都的發(fā)現(xiàn)。
漏洞攻擊程序使用方法
我用前面提到的方法寫了一個(gè)Exploit程序,按照“ccpx <目標(biāo)IP> [端口]”這樣的格式來(lái)使用,其中目標(biāo)IP就是你要攻擊的安裝了CCProxy的機(jī)器的IP地址,端口是目標(biāo)IP上的CCProxy的HTTP代理端口,這個(gè)端口默認(rèn)是808,但是可能會(huì)更改。
然后程序會(huì)提示你“本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?”,因?yàn)榍懊嫣岬皆?,所以要采取兩種不同的溢出字符串,如果你的機(jī)器和目標(biāo)主機(jī)在同一個(gè)網(wǎng)段上,那你就選擇Y,如果不在同一網(wǎng)段就選N。如果你選擇了Nn,程序還會(huì)詢問(wèn)你“本主機(jī)有沒(méi)有真實(shí)外網(wǎng)IP地址?”,也就是說(shuō)你的機(jī)器是在內(nèi)網(wǎng)還是外網(wǎng),有沒(méi)有真實(shí)IP地址,如果有就選Y,沒(méi)有則選N。如果這次你又選擇了N,那么程序會(huì)要求你輸入本主機(jī)所屬網(wǎng)關(guān)的外部IP地址,這個(gè)地址需要你自己想辦法得到,要得到它也并不困難。輸入之后就會(huì)成功發(fā)送溢出串,并自動(dòng)連接ShellCode所開出的 24876端口,如果成功的話,就會(huì)出現(xiàn)系統(tǒng)權(quán)限的CMD.EXE命令行了。
如果你的機(jī)器和目標(biāo)主機(jī)在同一個(gè)網(wǎng)段上面那就簡(jiǎn)單了,直接在第一步選Y就可以攻擊成功。如果你的機(jī)器雖然和目標(biāo)主機(jī)不在同一個(gè)網(wǎng)段上面,但是確有真實(shí)IP地址,那就在第二步選Y。
三種不同情況的具體攻擊過(guò)程如下:
1.你的機(jī)器和目標(biāo)主機(jī)在同一個(gè)網(wǎng)段上:
D:\Soft\ccx\ccpx\Debug>ccpx 192.168.0.103
本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?[y/n]y
[+] connecting to 192.168.0.103:808
[+] send magic buffer...
[+] connecting to CMD shell port...
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權(quán)所有 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator> exit
exit
[-] Connection closed.
2.你的機(jī)器雖然和目標(biāo)主機(jī)不在同一個(gè)網(wǎng)段上面,但是有真實(shí)IP地址:
D:\Soft\ccx\ccpx\Debug>ccpx 202.xxx.xxx.xxx
本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?[y/n]n
本主機(jī)有沒(méi)有真實(shí)外網(wǎng)IP地址? [y/n]y
[+] connecting to 202.xxx.xxx.xxx:808
[+] send magic buffer...
[+] connecting to CMD shell port...
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權(quán)所有 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator>exit
exit
[-] Connection closed.
3.你的機(jī)器在內(nèi)網(wǎng),而攻擊目標(biāo)主機(jī)在外網(wǎng):
D:\Soft\ccx\ccpx\Debug>ccpx 210.xxx.xxx.xxx
本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?[y/n]n
本主機(jī)有沒(méi)有真實(shí)外網(wǎng)IP地址? [y/n]n
請(qǐng)輸入本主機(jī)所屬網(wǎng)關(guān)的外部IP地址: 202.xx.xx.xx ←在這里輸入是你網(wǎng)關(guān)的外部IP地址
[+] connecting to 210.xxx.xxx.xxx:808
[+] send magic buffer...
[+] connecting to CMD shell port...
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權(quán)所有 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator>exit
exit
[-] Connection closed.
我這個(gè)程序里面的Jmp esp地址是中文版Windows 2000中的地址,在其他版本的操作系統(tǒng)中可能會(huì)有所不同,需要讀者自己修改。
TIPS:由于這個(gè)ShellCode里面采用了直接開端口的方法,所以如果讀者朋友的攻擊目標(biāo)上有防火墻的話,可能會(huì)導(dǎo)致攻擊不成功。這種情況你需要更改isno程序中的ShellCode,把它替換成反向連接的ShellCode再重新編譯一遍就行了。具體方法請(qǐng)關(guān)注最近幾期“新手學(xué)溢出”欄目。
前面提到的這種根據(jù)不同網(wǎng)絡(luò)情況來(lái)填充不同個(gè)數(shù)的A,從而把Jmp esp地址推到函數(shù)返回地址的方法是不是最好的方法呢?我覺(jué)得可能還有更好的方法,也許利用Sprintf函數(shù)的一些內(nèi)部特性就可以不用這樣而寫出通用的利用程序了,但是我沒(méi)時(shí)間去研究這個(gè)了,如果讀者有興趣的話可以自己研究一下,如果研究出來(lái),這也算是一項(xiàng)很實(shí)用的通用Exploit技術(shù)。
后來(lái)研究發(fā)現(xiàn)CCProxy不僅僅HTTP代理存在溢出問(wèn)題,Telnet代理等一些其他調(diào)用日志函數(shù)的端口也存在同樣的問(wèn)題,攻擊方法類似,這里就不再詳細(xì)分析了。另外,CCProxy 5.x以及以前的版本雖然也存在此漏洞,但是構(gòu)造字符串的方法略有不同,因此這個(gè)Exploit程序無(wú)法成功的攻擊CCProxy 5.x以及以前的版本,只能攻擊CCProxy 6.0。讀者可以自己研究一下老版本的CCProxy,并寫出Exploit程序。
結(jié)束語(yǔ)
這個(gè)漏洞雖然不是Windows操作系統(tǒng)本身的漏洞,但是CCProxy在國(guó)內(nèi)還算一個(gè)比較常用的軟件,因此還是有一些利用價(jià)值的。不信你可以用Super Scan之類的端口掃描器掃描國(guó)內(nèi)網(wǎng)段的TCP 808端口,很多時(shí)候都能找到安裝了CCProxy的機(jī)器。
其實(shí)寫這篇文章的目的并不是教大家去利用這個(gè)漏洞黑機(jī)器,而是告訴大家一個(gè)軟件漏洞從發(fā)現(xiàn)到跟蹤調(diào)試到最后寫Exploit程序的過(guò)程是怎樣的,也許你也能用這種方法找到一些其它的漏洞。
TIPS:什么是Gopher、RTSP、MMS?
Gopher是Internet上一個(gè)非常有名的信息查找系統(tǒng),它將Internet上的文件組織成某種索引,很方便地將用戶從Internet的一處帶到另一處。允許用戶使用層疊結(jié)構(gòu)的菜單與文件,以發(fā)現(xiàn)和檢索信息,它擁有世界上最大、最神奇的編目。
RTSP是Real Tranfer Stream Protocol的縮寫,翻譯為實(shí)時(shí)傳輸流協(xié)議,用來(lái)傳輸網(wǎng)絡(luò)上的流媒體文件,如RM電影文件等,它的下載方法請(qǐng)看后文《悄悄下載流媒體》。
MMS是Multimedia Messaging Service的縮寫,中文譯為多媒體信息服務(wù),它最大的特色就是支持多媒體功能,可以在GPRS、CDMA 1X的支持下,以WAP無(wú)線應(yīng)用協(xié)議為載體傳送視頻短片、圖片、聲音和文字,彩信就算MMS協(xié)議中的一種。
漏洞發(fā)現(xiàn)過(guò)程
其實(shí)發(fā)現(xiàn)這個(gè)漏洞是很偶然的,當(dāng)時(shí)在考慮公司產(chǎn)品的黑盒測(cè)試方案的時(shí)候,我想使用模板+測(cè)試用例的方式來(lái)進(jìn)行網(wǎng)絡(luò)部分的邊界測(cè)試。這是比較傳統(tǒng)的黑盒測(cè)試方法,其核心內(nèi)容就是把網(wǎng)絡(luò)協(xié)議包分塊,然后制定出對(duì)各個(gè)塊的測(cè)試策略,最后按照策略對(duì)所有塊逐步進(jìn)行測(cè)試。這種測(cè)試方法的好處在于可以有效的控制測(cè)試進(jìn)度,以及可以比較詳細(xì)地測(cè)試一個(gè)網(wǎng)絡(luò)協(xié)議的所有部分,而且在測(cè)試過(guò)程中還可以不斷地加入新的測(cè)試用例,以完善測(cè)試計(jì)劃。測(cè)試程序的編寫則可以使用腳本語(yǔ)言或C來(lái)完成。
TIPS:什么是黑盒測(cè)試?
黑盒測(cè)試法把程序看成一個(gè)黑盒子,完全不考慮程序的內(nèi)部結(jié)構(gòu)和處理過(guò)程。黑盒測(cè)試是在程序接口進(jìn)行的測(cè)試,它只檢查程序功能是否能按照規(guī)格說(shuō)明書的規(guī)定正常使用,程序是否能適當(dāng)?shù)亟邮蛰斎霐?shù)據(jù)產(chǎn)生正確的輸出信息,并且保持外部信息的完整性。黑盒測(cè)試又稱為功能測(cè)試。
我就是用這種方法測(cè)試公司的產(chǎn)品的時(shí)候,恰好當(dāng)時(shí)在公司內(nèi)部網(wǎng)之間使用CCProxy做代理服務(wù)器,因?yàn)闇y(cè)試HTTP協(xié)議要通過(guò)這個(gè)代理,所以測(cè)試過(guò)程中發(fā)現(xiàn)CCProxy崩潰了,也因此發(fā)現(xiàn)了這個(gè)漏洞,算是偶然吧。
漏洞分析過(guò)程
CCProxy的HTTP代理端口默認(rèn)是808,這個(gè)端口可以在其界面中進(jìn)行更改。漏洞的原理很簡(jiǎn)單,就是對(duì)CCProxy的 HTTP代理端口發(fā)送URL超過(guò)4056字節(jié)的畸形請(qǐng)求,CCProxy就會(huì)發(fā)生堆棧溢出。后來(lái)發(fā)現(xiàn),不僅僅是GET請(qǐng)求存在此問(wèn)題,所有POST、 HEAD等請(qǐng)求也都會(huì)導(dǎo)致溢出。在分析其原理后又發(fā)現(xiàn)CCProxy的Telnet代理也存在該問(wèn)題。
現(xiàn)在來(lái)詳細(xì)介紹一下我分析這個(gè)漏洞的過(guò)程。在發(fā)現(xiàn)了發(fā)送超長(zhǎng)請(qǐng)求可以導(dǎo)致CCProxy出錯(cuò)以后,就開始分析溢出點(diǎn)以及利用限制。所要用到的工具是SOFTICE調(diào)試器和IDA反匯編工具。
TIPS:很多人都知道使用WINDASM反匯編,但經(jīng)過(guò)它反匯編出來(lái)的代碼非常簡(jiǎn)單,很不容易看明白,但I(xiàn)DA就不一樣了,它不但會(huì)反匯編程序,并會(huì)盡量分析程序,并加上相應(yīng)的注釋。正因?yàn)檫@樣,IDA反匯編一個(gè)大的程序會(huì)花非常長(zhǎng)的時(shí)間。
整個(gè)調(diào)試分析漏洞的過(guò)程如下:首先在SOFTICE中下斷點(diǎn):Bpx ntdll!KiUserExceptionDispatcher,這個(gè)命令的意思就是程序運(yùn)行到Ntdll.dll中的 KiUserExceptionDispatcher就停下來(lái),交給SOFTICE進(jìn)行處理。KiUserExceptionDispatcher這個(gè)函數(shù)是Windows的異常處理過(guò)程中的很重要的一個(gè)步驟,它負(fù)責(zé)派發(fā)用戶層空間發(fā)生的所有異常到異常鏈中的異常處理函數(shù)地址,每當(dāng)在用戶層空間發(fā)生異常的時(shí)候就會(huì)調(diào)用這個(gè)函數(shù)。SOFTICE默認(rèn)是沒(méi)有加載Ntdll.dll的,所以我們可以通過(guò)DriverStudio套件中的一個(gè)叫做“Symbol Loader”的工具的Load Exports來(lái)加載這個(gè)DLL文件。
設(shè)好斷點(diǎn)后,就用一個(gè)簡(jiǎn)單的程序向808端口發(fā)送“GET /AAAA[...4056 bytes] HTTP/1.0<回車><回車>”這樣的超長(zhǎng)字符串,其中包含4056個(gè)A的超長(zhǎng)URL。發(fā)送之后SOFTICE會(huì)跳出來(lái)并停在KiUserExceptionDispatcher斷點(diǎn)上,這時(shí)候用“dd (*(esp+4))+b8”命令來(lái)查看出錯(cuò)時(shí)的EIP地址,這是因?yàn)镵iUserExceptionDispatcher的函數(shù)參數(shù)是一個(gè)指向保存異常發(fā)生時(shí)的寄存器的結(jié)構(gòu),該結(jié)構(gòu)從偏移0x8c的位置開始保存寄存器值,其具體保存寄存器值如下:
0x08c Gs
0x090 Fs
0x094 Es
0x098 Ds
0x09c Edi
0x0a0 Esi
0x0a4 Ebx
0x0a8 Edx
0x0ac Ecx
0x0b0 Eax
0x0b4 Ebp
0x0b8 Eip
0x0bc Cs
0x0c0 EFlags
0x0c4 Esp
0x0c8 Ss
用“dd (*(esp+4))+b8”命令發(fā)現(xiàn)出現(xiàn)異常的EIP是0x41414141,我們知道0x41就是A的ASCII碼,所以現(xiàn)在已經(jīng)證實(shí)我們發(fā)送的超長(zhǎng)字符串已經(jīng)覆蓋了某個(gè)函數(shù)的返回地址,導(dǎo)致該函數(shù)返回的時(shí)候返回到0x41414141這樣的地址。此時(shí)退出SOFTICE就會(huì)彈出 “0x41414141指令引用0x41414141的內(nèi)存。該內(nèi)存不能read?!边@樣的應(yīng)用程序錯(cuò)誤對(duì)話框。
TIPS:“0x41414141指令引用0x41414141的內(nèi)存。該內(nèi)存不能read?!边@種是典型的溢出提示,明確告訴我們溢出的地址和錯(cuò)誤,對(duì)進(jìn)一步分析溢出很有好處。
接下來(lái),我們還需要知道究竟是什么地方導(dǎo)致函數(shù)返回地址被覆蓋的。因此我們逐漸減少發(fā)送的字符串長(zhǎng)度,發(fā)現(xiàn)當(dāng)發(fā)送4039字節(jié)時(shí)就不會(huì)導(dǎo)致出錯(cuò)了。由于堆棧和返回地址被覆蓋,我們無(wú)法看到導(dǎo)致溢出的地址到底是哪里,但是根據(jù)經(jīng)驗(yàn)推測(cè),這可能是一個(gè)由Strcpy、Strcat或Sprintf等函數(shù)導(dǎo)致的溢出。因此我們?cè)谶@些函數(shù)下斷點(diǎn),然后再次發(fā)送4056字節(jié)的長(zhǎng)URL命令。但是發(fā)現(xiàn)沒(méi)有在這些函數(shù)中斷下來(lái),證明溢出過(guò)程并沒(méi)有調(diào)用這些函數(shù)。
到了這里似乎沒(méi)有好的辦法能夠確定溢出位置了,但是通過(guò)觀察發(fā)生溢出后的堆棧內(nèi)容,可以看到根據(jù)當(dāng)時(shí)的堆棧中的連續(xù)大片的“AAAA……”和開頭的時(shí)間和 “unknown Web”字符串等信息得知,當(dāng)對(duì)堆棧中對(duì)這些地址寫入內(nèi)容的時(shí)候會(huì)導(dǎo)致覆蓋返回地址,所以我們直接對(duì)堆棧地址設(shè)寫斷點(diǎn),使用命令“bpmd 01977908 w”來(lái)對(duì)0x01977908的地址設(shè)一個(gè)寫操作斷點(diǎn),這個(gè)地址是我們通過(guò)觀察溢出發(fā)生后的ESP來(lái)得到的,因?yàn)檫@應(yīng)該就是函數(shù)返回之后的ESP,即棧頂?shù)刂贰5沁@個(gè)地址是不固定的,可能不同的系統(tǒng)上這個(gè)地址也不一樣,即使在同一個(gè)系統(tǒng)上,這個(gè)地址也隨每次CCProxy進(jìn)程的啟動(dòng)而不同。但是在同一個(gè)系統(tǒng)上,一般試幾次就會(huì)使用同樣的地址,所以我們只需要多試幾次就肯定能夠中斷下來(lái)了。在設(shè)斷點(diǎn)之前首先要用Addr ccproxy來(lái)進(jìn)入CCProxy的進(jìn)程地址空間。
經(jīng)過(guò)仔細(xì)分析發(fā)現(xiàn),當(dāng)調(diào)用0040A410這個(gè)函數(shù)之前,會(huì)進(jìn)行壓棧操作,這個(gè)壓棧恰好會(huì)把函數(shù)返回地址寫入到堆棧01977908的位置,所以我們有理由相信就是調(diào)用這個(gè)0040A410這個(gè)函數(shù)的過(guò)程當(dāng)中導(dǎo)致了溢出。在0040A410函數(shù)入口出設(shè)斷點(diǎn),然后發(fā)送溢出字符串,中斷后按F12(即執(zhí)行到函數(shù)返回),可以看到恰好返回到0x41414141的地址,這就印證了我們的推測(cè),溢出確實(shí)發(fā)生在0040A410函數(shù)當(dāng)中。
然后我們用IDA來(lái)反匯編CCProxy.exe來(lái)看看0040A410函數(shù)到底進(jìn)行了哪些操作。反匯編的代碼如下:
text:0040A410 sub_40A410 proc near ; CODE XREF: sub_408A10+114 p
.text:0040A410 ; sub_408A10+262 p ...
.text:0040A410 mov eax, 280Ch
.text:0040A415 call __alloca_probe ;分配0x280c大小的緩沖區(qū)
.text:0040A41A mov eax, dword_501D04
.text:0040A41F push ebp
.text:0040A420 mov ebp, [esp+2814h] ;這是要記錄的內(nèi)容,作為參數(shù)傳入
可以看到這個(gè)函數(shù)調(diào)用“__alloca_probe”函數(shù)來(lái)進(jìn)行緩沖區(qū)分配,它和普通函數(shù)調(diào)用Sub esp,xxx的方式來(lái)分配緩沖區(qū)有點(diǎn)不同,這是因?yàn)樾枰峙涞木彌_區(qū)太大,直接減ESP可能會(huì)導(dǎo)致直接到達(dá)未分配的地址空間,所以需要用 “__alloca_probe“來(lái)分配這個(gè)大緩沖區(qū)。
我們?cè)倮^續(xù)跟蹤這個(gè)函數(shù),發(fā)現(xiàn)到0040A607的指令時(shí)覆蓋了函數(shù)的返回地址。代碼如下:
.text:0040A5F1 lea ecx, [esp+414h]
.text:0040A5F8 push ebp
.text:0040A5F9 push ecx
.text:0040A5FA lea edx, [esp+1820h]
.text:0040A601 push offset aSS_0 ; "[%s] %s"
.text:0040A606 push edx
.text:0040A607 call _sprintf
在這個(gè)調(diào)用了“_sprintf“函數(shù),按照“[日期] 內(nèi)容”的格式存入0x1820大小的局部字符串緩沖區(qū)中,由于沒(méi)有限制長(zhǎng)度,所以導(dǎo)致了緩沖區(qū)溢出。再仔細(xì)查看發(fā)現(xiàn)“_sprintf”函數(shù)是在 CCProxy自己的代碼段里面實(shí)現(xiàn)的,而沒(méi)有調(diào)用“msvcrt.dll”導(dǎo)出的Sprintf函數(shù),難怪我們前面在Sprintf函數(shù)下斷點(diǎn)沒(méi)有攔截到!
說(shuō)句題外話,現(xiàn)在市場(chǎng)上有些防溢出軟件產(chǎn)品是利用攔截系統(tǒng)的字符串拷貝函數(shù)然后回溯堆棧的方法,并宣稱從根本上解決了系統(tǒng)緩沖區(qū)溢出的問(wèn)題。這根本就是無(wú)稽之談,因?yàn)楹芏嘁绯龆际擒浖约旱拇a實(shí)現(xiàn)導(dǎo)致溢出的,例如這個(gè)CCProxy溢出這樣,根本就不調(diào)用任何系統(tǒng)函數(shù),所以那種保護(hù)方法并不能從根本上解決溢出的問(wèn)題。
在0040A410函數(shù)返回的時(shí)候,就會(huì)返回到被覆蓋的地址去。代碼如下:
.text:0040A700 add esp, 280Ch ;恢復(fù)堆棧
.text:0040A706 retn ;返回
到這里我們已經(jīng)可以看出,0040A410這個(gè)函數(shù)其實(shí)是一個(gè)記錄CCProxy日志的函數(shù),它按照“[日期] 內(nèi)容”的格式來(lái)記錄日志,但是在構(gòu)造日志字符串的時(shí)候沒(méi)有限制長(zhǎng)度,所以導(dǎo)致了緩沖區(qū)溢出。我們已經(jīng)找到了導(dǎo)致溢出的位置,接下來(lái)就要看看如何利用這個(gè)漏洞了。
漏洞利用
要利用漏洞,就要找到覆蓋返回地址的字符串偏移。我們可以通過(guò)發(fā)送AAAABBBBCCCCDDD……這樣的組合字符串看到底是哪里覆蓋了返回地址。經(jīng)過(guò)一番分析,得知在4056的偏移處恰好覆蓋了函數(shù)返回地址。所以我們這樣來(lái)設(shè)計(jì)溢出字符串:
GET /AAAA….|shellcode|jmp esp|jmp back| HTTP/1.0
其中“AAAA……”這樣的字符串是為了在執(zhí)行ShellCode之前騰出足夠的空間,因?yàn)樽帜窤所對(duì)應(yīng)的CPU指令是INC ECX,即一條無(wú)實(shí)際作用的指令,相當(dāng)于傳統(tǒng)的NOP指令,但是它比NOP指令的好處在于它是可顯示的字符,不易導(dǎo)致錯(cuò)誤。而ShellCode是一個(gè)普通開端口的ShellCode,對(duì)其中的字符無(wú)任何特殊要求。Jmp esp是一個(gè)包含Jmp esp指令的地址,把它作為覆蓋函數(shù)的返回地址,這樣當(dāng)函數(shù)返回的時(shí)候就會(huì)跳到這個(gè)地址去執(zhí)行Jmp esp指令,因?yàn)榇藭r(shí)的ESP恰好指向函數(shù)返回地址后面的地址,即隨后的Jmp back指令。這個(gè)指令是一串跳轉(zhuǎn)指令,用來(lái)跳過(guò)Jmp esp地址和ShellCcode,執(zhí)行到前面的AAAA……,即NOP指令,以便最后執(zhí)行到shellcode當(dāng)中。這里我們要選用一個(gè)比較通用的 jmp esp地址,如果是系統(tǒng)DLL中的Jmp esp地址,可能會(huì)隨系統(tǒng)打了不同的SP而有不同的地址,所以我們選擇0x7ffa54cd這樣的地址,它在同一類Windows系統(tǒng)(例如中文版 Windows 2000)當(dāng)中是固定的。Jmp Back指令我們用這樣的匯編指令:
mov ecx,25414141h ;把ECX設(shè)為0x25414141
shr ecx,14h ;把ECX右移0x14位,讓ECX變?yōu)?x254
sub esp,ecx ;把ESP減去0x254
jmp esp ;跳到此時(shí)的ESP去
這樣把ESP減去0x254就可以跳過(guò)前面的返回地址和ShellCode,這樣一來(lái)就能夠恰好跳到shellcode前面的NOP指令去執(zhí)行了。
這樣設(shè)計(jì)好溢出串,并編寫程序保證jmp esp恰好覆蓋返回地址,發(fā)送,果然溢出成功,并開出了shellcode指定的端口。這樣exploit是不是就算是完成了呢?于是我到外網(wǎng)找了一個(gè)安裝了CCProxy的肉雞試了一下,可是沒(méi)有成功。奇怪了,問(wèn)題究竟出在哪里呢?
經(jīng)過(guò)仔細(xì)分析發(fā)現(xiàn),由于溢出是按照“[日期] 內(nèi)容”的格式拷貝到字符串當(dāng)中導(dǎo)致的,其中“內(nèi)容”部分的格式是這樣的:
客戶端IP地址<空格>unknown<空格>Web<空格>HTTP請(qǐng)求
其中unknown和Web都是固定長(zhǎng)度的字符串,HTTP請(qǐng)求是我們所能控制的字符串。但是這里存在一個(gè)問(wèn)題,就是客戶端IP地址是我們無(wú)法控制的字符串,它的長(zhǎng)度是不固定的,這樣一來(lái),不同長(zhǎng)度的客戶端IP地址就會(huì)導(dǎo)致不同的溢出點(diǎn),這樣也就可能無(wú)法成功的溢出了。怎樣解決這個(gè)問(wèn)題呢?我們雖然無(wú)法控制客戶端IP地址的字符串長(zhǎng)度,但是我們可以得到這個(gè)字符串的長(zhǎng)度,并且在我們所能控制的HTTP請(qǐng)求當(dāng)中補(bǔ)齊這個(gè)長(zhǎng)度,讓我們發(fā)送的Jmp esp地址始終覆蓋在函數(shù)返回地址上面。
而客戶端IP地址可能根據(jù)不同網(wǎng)絡(luò)結(jié)構(gòu)而分為三種情況:
? 如果攻擊者和攻擊目標(biāo)在同一個(gè)網(wǎng)段(即中間不經(jīng)過(guò)網(wǎng)關(guān)),那么客戶端IP地址就是攻擊者主機(jī)的IP地址。
? 如果攻擊者和攻擊目標(biāo)不在同一個(gè)網(wǎng)段上(即中間經(jīng)過(guò)網(wǎng)關(guān)),但是攻擊者的主機(jī)有真實(shí)的IP地址。那么客戶端IP地址也是攻擊者主機(jī)的IP地址。
? 如果攻擊者和攻擊目標(biāo)不在同一個(gè)網(wǎng)段上(即中間經(jīng)過(guò)網(wǎng)關(guān)),而且攻擊者的主機(jī)沒(méi)有真實(shí)的IP地址。例如攻擊者在內(nèi)網(wǎng),而攻擊目標(biāo)主機(jī)在外網(wǎng),那么客戶端IP地址就是攻擊者的網(wǎng)關(guān)的外部IP地址。
知道了這三種情況之后,我們就可以動(dòng)手改進(jìn)剛才的Exploit程序了。首先要取出本機(jī)的IP地址,可以通過(guò)調(diào)用Socket函數(shù)Gethostname ()先取得獲取本機(jī)名,然后通過(guò)調(diào)用Gethostbyname()來(lái)得到本機(jī)IP地址的十六進(jìn)制數(shù)值,最后利用Inet_ntoa()把這個(gè)數(shù)值轉(zhuǎn)換為字符串。這樣就解決了前兩種情況的客戶端IP地址,那么對(duì)于第三種本機(jī)和目標(biāo)主機(jī)不在同一網(wǎng)段的情況又怎么辦呢?用程序?qū)崿F(xiàn)自動(dòng)取網(wǎng)關(guān)外部IP地址好像稍微麻煩了點(diǎn),我懶得寫這樣的程序了,干脆由用戶自己來(lái)輸入算了,怎么得到你的網(wǎng)關(guān)外部IP地址就不用我來(lái)教了吧,應(yīng)該是不難的,有些網(wǎng)站的論壇甚至都會(huì)直接顯示出你的IP地址,那就是你網(wǎng)關(guān)的IP地址。
TIPS:利用網(wǎng)關(guān)實(shí)現(xiàn)溢出攻擊還是第一次看到具體的例子,它們的網(wǎng)絡(luò)通訊是如何建立的?數(shù)據(jù)傳輸是怎么進(jìn)行的?有興趣的朋友可以考慮一下,嘗試?yán)眠@個(gè)過(guò)程做點(diǎn)事情,相信你會(huì)有更都的發(fā)現(xiàn)。
漏洞攻擊程序使用方法
我用前面提到的方法寫了一個(gè)Exploit程序,按照“ccpx <目標(biāo)IP> [端口]”這樣的格式來(lái)使用,其中目標(biāo)IP就是你要攻擊的安裝了CCProxy的機(jī)器的IP地址,端口是目標(biāo)IP上的CCProxy的HTTP代理端口,這個(gè)端口默認(rèn)是808,但是可能會(huì)更改。
然后程序會(huì)提示你“本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?”,因?yàn)榍懊嫣岬皆?,所以要采取兩種不同的溢出字符串,如果你的機(jī)器和目標(biāo)主機(jī)在同一個(gè)網(wǎng)段上,那你就選擇Y,如果不在同一網(wǎng)段就選N。如果你選擇了Nn,程序還會(huì)詢問(wèn)你“本主機(jī)有沒(méi)有真實(shí)外網(wǎng)IP地址?”,也就是說(shuō)你的機(jī)器是在內(nèi)網(wǎng)還是外網(wǎng),有沒(méi)有真實(shí)IP地址,如果有就選Y,沒(méi)有則選N。如果這次你又選擇了N,那么程序會(huì)要求你輸入本主機(jī)所屬網(wǎng)關(guān)的外部IP地址,這個(gè)地址需要你自己想辦法得到,要得到它也并不困難。輸入之后就會(huì)成功發(fā)送溢出串,并自動(dòng)連接ShellCode所開出的 24876端口,如果成功的話,就會(huì)出現(xiàn)系統(tǒng)權(quán)限的CMD.EXE命令行了。
如果你的機(jī)器和目標(biāo)主機(jī)在同一個(gè)網(wǎng)段上面那就簡(jiǎn)單了,直接在第一步選Y就可以攻擊成功。如果你的機(jī)器雖然和目標(biāo)主機(jī)不在同一個(gè)網(wǎng)段上面,但是確有真實(shí)IP地址,那就在第二步選Y。
三種不同情況的具體攻擊過(guò)程如下:
1.你的機(jī)器和目標(biāo)主機(jī)在同一個(gè)網(wǎng)段上:
D:\Soft\ccx\ccpx\Debug>ccpx 192.168.0.103
本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?[y/n]y
[+] connecting to 192.168.0.103:808
[+] send magic buffer...
[+] connecting to CMD shell port...
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權(quán)所有 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator> exit
exit
[-] Connection closed.
2.你的機(jī)器雖然和目標(biāo)主機(jī)不在同一個(gè)網(wǎng)段上面,但是有真實(shí)IP地址:
D:\Soft\ccx\ccpx\Debug>ccpx 202.xxx.xxx.xxx
本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?[y/n]n
本主機(jī)有沒(méi)有真實(shí)外網(wǎng)IP地址? [y/n]y
[+] connecting to 202.xxx.xxx.xxx:808
[+] send magic buffer...
[+] connecting to CMD shell port...
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權(quán)所有 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator>exit
exit
[-] Connection closed.
3.你的機(jī)器在內(nèi)網(wǎng),而攻擊目標(biāo)主機(jī)在外網(wǎng):
D:\Soft\ccx\ccpx\Debug>ccpx 210.xxx.xxx.xxx
本主機(jī)IP是否與目標(biāo)主機(jī)IP在同一個(gè)網(wǎng)段?[y/n]n
本主機(jī)有沒(méi)有真實(shí)外網(wǎng)IP地址? [y/n]n
請(qǐng)輸入本主機(jī)所屬網(wǎng)關(guān)的外部IP地址: 202.xx.xx.xx ←在這里輸入是你網(wǎng)關(guān)的外部IP地址
[+] connecting to 210.xxx.xxx.xxx:808
[+] send magic buffer...
[+] connecting to CMD shell port...
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權(quán)所有 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator>exit
exit
[-] Connection closed.
我這個(gè)程序里面的Jmp esp地址是中文版Windows 2000中的地址,在其他版本的操作系統(tǒng)中可能會(huì)有所不同,需要讀者自己修改。
TIPS:由于這個(gè)ShellCode里面采用了直接開端口的方法,所以如果讀者朋友的攻擊目標(biāo)上有防火墻的話,可能會(huì)導(dǎo)致攻擊不成功。這種情況你需要更改isno程序中的ShellCode,把它替換成反向連接的ShellCode再重新編譯一遍就行了。具體方法請(qǐng)關(guān)注最近幾期“新手學(xué)溢出”欄目。
前面提到的這種根據(jù)不同網(wǎng)絡(luò)情況來(lái)填充不同個(gè)數(shù)的A,從而把Jmp esp地址推到函數(shù)返回地址的方法是不是最好的方法呢?我覺(jué)得可能還有更好的方法,也許利用Sprintf函數(shù)的一些內(nèi)部特性就可以不用這樣而寫出通用的利用程序了,但是我沒(méi)時(shí)間去研究這個(gè)了,如果讀者有興趣的話可以自己研究一下,如果研究出來(lái),這也算是一項(xiàng)很實(shí)用的通用Exploit技術(shù)。
后來(lái)研究發(fā)現(xiàn)CCProxy不僅僅HTTP代理存在溢出問(wèn)題,Telnet代理等一些其他調(diào)用日志函數(shù)的端口也存在同樣的問(wèn)題,攻擊方法類似,這里就不再詳細(xì)分析了。另外,CCProxy 5.x以及以前的版本雖然也存在此漏洞,但是構(gòu)造字符串的方法略有不同,因此這個(gè)Exploit程序無(wú)法成功的攻擊CCProxy 5.x以及以前的版本,只能攻擊CCProxy 6.0。讀者可以自己研究一下老版本的CCProxy,并寫出Exploit程序。
結(jié)束語(yǔ)
這個(gè)漏洞雖然不是Windows操作系統(tǒng)本身的漏洞,但是CCProxy在國(guó)內(nèi)還算一個(gè)比較常用的軟件,因此還是有一些利用價(jià)值的。不信你可以用Super Scan之類的端口掃描器掃描國(guó)內(nèi)網(wǎng)段的TCP 808端口,很多時(shí)候都能找到安裝了CCProxy的機(jī)器。
其實(shí)寫這篇文章的目的并不是教大家去利用這個(gè)漏洞黑機(jī)器,而是告訴大家一個(gè)軟件漏洞從發(fā)現(xiàn)到跟蹤調(diào)試到最后寫Exploit程序的過(guò)程是怎樣的,也許你也能用這種方法找到一些其它的漏洞。
相關(guān)文章
Windows家族內(nèi)部各個(gè)安全漏洞集體大搜捕(圖)
Windows家族內(nèi)部各個(gè)安全漏洞集體大搜捕(圖)...2007-01-01關(guān)于對(duì)SQL注入80004005 及其它錯(cuò)誤消息分析
關(guān)于對(duì)SQL注入80004005 及其它錯(cuò)誤消息分析...2007-01-01