[4102] in bugtraq

home help back first fref pref prev next nref lref last post

Re: libX11

daemon@ATHENA.MIT.EDU (Paul Szabo)
Thu Feb 27 19:39:05 1997

Date: 	Fri, 28 Feb 1997 08:16:50 +1100
Reply-To: Paul Szabo <szabo_p@MATHS.SU.OZ.AU>
From: Paul Szabo <szabo_p@MATHS.SU.OZ.AU>
X-To:         auscert@auscert.org.au
To: BUGTRAQ@NETSPACE.ORG

A few days ago SNI released an advisory concerning buffer overrun problems
in libX11. Their "fix advice" was to upgrade to X11R6.3, or to remove
setuid/setgid privileges from vulnerable programs (e.g. xload and xterm).

I do not think I can upgrade to the current release of X11: how would I
integrate that into Digital Unix (a.k.a. OSF/1)? And I could not give up the
functionality of xterm...

So instead I wrote the following wrapper, and used it to wrap xload, xterm
and xconsole. My wrapper, and the SNI advisory, included below.

Paul Szabo - System Manager   //        School of Mathematics and Statistics
psz@maths.usyd.edu.au         //   University of Sydney, NSW 2006, Australia

-----

/*
    sec_wrapper.c -- Wrap setuid program to prevent command line or
                     environment variable buffer overrun.

Only tested on DUnix V4.0

        Does NOT check the values of the arguments and/or environment
        (other than checking their lengths), though that functionality
        could (should?) be added.

        This program is based loosely on the lpr wrapper released with
        AUSCERT Advisory AA-96.12. Any errors are my own.

DISCLAIMER:     Anything you do with this is at your own risk.

    V1.0  26 Feb 97  PSz

Installation instructions
~~~~~~~~~~~~~~~~~~~~~~~~~

  1.    su to root

  2.    Determine the full path of the prog you want to wrap, and
        its permissions, owner, and group:

                # ls -lg /usr/bin/badprog

  3.    Copy badprog to badprog.real, and change the permissions on it:

                # cd /usr/bin
                # cp -ip badprog badprog.real
                # chmod 711 badprog.real

  4.    Edit (a copy of) this program and define REAL_PROG (an absolute
        pathname), check the settings of MAX_ and GOOD_ variables, then
        compile:

                # cc -o badprog badprog_wrapper.c

  5.    Copy this new wrapper program into the directory originally
        containing badprog, replacing the existing badprog program.

        Use the information found in step #2 and set the same
        owner, group, permissions on the new badprog program:

                # cp badprog /usr/bin
                # cd /usr/bin
                # chown root badprog
                # chgrp daemon badprog
                # chmod 6711 badprog

        Check that the permissions, owner and group exactly
        match those noted in step #2:

                # ls -lg /usr/bin/badprog

  6.    Check that badprog still works!
*/


/* Make sure REAL_PROG points to the right location */
/* The MAX_ values should be appropriate to the program being wrapped. */
/* The GOOD_ values should be appropriate, leave undefined to skip check. */
/* (Beware: $TERMCAP often contains weird characters.) */

/* #define REAL_PROG    "/usr/bin/badprog.real" */

#define MAX_ARGC        50
#define MAX_ARG_LENGTH  1000
#define MAX_ENV_LENGTH  1000
/* #define GOOD_ARG_CHARS       "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/_.-" */
/* #define GOOD_ENV_CHARS       "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/_.,:+-=" */


#define SYSLOG 1


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef SYSLOG
#include <syslog.h>
#endif


#ifdef SYSLOG
#define sysl(msg)       syslog(LOG_ERR,"Possible %s attack by uid %d: %s\n",REAL_PROG,getuid(),msg)
#else
#define sysl(msg)
#endif

#define ZAP(x,err)      if (x) { printf("Sorry: %s\n",err); sysl(err); exit(-1); }


#ifndef REAL_PROG
        Cannot compile: you do not have REAL_PROG defined
#endif
#if MAX_ARGC > 1000 || MAX_ARGC < 1
        Cannot compile: you have a crazy value for MAX_ARGC
