Bugtraq mailing list archives

xterm segfaults from environment variables - too obvious


From: luyer () ucs uwa edu au (David Luyer)
Date: Tue, 11 Mar 1997 15:00:16 +0800


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.

Secondly, the script I used to test things to find it.

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.

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 my system, but rc does.
I'm 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#
---

Well anyway, here's the script...

David.
-------------------------- 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\).



Current thread: