Subject: Beginner's guide to armoring Linux
From: <Microsoft Internet Explorer 5¡Æ¢® AuAa>
Date: Sun, 17 Jun 2001 12:27:20 +0900

Preparing
your linux box for the Internet
Armoring
Linux

Lance
Spitzner
http://www.enteract.com/~lspitz

Last Modified: 19 September, 2000

Organizations throughout the world are adopting Linux as their production
platform.   By connecting to the Internet to provide critical
services, they also become targets of opportunity.  To help protect these
Linux systems, this article covers the basics of securing a Linux box.  The
examples provided here are based on Red Hat 6.0, but should apply to most Linux
distributions.

Installation
The best place to start in armoring
your system is at the beginning, OS installation. Since this is a production
system, you cannot trust any previous installations. You want to start with a
clean installation, where you can guarantee the system integrity. Place your
system in an isolated network. At no time do you want to connect this box to an
active network nor the Internet, exposing the system to a possible compromise. I
personally witnessed a system hacked by a script kiddie within 15
minutes of connecting to the Internet.  To get critical files and patches
later, you will need a second box that acts as a go between. This second box
will download files from the Internet, then connect to your isolated,
configuration "network" to transfer critical files or burn the patches to a
CDROM.

Once you have placed your future Linux box in an isolated network, you are
ready to begin. The first step is selecting what OS package to load. As of RH
6.0, you have three options, Workstation, Server, and Custom (default).  I
highly recommend Custom, as this allows you to choose what services are added
and how the system is partitioned.  The idea is to load the minimum
packages, while maintaining maximum efficiency.   The less software
that resides on the box, the fewer potential security exploits or holes.
This means if you do not need a News or Real Audio Server, don't install
it.  The nice thing about Linux is, if you change your mind, it is easy to
add packages later.  Regardless of which installation you choose, I would
add the manual pages and HOWTO docs.  I find the on-line man pages and docs
to be a critical resource that add little risk to your system.

If you selected Custom, you will be asked to partition your system.  I
always like to make root as big as possible and just throw everything in there,
then you do not run out of room in the future.  However, we do need several
partitions to protect the root drive.  If we were to fill the root
partition with data, such as logging or email, we would cause a denial of
service, potentially crashing the system.

Therefore, I always recommend a separate partition for /var, this is where
all the system logging and email goes.  By isolating the /var partition,
you protect your root partition from overfilling.   I've found 400 MB
to be more then enough for /var (increase this if your system will have alot of
mail) .  You may also consider making a separate partition for specific
application purposes, especially applications that store extensive logging. If
you are going to have users on your system you do not trust, you may also want
to create a seperate /home directory, so malicious users cannot fille the /
partition. For a standalone server, your partitions may look as follows:

/        - everything
else
/var     - 400 MB
swap     - (I
normally go with 256 MB)

Once the system has rebooted after the installation, be sure to install the
recommend security patches. For Red Hat, you can find these security patches at
Red Hat's errata
support site.  Patches are critical to armoring a system and should
always be updated.  [email-masked]
or [email-masked]
are excellent sources for following bugs and system patches.  Without these
patches, your system can be easily compromised.  Be sure to use your go
between box to get the patches, the Linux box should always remain on an
isolated network. . For Red Hat, once you download the rpm, you can easily
update your system using the following syntax.  An excellent example of
this is the security update for wu-ftpd

rpm -Uvh
wu-ftpd-2.6.0-14.6x.i386.rpm

For systems that are already on-line, you can ftp the rpm and install it at
the same time, using the following syntax.

rpm -Uvh
ftp://updates.redhat.com/6.1/i386/wu-ftpd-2.6.0-14.6x.i386.rpm

To maintain your patches, I highly recommend the utility autorpm. This command line utility
determines which .rpm's need to be updated, gets those rpm's from Red Hats's web
site, and then downloads and installs the updated files (if you so desire). This
tool is highly customizable and easy to use. The best thing is it can run out of
cron, so your file system gets checked every night, then emails you the next day
that you should update your system.

Eliminating
Services
Once you have loaded the installation package,
patches, and rebooted, we are now ready to armor the operating system. Armoring
consists mainly of turning off services, adding logging, tweaking several files,
and configuring TCP Wrappers. First we will begin with turning off services.

By default, Linux is a powerful operating system that executes many useful
services. However, most of these services are unneeded and pose a potential
security risk. The first place to start is /etc/inetd.conf. This file specifies
which services the /usr/sbin/inetd daemon will listen for. By default,
/etc/inetd.conf is configured for a variety of services, you most likely only
need two, ftp and telnet. You eliminate the remaining unnecessary services by
commenting them out (example A).
This is critical, as many of the services run by inetd pose serious security
threats, such as popd, imapd, and rsh.  Confirm what you have commented out
with the following command (this will show you all the services that were left
uncommented)

grep -v "^#"
/etc/inetd.conf

The next place to start are the .rc scripts, these scripts determine what
services are started by the init process. For Red Hat, you will find these
scripts in /etc/rc.d/rc3.d (or /etc/rc.d/rc5.d if you automatically boot to a
GUI, such as Gnome or KDE).  To stop a script from starting, replace the
capital S with a small s. That way you can easily start the script again just by
replacing the small s with a capital S. Or, if you prefer, Red Hat comes with a
great utility for turning off these services.  Just type "/usr/sbin/setup" at the
command prompt, and select "System Services", from there you can select what scripts
are started during the boot up process.  Another option is chkconfig, which you will
find on most distributions.  The following startup scripts may be installed
by default but are not critical to system functioning.  If you don't need
them, turn these scripts off.  The numbers in the names determine the
sequence of initialization, they may vary based on your distribution and
version.  Scripts that start with a capital K instead of a captial
S are used to kill services that are already running.

S05apmd       (You only need this
for laptops)
S10xntpd     (Network time
protocol)
S11portmap   (Required if you have any rpc services,
such as NIS or NFS)
S15sound     (Saves sound cared
settings)
S15netfs     (This is the nfs client, used
for mounting filesystems from a nfs server)
S20rstatd    (Try
to avoid running any r services, they provide too much information to
remote users)
S20rusersd
S20rwhod
S20rwalld
S20bootparamd (Used for diskless
clients, you probably don't need this vulnerable service)

S25squid     (Proxy server)

S34yppasswdd (Required
if you are a NIS server, this is an extremely vulnerable service)

S35ypserv    (Required if you are a NIS server,
this is an extremely vulnerable service)
S35dhcpd
(Starts dhcp server daemon)
S40atd       (Used for the at
service, similar to cron, by not required by the system)
S45pcmcia    (You
only need this script for laptops)
S50snmpd
(SNMP daemon, can give remote users detailed information about your
system)
S55named     (DNS server.  If you are
setting up DNS, upgrade to the latest version of BIND,  http://www.isc.org/bind.html)

S55routed    (RIP, don't run this unless you
REALLY need it)
S60lpd       (Printing
services)
S60mars-nwe   (Netware file and print
server)
S60nfs       (Use for NFS server,
do not run unless you absolutely have to).
S72amd        (AutoMount
daemon, used to mount remote file systems)
S75gated      (used to run other routing
protocols, such as OSPF)
S80sendmail  (You can still
send email if you turn this script off, you just will not be able to receive or
relay)
S85httpd     (Apache webserver, I recommend
you upgrade to the latest version, http://www.apache.org/)

S87ypbind     (Required if you are a NIS
client)
S90xfs       (X font
server)
S95innd      (News server)

S99linuxconf
(Used to remotely configure Linux systems via browser, every black-hat's dream
:)

To see how many services are running before you change the startup scripts,
type

ps aux | wc -l

Once you are done with the installation and have turned off the startup
scripts, type the command again and compare how the number of services have
decreased. The fewer services running, the better. Also, confirm which are left
running by executing the following command:

netstat -na --ip

Logging and
Tweaking
Once you have eliminated as many services as
possible, we want to enable logging. All system logging occurs in
/var/log.   By default, Linux has excellent logging, except for
ftp.  You have two options for logging for ftp, configure /etc/ftpaccess
file or edit /etc/inetd.conf.  I prefer to edit /etc/inetd.conf, as it is
simpler (i.e. harder to mess up :).  Edit /etc/inetd.conf as follows to
ensure full logging of all FTP sessions.

ftp
stream  tcp     nowait  root
/usr/sbin/tcpd  in.ftpd -l -L -i -o

--- From the man pages
---

If the -l option is specified,
each ftp session is logged in the syslog
If the -L flag is used, command logging
will be on by default as soon as the ftp server is invoked.  This will
cause  the  server  to log all USER commands, which if a user
accidentally enters a password for that command instead of the username, will
cause passwords to be logged via syslog.
If the -i option is specified, files
received by the ftpd(8) server will be logged to the xferlog(5).

If the -o option is
specified, files transmitted by the ftpd(8) server will be logged to the
xferlog(5).

--- snip snip
---

Next comes tweaking. This involves various file administration. The first
thing we want to do is secure our /etc/passwd file (this is the database file
that holds your user accounts and passwords).  First, we want to ensure our
system is using /etc/shadow, this securely stores everyone's password as hashes
in a file only root can access.  This protects your passwords from being
easily accessed and cracked (one of the first exploits a hacker looks
for).  The use of shadow passwords is default as of RH 6.0, however it
never hurts to be sure. All you have to do is type the following command as
root.  This automatically  converts your passwords to the /etc/shadow
file. Of all the actions you can take to secure your system, I consider this to
be one of the most important.

pwconv

The second step is to remove most of the default system accounts in
/etc/passwd.  Linux provides these accounts for various system activities
which you may not need.  If you do not need the accounts, remove
them.  The more accounts you have, the easier it is to access your
system.  An example is the "news" account.  If you are not running
nntp, a news group server, you do not need the account (be sure to update
/etc/cron.hourly, as this looks for the user "news"). Also, make sure you remove
the "ftp" account, as this is the account used for anonymous ftp.  From the
man pages.

man ftpd:

Ftpd authenticates users according
to four rules.

4)     If
the  user name is ``anonymous'' or ``ftp'', an anonymous ftp account must
be pre-sent in the password file (user ``ftp'').  In this case the user is
allowed to log in by specifying any password (by convention this is given as the
client host's name).

For an example of my /etc/passwd file, check out example C.

We also want to modify the file /etc/ftpusers (example D). Any
account listed in this file cannot ftp to the system. This restricts common
system accounts, such as root or bin, from attempting ftp sessions. Linux has
the file by default.  Ensure that root stays in this file, you never want
root to be able to ftp to this system.  Ensure that any accounts that need
to ftp to the box are NOT in the file /etc/ftpusers.

Also, ensure that root cannot telnet to the system. This forces users to
login to the system as themselves and then su to root. The file /etc/securetty
lists what ttys root can connect to.  List only tty1, tty2, etc in this
file, this restricts root logins to local access only.  ttyp1, ttyp2, are
pseudo terminals, they allow root to telnet to the system remotely (example E).

Last, create the file /etc/issue. This file is an ASCII text banner that
appears for all telnet logins (example B). This
legal warning will appear whenever someone attempts to login to your system. If
you want to continue using the same /etc/issue file, you will have to modify
/etc/rc.d/init.d/S99local.  By default, Linux creates a new /etc/issue file
on every reboot.

Connecting to
your server
For those of you who will be doing remote
administration, it is critical that you develop a secured, controlled way to
connect to the server.  Often, you need remote access to your server for
administration or the uploading of files, these communications need to be
secured  I will discuss two options here, ssh and TCP Wrappers.

I prefer ssh, as it encrypts all communication between you and the
firewall.  TCP Wrappers will NOT protect your network traffic from
sniffing.  Users can still capture all of your keystrokes
(including passwords) on the network.  If you are concerned about users
capturing communications to your firewall, I recommend you replace telnet/ftp
with ssh.  ssh will encrypt all communications to your server, allowing you
both to upload files and administer the server in a secure manner.  ssh is
similar to TCP wrappers in that it has its own layer of logging, and can limit
what systems can connect to it.  For more information on ssh, you can find
ssh here, including source for
both ssh clients and server daemon.  I recommend you use ssh version 1.2.x,
as version 2.x has a limiting license. Another ssh option is Openssh.

TCP Wrappers, while it does not encrypt, it does log and control who can
access your system.  It is a binary that wraps itself around inetd
services, such as telnet or ftp. With TCP Wrappers, the system launches the
wrapper for inetd connections, logs all attempts and then verifies the attempt
against a access control list. If the connection is permitted, TCP Wrappers
hands the connection to the proper binary, such as telnet. If the connection is
rejected by the access control list, then the connection is dropped.
Fortunately for us Linux users, TCP Wrappers is already installed, the only
thing left for us to do is edit the /etc/hosts.allow and /etc/hosts.deny
file.  These files determine who can and cannot access our systems.
Also, TCP Wrappers allows us to do fancy things, such as banners or spawn
additional programs, such as safe_finger.  The syntax is relatively
simple.  Put the IP address or networks in /etc/hosts.allow that you want
to permit connections from.  Put IP addresses or networks in
/etc/hosts.deny that you do not want to permit access.  By default, Linux
allows connections from everyone, so you will need to modify these files.
2 recommendations when working with TCP Wrappers.

Use IP addresses instead of system or domain names.

Set up /etc/hosts.deny to deny everything (ALL), then permit only specific
sites with /etc/hosts.allow.

For examples on how to setup
/etc/hosts.allow and /etc/hosts.deny, see example F.
For more ideas on how to use TCPWrappers, check out Intrusion Detection.

For the Truly
Paranoid
I consider the measures discussed above
absolutely essential.  By following these steps, you have greatly improved
your system's security, congratulations!  Unfortunately, your system is not
100% secure, nor will it ever be.  So, for the truly paranoid, I have added
some additional steps you can take.

First we will create the wheel group.  The wheel group is a group of
select individuals that can execute powerful commands, such as /bin/su. By
limiting the people that can access these commands, you enhance the system
security.  To create the group, vi the file /etc/group, create the group
wheel, and add the system admins to the group.  Then identify critical
system binaries, such as /bin/su.  Change the group ownership to wheel, and
the permissions to owner and group executable only (be sure to maintain the suid
or guid bit for specific binaries).  For /bin/su, the commands would be:

/bin/chgrp wheel
/bin/su
/bin/chmod 4750 /bin/su

Second, we will lock down the files .rhosts, .netrc, and
/etc/hosts.equiv.  The r commands use these files to access systems.
To lock them down, touch the files, then change the permissions to zero, locking
them down. This way no one can create or alter the files. For example,

/bin/touch /root/.rhosts
/root/.netrc /etc/hosts.equiv
/bin/chmod 0 /root/.rhosts /root/.netrc
/etc/hosts.equiv

Third, we configure /etc/shadow to use MD5 hashes instead of the
crypt(3) function.  This makes the encrypted password file far more
difficult to crack.  This is done by modifying the PAM modules.  PAM
(Pluggable Authentication Modules) is a suite of shared libraries that enable
you to choose how applications authenticate users.  To learn more about
PAM, check out ftp://ftp.us.kernel.org/pub/linux/libs/pam/Linux-PAM-html/pam.html

In the old days, you had to manually modify the PAM modules to use MD5
hashes.  However, with Red Hat 6.0 or greater, you can select MD5 hashes
with the setup utility.  Just type "setup" at the command prompt, then
select "authentication configuration".  From there, you can choose to use
MD5 hashes.  However, the MD5 hashes will not take effect until the user
re-enters their password.  For those of you who do not have the setup
utility (or have Red Hat 5.2 or earlier), you can still modify the PAM modules
manually (example
G).

For us bash users, I'm not a big fan of the .bash_history file.  I do
not want people (including root) to know my command history.  So, in my
.bash_profile, I export the following entry:

HISTFILESIZE=0

This means that nothing will be logged to my .bash_history file.  I will
still have keystroke history and recall, the HISTSIZE env variable, but command
history will not be written to the .bash_history file.

Last thing we can do is protect our system from physical access.  This
mainly consists of setting up a password for our BIOS.  Also, you can
password protect your system during boot-up by configuring /etc/lilo.conf with a
password (password=xxx)  where xxx is your password.
However, keep in mind, once someone has physical access to your system, there is
no guaranteed way to protect it.

IPChains
No discussion about Linux security would
be complete without covering IPChains.  IPChains is packet filtering
software that comes with the 2.2.x kernel and above. This means if you are
running Red Hat 6.0 or later, you have it as part of your Linux installation
kit.  IPChains is similar to Cisco Access Control Lists, it can control
what packets can come in and out of your Linux box.  Primarly used as a
firewall application, IPChains can also be used to armor your standalone Linux
box.    To armor a standalone system, I configure IPChains to
allow only TCP connections I initiate.  If anyone attempts to initate any
TCP connections to me, the connection is denied.  Since IPChains is not
stateful, I do allow all UDP and ICMP connections.  Last, I log all denied
connections, this lets me know if someone out there is being naughty :)
However, I drop but do not log all the broadcat/multicast traffic, as this would
quickly fill up the system logs. A simple IPChains configuration to armor a
standalone system would look something like this.

bash# ipchains
-L
Chain input
(policy DENY):
target prot opt source destination ports
DENY all ------ 0.0.0.0 anywhere
n/a
DENY all
------ anywhere 255.255.255.255 n/a
DENY all ------ anywhere
BASE-ADDRESS.MCAST.NET/8 n/a
ACCEPT tcp !y---- anywhere anywhere any
-> any
ACCEPT udp ----l- anywhere anywhere any -> any

ACCEPT icmp ----l- anywhere
anywhere any -> any
DENY all ----l- anywhere anywhere n/a
Chain forward (policy
ACCEPT):
Chain
output (policy ACCEPT):

To see the config files for this, see example H. To learn
more about using IPChains as a firewall or for a standalone system, check out
the IPChains
HOWTO.

Conclusion
We have covered some of the more basic
steps involved in armoring a Linux box (Red Hat distribution). The key to a
secure system is having the minimal software installed, with protection in
layers, such as TCP Wrappers, IPChains, and shadowed passwords. There are many
additional steps that can be taken, such as  tripwire
(monitor changes in system binaries) and swatch (automated log
monitoring and alerts). I also recommend that new Linux users check out Bastille Linux, a PERL script that can
automatically secure your new Linux system, step by step. Remember, no system is
truly 100% secure. However, with the steps outlined above, you greatly reduce
the security risks.

Author's bio

Lance Spitzner is currently an active member of the Honeynet Project. He enjoys learning by
blowing up systems in his home lab. Before this, he was a tanker in the Rapid
Deployment Force, where he blew up things of a different nature. You can
reach him at [email-masked] .

Whitepapers