#endif
#if MAX_ARG_LENGTH > BUFSIZ || MAX_ARG_LENGTH < 10
        Cannot compile: you have a crazy value for MAX_ARG_LENGTH
#endif
#if MAX_ENV_LENGTH > BUFSIZ || MAX_ENV_LENGTH < 10
        Cannot compile: you have a crazy value for MAX_ENV_LENGTH
#endif


void main( int argc, char* argv[] /* , char *envp[] */ )
{
        int     iii, jjj;
        char    **ccc, *ddd;

        extern char **environ;

        ZAP( argc<1, "too few arguments" );
        ZAP( argc>MAX_ARGC, "too many arguments" );

        for( iii=1; iii<argc; iii++ )
        {
                jjj = strlen(argv[iii]);
                ZAP( jjj<1, "argument too short" );
                ZAP( jjj>MAX_ARG_LENGTH, "argument too long" );
#ifdef GOOD_ARG_CHARS
                ZAP( strspn(argv[iii],GOOD_ARG_CHARS) != jjj, "bad char in argument" );
#endif
        }

        /* Which one: environ and/or envp ?? */
        for( ccc = environ; *ccc; ccc++ )
        {
                jjj = strlen(*ccc);
                ZAP( jjj<2, "environment component too short" );
                ZAP( jjj>MAX_ENV_LENGTH, "environment component too long" );
                ZAP( !strncmp(*ccc,"LD_",3), "suspicious environment component LD_" );
                ddd = strchr(*ccc,'=');
                ZAP( (int)ddd < (int)*ccc || (int)ddd >= ((int)*ccc)+jjj || *ddd != '=',
                    "badly formed environment component" );
#ifdef GOOD_ENV_CHARS
                ZAP( strspn(*ccc,GOOD_ENV_CHARS) != jjj, "bad char in environment component" );
#endif
        }

        /* execve( REAL_PROG, argv, envp ); */
        execv( REAL_PROG, argv );
        perror( REAL_PROG );
        exit( 1 );
}

-----

