The X11 window system poses a number of problems for a firewall system. (Note that most window systems supplied by UNIX vendors are either based on or very similar to X11 - from a firewalls point of view, most of the considerations are the same - so this discussion of X11 applies to other window systems as well.)
The first problem with X11 is that the client/server relationship is backwards from most other protocols. The X11 "server" is the display/mouse/keyboard unit, and the "clients" are the application programs driving windows or interacting with the mouse and keyboard on that server. Thus, the server is typically inside the firewall (sitting on the user's desk), and the clients are outside (running on whatever remote computers the user has accessed).
X11 servers have certain capabilities that make them a very tempting target for attackers. There are a number of things an attacker can do with access to an X11 server, including:
Getting screen dumps - obtaining a copy of whatever information is being displayed on the screen at any given time.
Reading keystrokes - for example, reading a user's password as he or she types it at the keyboard.
Injecting keystrokes as if they were typed by the user; this potentially allows the attacker to do all kinds of mean and nasty things, especially in a window where the user happens to be running a root shell.
X11 has certain security mechanisms, but to date they've proven either too weak or too cumbersome to be truly useful against determined attack. One, commonly referred to as the "magic cookie" mechanism, relies on a secret shared between the server and legitimate clients; clients are allowed to access the server only if they can prove they know the secret. The problem is, even though the secret is never passed directly between the X11 client and server, most ways that users make the secret available to both the server and the client (via an NFS-accessible file in their home directory that's accessible to both server and client, for example) compromise the secret to anybody who is snooping on the network. While the magic cookie mechanism is theoretically secure, in practice it is undermined by the way that it is commonly and incorrectly used; unfortunately, there's no easy way to use it correctly.
Another of X11's security mechanisms, called the xhost mechanism, allows the user to tell the server which remote IP addresses the server should accept connections from. Users are supposed to authorize only specific hosts where they intend to run X11 clients. The problem is, users forget to preauthorize the hosts before starting the clients, and the clients are refused access; after this happens a few times, many users disable the controls altogether. For example, they issue an xhost + command to allow connections from any and all hosts in the name of convenience (so they can easily run programs on remote systems), without giving any thought to the security implications of their actions. Even if users don't disable xhost altogether, they're still vulnerable to any connections from the machines they've approved; there's no way for the xhost mechanism to determine whether or not any given connection from one of those machines is legitimate.
Few sites need to run X11 across their firewalls from the Internet. There are occasional WWW sites that provide X clients as a way to provide real-time displays, but they are few and far between. If you need to allow X11 from the Internet, consider using one of the X11 proxies discussed in Chapter 7, for example, x-gw in the TIS Firewall Toolkit.
X11 uses TCP. X11 uses port 6000 for the first server on a machine. This choice of ports presents another problem for packet filtering systems: the X11 ports are in the middle of the "above 1023" range of ports that most applications use for random client-side ports. Thus, any packet filtering scheme that allows packets in to ports above 1023 (in order to allow packets from remote servers to local clients) needs to be very careful not to allow connections in to X11 servers. It can do this either by totally blocking access to the range of ports used by these servers (which can be a tricky proposition because of the possibility of multiple servers per machine, per the discussion below) or by using "start-of-connection" filtering (looking at the TCP ACK bit) to disallow inbound TCP connections to any ports.
Some machines run multiple X11 servers. The first server is at port 6000, the second at 6001, and so on. On a UNIX system, the DISPLAY environment variable tells clients what X11 server to contact. This variable is of the form hostname:n; this tells clients to contact the server on port 6000+n on machine hostname.
Sometimes such machines actually have multiple display/keyboard/mouse setups, but more often the multiple servers are virtual servers for some remote X terminal. X11 is a very verbose, high-bandwidth protocol; it doesn't run well over dial-up links. One of the solutions that's been adopted (for example, by NCD's XRemote package) is to run a virtual X11 server on a well-connected machine (for example, linked by Ethernet to the machines the client programs are running on), and then to speak some other, more frugal protocol over the slow link between this virtual server and the real X terminal. Every machine running X11 will have a server at port 6000. A few will have servers at 6000 and 6001. Only a very few machines will have more than that.
Thus, to block access to all these servers, assuming that you can't do start-of-connection filtering, you need to block access to ports 6000 through 6000+n, where n is some undetermined number. You don't want to make n too small, because that might expose some of the virtual X11 servers to attack. On the other hand, you don't want to make it too big, either, because you're blocking ports in the range of random ports that could be used by other application clients. You don't want to keep another protocol's client (e.g., Telnet or FTP) from working simply because it happened to pick as its random client port a port blocked to prevent X11 access.
You do have one thing going for you: the way most operating systems allocate such random ports. Generally, when a client application asks the operating system to allocate a random port for its use, the kernel allocates the next available port after the last one allocated (wrapping around to the beginning of the port number space when necessary). If a client happens to grab a port blocked because of X11, the client will fail. If the user tries to run the client again a few times, the client will get a new port each time, and will eventually succeed when the port allocated moves beyond the blocked range.
A common approach (again, assuming that you can't do start-of-connection filtering to block external connections to internal servers) is to block, say, four ports (ports 6000 through 6003) on all hosts, and more ports on hosts where you know or suspect people will run lots of virtual X11 servers, e.g., the hosts people dial in to from their X terminals at home. A more straightforward approach is to use proxying to direct connections to a bastion host that is not running a window system. It can make outbound connections on any port without worrying about hitting the blocked range, because it doesn't need a blocked range.
What should you do on a machine where you've blocked a large range of ports (because of the potential for many X11 servers on that machine)? If you have problems with clients of other protocols because of the blocked ports, you could run a simple program to keep the kernel's "next port" assignment out of the blocked range. The program would simply need to ask the kernel for a random port, and if the port it was assigned was in the blocked range, keep asking for more random ports until the ports being assigned were no longer in the blocked range. The program would then need to perform this check every minute or so. Most sites will choose to either avoid the problem altogether with proxying, or ignore the problem, rather than going to this length to deal with it, but if you have a server that must provide heavily used Internet client access and multiple X servers, it may be worth it to you.
Some vendors provide modified or enhanced X11 servers with somewhat different characteristics; for example, Sun's OpenWindows server listens at both port 6000 (for X11) and port 2000 (for Sun's older NeWS window system protocol), with second servers at ports 6001 and 2001, and so on.
Direc- | Source | Dest. | Pro- | Source | Dest. | ACK | |
---|---|---|---|---|---|---|---|
tion | Addr. | Addr. | tocol | Port | Port | Set | Notes |
In | Ext | Int | TCP | >1023 | 6000+n | [52] | Incoming X11 connection to nth server, client to server |
Out | Int | Ext | TCP | 6000+n | >1023 | Yes | Incoming X11 connection to nth server, server to client |
Out | Int | Ext | TCP | >1023 | 6000+n | [52] | Outgoing X11 connection to nth server, client to server |
In | Ext | Int | TCP | 6000+n | >1023 | Yes | Outgoing X11 connection to nth server, server to client |
[52] ACK is not set on the first packet of this type (establishing connection) but will be set on the rest.
Do not allow clients on the Internet to connect to X11 servers on your internal network. If you have to, use an X11 proxy server (such as the one in the TIS FWTK) running on a bastion host.
If you cannot use start-of-connection filters, blocking X11 may block other connections. You will need to use proxying or special programs if you have large numbers of X11 servers on the same machine.