- Introduction
The purpose of this paper is to describe necessary measures that should be
taken in order to secure a default Linux installation. Most default
installations of Linux are grossly insecure. This paper focuses on
methods that can be used not only to secure a machine with a high degree of
confidence, but still allow your users to be able to accomplish their work.
This paper does not cover procedures for securing a machine that is
already on a network. As a rule, no machine should be placed on any network
prior to its having been secured against local and remote attack. If a
machine has already been compromised, none of the following procedures will
improve the system's security. In most cases, depending on the skill of the
intruder, the machine will likely already be trojaned or backdoored. Applying
the following security procedures on such a machine would only provide a
false sense of security.
As a firm adherent to the philosophy of proactive security, the author does
not recommend any attempt to "back-track" and attempt to secure machines that
are already in place. It is best to freshly re-install and secure these
machines from scratch. After all, it only takes one compromised machine to
shatter the security posture of one's entire network.
Because of the amount of material being covered, this paper will be divided
into two parts:
- Part I will deal with securing the system with the tools Linux
provides. One exception to this rule is the inclusion of Secure
Shell or SSH.
- Part II will cover additional software the sysadmin can install,
such as log analyzers, port monitors, and kernel modifications.
Some of the built-in firewalling capabilities of Linux will also
be examined in Part II.
Before undertaking the task of securing a machine, it is a advisable to
determine the purpose that machine will serve. Will the system serve only
as a web server, a mail server, or a combination of other services? The
server's purpose should be planned well in advance, so the admin can best
determine the approach to properly secure the machine. As cheap as
computing power is these days, there is little justification for a single
machine that is publicly exposed to the Internet to serve multiple
functions. As a rule, a web server should provide only web services and
should not provide FTP or SMTP services. By limiting the services a
machine provides, the sysadmin can significantly limit the risk of the
machine being compromised.
Another thing for the admin to consider is the type of intruder they are
trying to secure this machine against. While most admins prepare against
attacks from outside, very few take any form of precaution against intruders
from within their organization. This is known as a "hard crunchy shell with
a soft chewy inside" security model. Such an approach is ill-advised, given
recent statistics which indicate that 60 to 75 percent of computer intrusions
are actually committed by insiders.
With the above in mind, this document will place special emphasis on
securing the machine in such a way that it can readily repel both remote
and local attacks.
- Prerequisites
It is assumed that the reader already has a freshly-installed Linux machine with
a freshly built kernel and wishes to secure it. Although this paper concentrates on
securing a Slackware Linux machine, the concepts here can be applied to most
any flavor of Linux or Unix, whether a SVR4 or BSD derivative. It is also assumed
that the machine is already configured with a TCP/IP stack and is ready to be
placed on a network. Understanding of fundamental concepts of Unix (such as file
permissions and editing scripts) will be helpful.
Disclaimer:
Properly securing a machine can be a daunting task; especially with the
amount of new exploits surfacing on an almost daily basis. This paper is
not meant to be a total security solution, but should instead be regarded
as a guide to security through many of the measures that can be taken to
protect a machine from intruders.
- Services
Before installing any software to increase the machine's security, the first
task in locking down the system is shutting down services. This is
accomplished by means provided by Linux.
- Logging
Logging on Unix system is handled by the syslogd daemon. As with Linux's
overall default security posture, the default logging leaves much to be
desired. The global file that controls how logging is handled, and where
log files are stored is the /etc/syslog.conf file:
-- sample syslog.conf section --
*.=info;*.=notice /usr/adm/messages
*.=debug /usr/adm/debug
-- sample syslog.conf section --
(1).(2) (3)
- /etc/syslog.conf fields explained
- Facility: The actual subsystem that provides the message. This may be one
of the keywords listed below or an asterisk (*) for everything.
- Syslog level (priority): Determines the severity of the message
- Action: Determines how the information passed from syslogd will be
handled.
Note: The facility and priority must be separated by a period. From the example above we
can see that any 'information' or 'notice' messages produced by any of the subsystems
facilities are logged to /usr/adm/messages and all 'debug' messages produced by any subsystem
is logged to /usr/adm/debug.
The following tables list the facility and priority keywords available:
- Facility keywords
- auth
logs information regarding user authentication
- authpriv
Same as above but also provides authentication that may
include privileged information such as usernames
- cron
logs information associated with the cron daemon
- daemon
logs information from system daemons
- kern
logs kernel related messages
- lpr
logs printer service related messages
- mail
logs messages related to electronic mail
- mark
used to generate timestamps in logfiles
- news
logs messages related to internet news
- security
same as auth
- syslog
logs messages generated by syslog
- user
logs messages generated by user programs
- uucp
logs messages related to uucp
- local0 - local7
used for logging by customized programs
- Priority keywords (from lowest to highest)
- debug
logs debugging information
- info
logs informational messages
- notice
a condition that should be handled in a special way
- warning
system warning
- warn
same as above
- err
system error
- crit
critical condition
- alert
condition that needs intervention
- emerg
possible system crash
- panic
system panic
Note: By default, syslog will log the priority selected in syslog.conf and
all priorities above that priority. To log only a specific priority the
equal (=) operator may be used:
mail.=info
This would log only informational messages related to electronic mail
- Actions
- file
the path to log the information to, such as: /var/adm/messages
- terminal
log to a console, such as /dev/tty1
- printer
log to a printer, such as /dev/lp1
- @hostname
the hostname of a remote machine send logs to
- username
use 'write' to send messages to specified user
- named pipe
send logs to a FIFO file
Armed with this knowledge we can create a better syslog.conf file that is custom-tailored to
our particular system.
- Sample syslog.conf
-- begin sample syslog.conf --
*.=info;*.=notice;*.warn;mail.none /usr/adm/messages
*.=debug /usr/adm/debug
*.warn;*.crit;*.emerg /usr/adm/syslog
*.warn;*.crit;*.emerg /usr/adm/messages
auth.* /usr/adm/log.auth
cron.* /usr/adm/log.cron
daemon.* /usr/adm/log.daemon
kern.* /usr/adm/log.kern
mail.* /usr/adm/log.mail
mark.* /usr/adm/log.mark
syslog.* /usr/adm/log.syslog
user.* /usr/adm/log.user
-- end sample syslog.conf --
As you can see we are still logging nearly everything to /usr/adm/messages,
but we are also logging individual facilities to individual log files.
Though this will increase the amount of disk space used by the log files,
it will also greatly increase your logging capabilities. Notice that
multiple entries may appear on the same line as long as they are separated
by a semicolon (;).
Part II of this article will discuss some methods and programs that can be
used to easily manage these log files.
- SUID/SGID Binaries
SUID and SGID files are files with a special bit set on them that allow a
regular user to run binaries with elevated privileges. As an example, the
Sendmail program must access system resources that only the root user can
normally access. By making the Sendmail program Set User ID (SUID) root, a regular
user will still be able to run the program. A Group User ID (SGID) file follows the
same approach but runs the binary with a group other than that of which the user belongs
to. These files will often be the focus of malicious local users looking to gain
unauthorized elevated privileges. These files are easy to spot because of the SUID/SGID flag:
# ls -al /usr/sbin/sendmail
r-sr-xr-x 1 root kmem 326329 Oct 15 01:21 /usr/sbin/sendmail
Notice in the user permission field for the files owner there is an 's'
where you normally find an 'x'. This indicates the file is SUID and can be
executed by a regular user even though the files runs with elevated
privileges.
# ls -al /usr/sbin/foo
r-xr-sr-x 2 foo foo 14567 Oct 15 01:22 /usr/sbin/foo
In this example we find an 's' in place of the executable bit in the group
permissions field. This indicates the file is SGID and can be run by a
regular user but with elevated group access.
- Locating and Removing SUID/SGID Binaries
It is a good idea to determine what binaries on our system are SUID/SGID and
try to reduce that list to the bare minimum. The following command will
search the entire file system for SUID/SGID files and list them in a file
called /tmp/suids. We are going to use this list as a script to remove
unnecessary SUID/SGID files.
#find / \( -perm -4000 -o -perm -2000 \) -exec ls -ldb {} \; >> /tmp/suids
Now we can examine the /tmp suids file with an editor and remove any files
from the list we wish to allow to remain running SUID/SGID. Most files that
are set SUID/SGID can be run with more favorable permissions. Another
option to removing the SUID and SGID bits is to refine the access control
to limit access to those files to a particular group.
After we have determined which files we wish to remain running SUID/SGID we
can use vi to convert our file into a script.
- cat /tmp/suids |cut -b55-200 > $HOME/remove_suid.sh
- cd
- vi remove_suid.sh
- :%s/ \//chmod -s \//g
- <return>
- Add the following to the top of the file:
- #!/sbin/sh
- :wq!
- chmod 700 remove_suid.sh
- ./remove_suid.sh
The script will then strip the SUID and SGID bits from any files that were
left on our list. After running the script run the above find command
again to ensure the bits were stripped properly. Ensure these files are
removed from the /tmp and $HOME directories once the script has been
executed.
- TCP-Wrappers
TCP-Wrappers is an access control mechanism for TCP and UDP services written and
maintained by Wietse Venema. Fortunately, TCP Wrappers comes default with most flavors
of Linux. If for some reason you do not have TCP Wrappers on your system, it
can be obtained from ftp://ftp.porcupine.org/pub/security.
TCP-Wrappers are designed to restrict TCP or UDP services called from inetd to
particular host names and or IP addresses. They can also be used to restrict
certain hostnames and or IP addresses from accessing TCP and UDP services.
This is done through two separate access control lists. The first,
/etc/hosts.allow determines what hosts are allowed to connect to what
services. The second file, /etc/hosts.deny determine what hosts are
specifically restricted from what services. These access control lists
provide a powerful and flexible method for allowing and denying access to a
system. First we will examine a sample /etc/hosts.allow file:
-- sample /etc/hosts.allow file --
wu.ftpd: 192.168.1.1, 192.168.1.2
ipop3d: barney
-- sample /etc/hosts.allow file --
The syntax of the file is fairly obvious. In the above example we are
allowing ftp access to the two IP addresses listed and pop access to the host
'barney'.
Typically setting up the /etc/hosts.deny file is even easier as we can see
in below:
-- sample /etc/hosts.deny file --
ALL: ALL
-- sample /etc/hosts.deny file --
At first glance it may seem we are restricting access to the system's
services to everyone. By setting up our access control list in this fashion we are
following the golden rule of "that which is not expressly permitted is
denied". Essentially we are denying everyone access to all services called
from inetd.conf with the exception of the hosts listed in the
/etc/hosts.allow file. Obviously this is a much better policy than the
flipside which is "everything is allowed except that which is forbidden".
These concepts may seem confusing but they are very simple. It is much
easier to deny everything to everyone then set up allows for specific
trusted hosts than to try and allow everything to everyone with the
exception of certain untrusted hosts.
TCP Wrappers also contains other specialized functions such as the ability
to set customized logging variables and also display a banner upon connection to
certain services. Be sure to consult the documentation included with the
distribution to use these features.
- SSH
There is no sane reason to still be using telnet to remotely connect to a
machine. With programs like telnet, all of our data is sent across the wire
unencrypted. SSH is a client-server utility that provides an encrypted
tunnel between two or more machines.
- Obtaining and Installing SSH
SSH v1.2.27 may be obtained from ftp://ftp.cs.hut.fi/pub/ssh/. Installing
SSH is rather straightforward. For a standard installation it is a matter of
running the 'configure script', executing 'make' and then 'make install'.
See the README for compile-time options to SSH. During installation a global
configuration file will be installed in /etc/sshd_config. Some of the
defaults entries for the configuration file are not very security conscious
and can be tightened up a bit. Following is a description of the default
entries.
Port 22
Defines what port the SSH daemon will listen on. Port 22 is the
standard port for SSH.
ListenAddress 0.0.0.0
Interface to bind the SSH daemon to. Unless you are running a
multi-homed host we can leave the default.
HostKey /etc/ssh_host_key
File containing the host's keys.
RandomSeed /etc/ssh_random_seed
File containing the random seed.
IdleTimeout 30m
Determines how long an idle client may remain connected before being
automatically disconnected. This should be set to a reasonable number.
This is a flexible option and can be specified in (s)econds, (m)inutes,
(h)ours, (d)ays, or (w)eeks.
ServerKeyBits 768
The number of bits for the server key.
LoginGraceTime 300
Sets the time, in seconds, that the SSHD daemon will
wait for a connected client to authenticate. Allowing a client 300 seconds
to authenticate is a bit extreme and should be lowered.
KeyRegenerationInterval 600
Sets the interval for the regeneration of new keys. 600 seconds is a
reasonable default.
PermitRootLogin no
Allow/disallow root logins. Root should never be
allowed to login remotely, that is what su is for.
IgnoreRhosts yes
If set to yes all $HOME/.rhosts are ignored. The /etc/hosts.equiv file is
unaffected by this option.
StrictModes yes
If set to the default of 'yes' the SSH daemon will not allow access to a
user whose home directory is owned by a different user.
QuietMode no
If set to 'no' all logging will be suppressed except for fatal errors.
Normal connection requests for SSH are handled through the syslog daemon.
Unless you are trying to debug an error this can be set to 'no'.
X11Forwarding no
If set to 'yes' the X Windows System forwarding is allowed. I typically do
not use X Windows and set this to 'no'.
X11DisplayOffset 10
Specifies the first X Windows display available to SSH for forwarding.
FascistLogging yes
If set to yes, the SSH daemon will provide extra logging that can be useful
for debugging purposes.
PrintMotd yes
If set to 'yes', the /etc/motd will be displayed after a user authenticates.
KeepAlive yes
If set to 'yes', the SSH daemon will periodically check the status of a
connection. If connectivity cannot be verified the connection will be
closed.
SyslogFacility DAEMON
The default syslog facility.
RhostsAuthentication no
If set to 'no' does not allow .rhosts or /etc/hosts.equiv authentication.
This should never be set to yes under any circumstances.
RhostsRSAAuthentication no
Enables or disables RSA Key Authentication. This should be set to 'no'.
RSAAuthentication no
Enables and disables RSA Authentication.
PasswordAuthentication yes
Enables or disables password authentication. For obvious reasons, this
should never be set to 'no'.
PermitEmptyPasswords no
If set to 'yes' users with blank passwords may still authenticate. Obviously
this should be set to 'no'.
The sshd_config file also provides an additional layer of protection by
allowing only specific IP addresses to connect.
The following entry will allow users to connect from only the IP address
listed:
#Restrict connections to one IP address
AllowHosts 192.168.1.1
Currently our SSH daemon has not been started. Now that we have made the
desired changes to the sshd_config file we may start it by invoking:
# /usr/local/sbin/sshd
On Slackware systems, the /etc/rc.d/rc.inet2 file will start the SSH daemon
automatically when the system is rebooted. If you are using a different
flavor of Linux you may have to add an entry to your rc.local file.
- Using SSH
Using SSH to connect to a remote host is as easy as using telnet. The
general syntax is:
$ ssh -l hostname
Included with the SSH package is another incredibly handy utility, Secure
Copy (SCP). SCP, as it's name implies, is a secure method to copy files from
one host to another. This can all but eliminate the systems administrator's
need for running ftpd to transfer files insecurely. The general syntax for
SCP is:
$ scp :/path/to/file /path/to file/on/local/machine
As an example let's say we wish to copy the file /etc/foo from host spanky
to host alfalfa. The following is a capture of that session:
$ scp spanky:/etc/foo /etc/foo
user@remotehost.com's password:
foo | 0 KB | 0.0 kB/s | ETA: 00:00:00 | 100%
$
SSH also contains a wealth of other features such as secure X11 Port
Forwarding, and application proxying. Take the time to read the
documentation that is included with the distribution. (I generally do
./configure --without-x because I do not trust X.)
- Tripwires
Tripwire is a commercial program that can be used to monitor and detect
changes to critical files and binaries on your system. Often times an
attacker will replace a binary on a system with a trojaned version. As an
example, the 'ps' command is frequently trojaned binary. The attacker can
configure the trojaned version of 'ps' to hide any system processes, such as
a sniffer, from the machines administrator. The heart of tripwire is the MD5
series of encryption algorithms. MD5 works by taking a message (this can be
a binary file or a text file) as it's input, and producing a 128-bit digital
fingerprint as it's output. An example is shown below.
-------
ps -----------> | MD5 | -------------> b38674b49f679a4ecdd47b7e0642dc85
-------
Generally a database of fingerprints for important system binaries and files
is generated and kept offline or read-only media. If an attacker was to modify
the ps binary in any way and we generated a new fingerprint, it would be
drastically different than the first fingerprint we generated. Keeping the
fingerprint database stored offline or on read-only media cannot be stressed
enough. If this database is kept online and attacker could easily trojan a
system and then generate new fingerprints to the database. The next time
fingerprints were reconciled, the prints would match. This also goes back to
what I said about proactive security. If you are implementing a tripwire
on a system that is already in place, you may be generating fingerprints for
binaries that had already been trojaned. Another reason why it is best to
start out on a freshly installed system
Essentially Tripwire is a program written around the MD5 algorithm. I have
always found it to be a bit cumbersome so we will take a look at building a
home-made tripwire using readily available software. Depending on your needs,
if you'd prefer to use the commercial product it may be obtained from
www.tripwire.com.
Now we will take a look at setting up a home-made tripwire. First we need to
generate a set of known good fingerprints. A minimal set of recommended
binaries to tripwire are already in the script. The script is generic and
can be easily modified to suit your needs.
Note: This script relies on the md5sum utility which is a default package
for most Linux installations. If md5sum is not installed on your system, it
may be downloaded from: ftp://ftp.pgp.net/pub/pgp/utils/md5sum/.
--begin generate.sh--
#!/bin/sh
#Generate a set of known-good fingerprints for important system files
#Make sure you have a blank floppy formatted with the ext2 file system
#in /dev/fd0
mount -t ext2 /dev/fd0 /mnt
md5sum /sbin/ifconfig > /mnt/database.orig
md5sum /bin/netstat >> /mnt/database.orig
md5sum /usr/bin/who >> /mnt/database.orig
md5sum /usr/bin/md5sum >> /mnt/database.orig
md5sum /bin/ls >> /mnt/database.orig
md5sum /bin/ps >> /mnt/database.orig
md5sum /usr/sbin/syslogd >> /mnt/database.orig
md5sum /sbin/ifconfig >> /mnt/database.orig
md5sum /usr/sbin/inetd >> /mnt/database.orig
sleep 5
umount /dev/fd0
--end generate.sh--
We now have a known clean set of fingerprints for our important system files
on a floppy disk. Be sure to write-protect the floppy via the physical tab
located on the floppy disk, or optimally, burn the fingerprints to CD-ROM.
The following script will generate a new set of fingerprints called /tmp/databse,
mount the media which the known good set of prints is contained on, compare the two
sets of fingerprints, and then take appropriate measures. The /tmp/database file will
then be removed and the media with the known-good set of prints will be unmounted.
Once again this script can be easily tailored to suit your particular needs.
Note: This script can be run from cron on whatever basis you feel is
necessary. If paranoid, once an hour wouldn't hurt. Ensure the permissions on
the /tmp directory are readable and writable by root only. Also ensure that
you save this file with the proper file permissions, otherwise all the work we
have done can easily be thwarted by a clever attacker. The following crontab
will run this script once an hour:
00 * * * * /bin/sh /usr/sbin/update.sh
--begin update.sh--
#!/bin/sh
# A customizable tripwire
# Thanks to munge@attrition.org for the shell scripting help
# Mount our known-good fingerprint database
# Change /dev/fd0 to suit your needs
mount -t ext2 /dev/fd0 /mnt
# additionally add to email to root?
if [ $? -ne 0 ]
then echo "Aborting, perhaps disk is not in drive?"
exit 99
fi
# this gets run in 2 situations, what the hell:
RMS() {
rm -f /tmp/database /tmp/diffs
}
# Generate a new batch of fingerprints and temporarily store them in
/tmp/database
sleep 5
md5sum /sbin/ifconfig > /tmp/database
md5sum /bin/netstat >> /tmp/database
md5sum /usr/bin/who >> /tmp/database
md5sum /usr/bin/md5sum >> /tmp/database
md5sum /bin/ls >> /tmp/database
md5sum /bin/ps >> /tmp/database
md5sum /usr/sbin/syslogd >> /tmp/database
md5sum /sbin/ifconfig >> /tmp/database
md5sum /usr/sbin/inetd >> /tmp/database
sleep 5
# DIAGNOSTICS
# An exit status of 0 means no differences were found,
# 1 means some differences were found, and 2 means trouble.'
# 'create temp file of diffs:'
# Compare the newly generated set of fingerprints to the known good set
diff /tmp/database /mnt/database.orig > /tmp/diffs
# '$? is the exit code of the previous command'
EXIT=$?
# if all is well mail will be sent to root
if [ $EXIT -eq 0 ]
then echo "Finger Prints match" | mail -s FingerPrints root
RMS ; # run the rm function
umount /mnt
exit 0 ; # no need to run the rest of the program, die
fi
# rest of program assumes things have gone badly....
# Insert this as the first line of the body
# and pipe to mail:
# If fingerprints don't match mail root stating so
sed '1iBAD MATCH! SHAME ON ADMIN!
' /tmp/diffs | mail -s FingerPrints root
# 'changed rm flag to -f so your
# program does not crap out if
# it does not find the file'
RMS
umount /mnt
# Additionally send mail to our pager stating we have a problem
# Something bad has happened so halt the machine after the page has been
# sent.
if [ $EXIT -ne 0 ]
then echo "Possible System Compromise" | mail -s "Badmatch!" pager@pagemart.net
sleep 30
shutdown -h now
fi
--end update.sh--
- Closing
If you take the time to walk through your filesystem and ensure that both
file and group permissions are reasonable you should then have a secure Linux
machine. In the next article additional measures and software will be discussed
that can be used to further secure the machine. Remember, the security of a machine
is an on-going job. Stay current with new exploits and vulnerabilities. Know your
system and know your software. It is always a good idea to frequently audit your system
to make sure none of the controls you have put into place have been
compromised.
One other thing to keep in mind is the physical security of a machine. Yes,
you may have spent the greater part of a day securing that box but it only
took Bob the Disgruntled Employee five minutes to reboot the system with
installation floppies and add himself a root account. If the machine must
remain in a place accessible to others invest in floppy drive locks or
remove the floppy drive altogether.
To read Securing Linux Part II, click here.
|