> From owner-bugtraq@NETSPACE.ORG Tue Feb 25 11:22:38 1997
> Date:         Mon, 24 Feb 1997 16:06:43 -0700
> From: David Sacerdote <davids@SECNET.COM>
> Subject:      libX11
> To: BUGTRAQ@NETSPACE.ORG
>
>                         ######    ##   ##    ######
>                         ##        ###  ##      ##
>                         ######    ## # ##      ##
>                             ##    ##  ###      ##
>                         ###### .  ##   ## .  ######.
>
>                             Secure Networks Inc.
>
>                              Security Advisory
>                              February 24, 1997
>
>                     Environment Variable Problems in X11
>
>
> While examining the differences between X11R6.1 and X11R6.3, it has come to
> our attention that a number of serious security problems in libX11 were fixed
> between releases.  These problems permit unprivileged users to obtain elevated
> access, including group sys, group kmem, and root privileges, depending on the
> operating system and the X11 release.  Administrators should be aware that
> these problems are actively being exploited, and should take the precautions
> outlined below to ensure they are not susceptible to these problems.
>
>
> Technical Details
> ~~~~~~~~~~~~~~~~~
>
> In X11R6.1 and earlier, there are many places where libX11 looks at
> environment variables, and then performs string operations on them.  X11R6.1
> and earlier, however, perform no bounds checking when doing these string
> operations.  Setuid and setgid programs which use functions provided by libX11
> may allow users to obtain elevated privileges.
>
> One of the many examples of flawed code in X11R6.1, in this case from
> GetDflt.c reads:
>
> if (ptr = getenv("HOME"))
>         (void) strcpy(dest, ptr);
>
> While the corrected code for this particular exammple in X11R6.3 reads:
>
> if (ptr = getenv("HOME")) {
>         (void) strncpy(dest, ptr, len);
>         dest[len-1] = '\0';
>
> Note that this code correctly adds a null character at the end of the
> string after the strncpy.
>
>
> Impact
> ~~~~~~
> Depending on platform and X11 release, individuals with shell access can
> obtain elevated access, including group sys, group kmem, and root
> privileges.
>
>
> Vulnerable Systems
> ~~~~~~~~~~~~~~~~~~
> Any system which is running X11R6.1 or earlier, and has at least one setuid or
> setgid program which uses libX11 is vulnerable.
>
> You can perform a simple test to determine whether your system is vulnerable.
> First, set the HOME environment variable to a string at least 2500 characters
> long.  Using a sh compatible shell, do this by issuing the commands:
>
> $ HOME=jjjjjjj...jjjjj                  (2500 repititions of 'j')
> $ export HOME
>
> Using csh or tcsh, use the command:
>
> % setenv HOME jjjjj...jjjjjjj           (2500 repititions of 'j')
>
> Then, run a setuid or setgid X program, such as xload.  If you are running a
> vulnerable release of X11, you will get an error message including either the
> words "Segmentation Fault" or "Bus error."  If the words "Segmentation Fault"
> and "Bus Error" do not appear, and the program operates correctly, you are not
> vulnerable to this problem.
>
> Be aware that if you use a string much shorter than 2500 characters, this test
> will not produce meaningful results, because the length of the buffer in
> question is 2048 characters.  Also, if your DISPLAY environment variable does
> not point to a display which you have authorization to connect to, the test
> will not be able to connect to a valid display and therefore will not work.
>
>
> Fix Information
> ~~~~~~~~~~~~~~~
> To fix these problems without loss of functionality, upgrade to the current
> release of X11.  You can obtain X11R6.3 by referring to
> http://www.x.org/consortium/GettingX.html
>
> As an alternative workaround, administrators may want to remove setuid and
> setgid bits from vulnerable programs.  To find all setuid and setgid programs,
> in the X11 distribution, the following command can be executed:
>
> % cd /usr/X11/bin
> % find . \( -perm -02000 -o -perm -04000 \) -exec ls -l {} \;
> % find . \( -perm -02000 -o -perm -04000 \) -exec chmod ug-s {} \;
>
> Remember to perform the same command if you wish to remove permissions from
> programs stored in other system directories.  Keep in mind that that the
> use of this workaround will result in reduced functionality for non-root
> users.
>
>
> Additional Information
> ~~~~~~~~~~~~~~~~~~~~~~
>
> If you have any questions about this advisory, feel free to contact me,
> David Sacerdote, at davids@secnet.com.  If you should wish to encrypt
> traffic for me, my pgp key is:
>
> -----BEGIN PGP PUBLIC KEY BLOCK-----
> Version: 2.6.2
>
> mQCNAzJ4qJAAAAEEAOgB7mooQ6NgzcUSIehKUufGsyojutC7phVXZ+p8FnHLLZNB
> BLQEtj5kmfww2A2pR29q4rgPeqEUOjWPlLNdSLby3NI8yKz1AQSQLHAwIDXt/lku
> 8QXClaV6pNIaQSN8cnyyvjH6TYF778yZhYz0mwLqW6dU5whHtP93ojDw1UhtAAUR
> tCtEYXZpZCBTYWNlcmRvdGUgPGRhdmlkc0BzaWxlbmNlLnNlY25ldC5jb20+
> =LtL9
> -----END PGP PUBLIC KEY BLOCK-----
>
> Many thanks to the unknown individual who undertook to fix this set
> of holes in the final days of the X Consortium.
>
> Additional information about the X Windowing System can be found at
> http://www.x.org
>
> You can find Secure Networks papers at ftp://ftp.secnet.com/pub/papers
> and advisories at ftp://ftp.secnet.com/advisories
>
> You can browse our web site at http://www.secnet.com
>
> You can subscribe to our security advisory mailing list by sending mail to
> majordomo@secnet.com with the line "subscribe sni-advisories" in the body of
> the message.
>
>
> Copyright Notice
> ~~~~~~~~~~~~~~~~
> The contents of this advisory are Copyright (C) 1997 Secure Networks Inc,
> and may be distributed freely provided that no fee is charged for
> distribution, and that proper credit is given.

home help back first fref pref prev next nref lref last post