Vulnerability Development mailing list archives

Re: exim remote heap overflow, probably not exploitable


From: Nick Cleaton <nick () cleaton net>
Date: Wed, 3 Sep 2003 20:11:27 +0100

On Mon, Sep 01, 2003 at 07:00:34AM +0100, Nick Cleaton wrote:

Exim (www.exim.org) is a message transfer agent (MTA) developed
at the University of Cambridge for use on Unix systems connected
to the Internet.

There's a heap overflow in all versions of exim3 and exim4 prior
to version 4.21.  It can be exercised by anyone who can make an
SMTP connection to the exim daemon.

The overflow is very limited, and in my opinion it's probably not
exploitable.  However, it's possible that this will prove to be
exploitable for arbitrary command execution on some platforms in
some circumstances.

Patches:

  http://www.exim.org/pipermail/exim-announce/2003q3/000094.html

Full details coming soon to vuln-dev.


At line 1972 of exim-4.20/src/smtp_in.c :

  if (*smtp_data == 0) Ustrcpy(smtp_data, "(no argument given)");

'smtp_data' is a pointer into the 513 byte heap buffer 'cmd_buffer'.

A carefully formatted HELO or EHLO command can arrange for '*smtp_data'
to be 0 and for 'smtp_data' to be within 2 bytes of the end of
'cmd_buffer', so that the string "o argument given)" followed by a
NULL is written off the end of cmd_buffer.

Consider an input line consisting of "HELO" followed by 506 spaces
followed by a NULL then a newline.

This is the longest input line that this loop at line 441 will
accept:


    while ((c = (receive_getc)()) != '\n' && c != EOF)
      {
      if (ptr >= cmd_buffer_size)
        {
        os_non_restarting_signal(SIGALRM, sigalrm_handler);
        return OTHER_CMD;
        }
      cmd_buffer[ptr++] = c;
      }


Now the code at line 462 removes any trailing whitespace from the
buffer and NULL terminates it:


  while (ptr > 0 && isspace(cmd_buffer[ptr-1])) ptr--;
  cmd_buffer[ptr] = 0;


but it doesn't trim all our spaces because the NULL we put at the
end of the line protects them.  At this point the buffer is mostly
full of spaces, but the last two chars in the buffer are NULLs.

Now smtp_data is pointed to the character after the HELO command,
and then advanced over any whitespace by this code at line 508:


   while (isspace(*smtp_data)) smtp_data++;


after which smtp_data points to the NULL at byte 511 of cmd_buffer.


We can, of course, choose to use less space characters so as to
write less far off the end of the buffer.  So, we can write a single
NULL up to 18 bytes off the end of the buffer, with the side effect
of writing ASCII over everything up to the NULL.

Papers such as http://www.phrack.org/show.php?p=57&a=8 and
http://bespin.org/~qitest1/txt/heap_off_by_one.txt.asc suggest that
it might well be exploitable under linux.

My main reason for rating this as "probably not exploitable" even
under Doug Lea's malloc is that the 513 byte buffer is never
free()ed, and neither is the 8192 byte buffer that gets malloc()ed
immediately after the 513 byte buffer.  

A quick scan of the exim sources didn't find much in the way of
free() calls on buffers over 512 bytes in any code that runs in
normal circumstances before these two buffers get allocated, so I'm
imagining that it's likely that they'll both come off the wilderness
chuck.  The relevant part of the heap will then look something like:

      513ByteBuffer CorruptBoundaryTag 8192ByteBuffer

and the corrupt boundary tag will never be accessed since the chunks
before and after it are never free()ed.

Does that seem reasonable, or am I in dreamland ?

Can anyone get as far as a segfault on some platform ?

--
Nick Cleaton
nick () cleaton net


Current thread: