A Look at Some of the Greatest Unix Security Holes of All Time

The hottest trend these days in network intrusion is to exploit buffer overruns, a technique where-by you feed a program more data than it has allocated, overwriting the memory in the hope of making the program do something it would normally never do. It's an interesting technique but just one of many available in the arsenal of today's intruders. In the interest of feeding the media blitz about Internet security, this month's column features a walk through some of the more innovative and interesting security holes that we've come across in the past few years.

The hottest trend these days in network intrusion is to exploit buffer overruns, a technique where-by you feed a program more data than it has allocated, overwriting the memory in the hope of making the program do something it would normally never do. It’s an interesting technique but just one of many available in the arsenal of today’s intruders. In the interest of feeding the media blitz about Internet security, this month’s column features a walk through some of the more innovative and interesting security holes that we’ve come across in the past few years.

LD_PRELOAD on setuid Binaries


This is a very old bug; a CERT advisory was issued in May 1992 for SunOS v4.0 and higher. To understand what the problem is, you have to understand what setuid binaries are, and roughly how shared libraries work.

Normally, the actual tasks a program can perform depend on the permissions of the user who is running it, not those of the user who owns the program binary.

For example, when you run a program owned by root, as most Linux binaries are, the program has the same kind of access rights that you have. It does not have root access to everything on the system.

setuid binaries are programs that have been marked (using chmod) to behave specially. While running, these programs act as if they were being run by the owner of the program, regardless of who is actually running the program. A classic example is the su (“set user”) program, which allows you to become another user on the system by supplying that user’s password.

Normally only root can change from one user to another. But because the su binary is owned by root and is setuid, su has all the privileges that root does, regardless of the user running the program.

Shared libraries are commonly used libraries of code that other programs can load dynamically. Because the library code is stored separately, programs that use shared libraries have smaller binaries.

Another cool feature of shared libraries is that you can use them to update a large number of programs in one fell swoop by updating a single shared-library file.

The process of combining different pieces of a compiled program to form a runable binary is known as linking. Statically linked programs link all of the relevant pieces of code as the final stage of the compilation process. This results in a completely self-contained binary that does not use any shared libraries.

A dynamically linked program invokes a run-time linker to link the necessary shared libraries that the binary requires. By default, the linker usually looks for shared libraries in the /lib and /usr/lib directories. An alternative would be for the user to specify the path of the shared library by setting the environment variable LD_LIBRARY_PATH.

By modifying this environment variable, you can cause programs to load your code rather than the default shared library. This is not a problem for regular programs, but for setuid root programs, this is a potential security hole.

The Sun guys recognized this and designed the run-time linker to check to see if the “real” user ID (i.e., the user ID of the person actually running this program) is the same as the “effective” user ID (i.e., the value changed when a setuid program is run). If these two values are not the identical, then the linker will ignore all of the environment variables.

However, this does not completely plug the hole. Some setuid programs, such as the perennial intruder’s favorite, sendmail, change their “real” user ID to be the same as their “effective” user ID before they call another program. This means that if this second program is dynamically linked, it will not ignore the LD_ LIBRARY_PATH and similar variables.

The solution suggested in CERT’s advisory is to write a wrapper program that removes any environment variables prefixed by LD_.

LD_PRELOAD Through Telnet


This is a slightly more recent bug (the CERT advisory was issued in November 1995) that exploits a feature of the telnet protocol. When using telnet to access a remote server, the environment variables from the local shell can be transmitted across to the remote shell.

You may be able to guess where this is headed. The telnet daemon accepts the environment variables from the client, then proceeds to run the login program, which is supposed to read the username and password and, if correct, start a up shell for the user. login is a dynamically linked executable and is run from telnet as the root user. If you can manage to place a shared library on the remote machine and convince the telnet daemon to set up the environment just right, then login will run with your modified shared library.

This is most easily exploitable if a user has a local account, and so can place a shared library in that user’s home directory. Another possible way to exploit this hole is to use anonymous FTP if the target allows uploads.

Once again, cleaning the environment before running login is the suggested solution.

Sun’s /dev/audio Bug


Back in the early 1990s, you could get a Sun system with a microphone, which was something of a novelty to PC users at the time. There was a convenient method of accessing both the speakers and the microphone, which is familiar to Linux users today: a device called /dev/audio. Data written to /dev/ audio is played on the speakers; data read from this device is a digitization of whatever sounds the microphone is picking up.

Sun set the permissions of the audio device to 666, allowing all users to read and write to the device. Since there was no indicator light to show when the microphone was on, any users with access to the system could eavesdrop on conversations near the microphone virtually undetected, even if they were logged in remotely. A large number of these systems were on the desks of system administrators and in machine rooms, so this became a serious security hole.

chfn CR Bug

Users use the chfn command (“change fullname”) to alter the GCOS (General Comprehensive Operating System) field in the password file, the fifth field in this colon-delimited example:

rusty:x:1000:1000:Paul Rusty Russell,,,:/home/rusty:/bin/bash

The GCOS field is traditionally a comma-separated list containing the person’s real name, room number, and work and home phone numbers, any of which can be blank. The password file as a whole consists of one entry per line.

Some very early versions of chfn allowed users to include a carriage return within their GCOS field, essentially resulting in a new line in the password file. Using this method, users could create accounts with root privileges and no password.

ps Solaris /tmp Permissions Bug

In 1995, Scott Chasin published a Solaris 2.x vulnerability called psrace, which relied on a mistake in Sun’s initialization scripts. Sun had introduced a swap-based filesystem (called tmpfs) for mounting over /tmp. The idea was that files in /tmp are usually short-lived, and so there’s no point in hitting the disk at all.

Early versions of Solaris, however, had a bug in their scripts on systems with tmpfs enabled: They didn’t mark the /tmp directory “sticky” by default. To delete a file, you do not need permission to write to a file, you only need write permission on the directory the file is in.

However, if the directory is marked sticky (using chmod), in order to delete a file, you must also own the file you are trying to delete. This is extremely useful for shared directories, such as /tmp, where everyone needs to be able to write but no one should be able to delete other people’s files, even accidentally.

What happens if /tmp is not sticky, as in the Solaris case? In addition to allowing anyone to get rid of anyone else’s files on a whim, there’s a far nastier hole that’s caused by the way Solaris’s ps program uses /tmp.

The ps program needs to be able to see the names and details of all processes running, so the program is setuid root. The first time you run ps on Solaris, it looks up the location of the process table inside the kernel and other details it needs. Because searching for this information is time-consuming, it stores it in a file called /tmp/ps_data, where future invocations of ps can find it. Unfortunately, Sun assumed that the /tmp directory would be sticky. Solaris ps first put the information in a file called /tmp/ ps.XXX, where XXX was the process ID of ps, then changed the owner of the file to root, and finally renamed the file to /tmp/ps_data.

Chasin wrote a simple exploit program that deletes the /tmp/ps_data file (to force ps to create a new one), then looks in the /tmp directory for a file starting with ps. When it finds one, it quickly deletes it and replaces it with a symbolic link to another file. If the program’s timing is right, ps will then run chown on the symbolic link, making the file the link points to owned by root. If the file was setuid, it is now setuid root.

A fairly easy way for an attacker to get root access using this vulnerability is to copy a version of the shell, /bin/ sh, to a directory, make it setuid, then run the exploit program telling it to create the symbolic link to your setuid shell. The program has to run several times before it gets lucky, but once it’s successful, you have a setuid root shell.

SGI colorview Bug

This is probably my favorite hole, because it’s particularly stupid. For a long time, Silicon Graphics was synonymous with “totally insecure systems, with poor default settings,” and features like allowing anyone to connect to its X server; having no password on remote access to the lp account only helped to strengthen this dubious reputation.

SGI’s early attempts at GUI tools to control system-administration tasks were particularly riddled with security holes. Anything as large and complex as a GUI program should probably not be setuid root!

The worst offender was an SGI program called colorview. It was a simple program that read the color database and popped up a window containing a scrolled list of color names underneath a square pad of that color. Clicking on the name would change the pad to that color.

This program was setuid root. There was no discernable reason; the color database was readable by anyone, and displaying the colors certainly didn’t require any special privileges. I still don’t know why SGI did this.

The colorview program took a couple of command-line options, one of which allowed it to read from an alternate color file. Even if the file didn’t look at all like a color database, colorview would still print out the contents in the scrolling window. Because colorview ran as root, you could use it to read people’s mailboxes, the shadow password file, or anything else on the system.

In Conclusion

So what have we learned from all of this? Well, if there’s one thing that our brief jaunt through Unix history has taught us, it’s that we should very carefully scrutinize any program that runs with special privileges. And as the /dev/audio bug demonstrates, even if you think you know everything about security, something else is waiting just around the corner.

Paul “Rusty” Russell is the Linux kernel IP packet filter maintainer. He works for Linuxcare and can be reached at paul.russell@rustcorp.com.au.

Comments are closed.