Security Quick-Start HOWTO for Linux

Hal Burgiss

     hal@foobox.net
    

v. 1.2, 2002-07-21

Revision History
Revision v. 1.22002-07-21Revised by: hb
A few small additions, and fix the usual broken links.
Revision v. 1.12002-02-06Revised by: hb
A few fixes, some additions and many touch-ups from the original.
Revision v. 1.02001-11-07Revised by: hb
Initial Release.

Table of Contents
1. Introduction
1.1. Why me?
1.2. Copyright
1.3. Credits
1.4. Disclaimer
1.5. New Versions and Changelog
1.6. Feedback
2. Foreword
2.1. The Optimum Configuration
2.2. Before We Start
3. Step 1: Which services do we really need?
3.1. System Audit
3.2. The Danger Zone (or r00t m3 pl34s3)
3.3. Stopping Services
3.4. Exceptions
3.5. Summary and Conclusions for Step 1
4. Step 2: Updating
4.1. Summary and Conclusions for Step 2
5. Step 3: Firewalls and Setting Access Policies
5.1. Strategy
5.2. Packet Filters -- Ipchains and Iptables
5.3. Tcpwrappers (libwrap)
5.4. PortSentry
5.5. Proxies
5.6. Individual Applications
5.7. Verifying
5.8. Logging
5.9. Where to Start
5.10. Summary and Conclusions for Step 3
6. Intrusion Detection
6.1. Intrusion Detection Systems (IDS)
6.2. Have I Been Hacked?
6.3. Reclaiming a Compromised System
7. General Tips
8. Appendix
8.1. Servers, Ports, and Packets
8.2. Common Ports
8.3. Netstat Tutorial
8.4. Attacks and Threats
8.5. Links
8.6. Editing Text Files
8.7. nmap
8.8. Sysctl Options
8.9. Secure Alternatives
8.10. Ipchains and Iptables Redux

1. Introduction

1.1. Why me?

Who should be reading this document and why should the average Linux user care about security? Those new to Linux, or unfamiliar with the inherent security issues of connecting a Linux system to large networks like Internet should be reading. "Security" is a broad subject with many facets, and is covered in much more depth in other documents, books, and on various sites on the Web. This document is intended to be an introduction to the most basic concepts as they relate to Linux, and as a starting point only.


Iptables Weekly Log Summary from Jul 15 04:24:13 to Jul 22 04:06:00
Blocked Connection Attempts:

Rejected tcp packets by destination port

port                 count
111                  19
53                   12
21                   9
515                  9
27374                8
443                  6
1080                 2
1138                 1


Rejected udp packets by destination port

port                 count
137                  34
22                   1

    

The above is real, live data from a one week period for my home LAN. Much of the above would seem to be specifically targeted at Linux systems. Many of the targeted "destination" ports are used by well known Linux and Unix services, and all may be installed, and possibly even running, on your system.

The focus here will be on threats that are shared by all Linux users, whether a dual boot home user, or large commercial site. And we will take a few, relatively quick and easy steps that will make a typical home Desktop system or small office system running Linux reasonably safe from the majority of outside threats. For those responsible for Linux systems in a larger or more complex environment, you'd be well advised to read this, and then follow up with additional reading suitable to your particular situation. Actually, this is probably good advice for everybody.

We will assume the reader knows little about Linux, networking, TCP/IP, and the finer points of running a server Operating System like Linux. We will also assume, for the sake of this document, that all local users are "trusted" users, and won't address physical or local network security issues in any detail. Again, if this is not the case, further reading is strongly recommended.

The principles that will guide us in our quest are:

  • There is no magic bullet. There is no one single thing we can do to make us secure. It is not that simple.

  • Security is a process that requires maintenance, not an objective to be reached.

  • There is no 100% safe program, package or distribution. Just varying degrees of insecurity.

The steps we will be taking to get there are:

  • Step 1: Turn off, and perhaps uninstall, any and all unnecessary services.

  • Step 2: Make sure that any services that are installed are updated and patched to the current, safe version -- and then stay that way. Every server application has potential exploits. Some have just not been found yet.

  • Step 3: Limit connections to us from outside sources by implementing a firewall and/or other restrictive policies. The goal is to allow only the minimum traffic necessary for whatever our individual situation may be.

  • Awareness. Know your system, and how to properly maintain and secure it. New vulnerabilities are found, and exploited, all the time. Today's secure system may have tomorrow's as yet unfound weaknesses.

If you don't have time to read everything, concentrate on Steps 1, 2, and 3. This is where the meat of the subject matter is. The Appendix has a lot of supporting information, which may be helpful, but may not be necessary for all readers.


1.5. New Versions and Changelog

The current official version can always be found at http://www.tldp.org/HOWTO/Security-Quickstart-HOWTO/. Pre-release versions can be found at http://feenix.burgiss.net/ldp/quickstart/.

Other formats, including PDF, PS, single page HTML, may be found at the Linux Documentation HOWTO index page: http://tldp.org/docs.html#howto.

Changelog:

Version 1.2: Clarifications on example firewall scripts, and small additions to 'Have I been Hacked'. Note on Zonealarm type applications. More on the use of "chattr" by script kiddies, and how to check for this. Other small additions and clarifications.

Version 1.1: Various corrections, amplifications and numerous mostly small additions. Too many to list. Oh yea, learn to spell Red Hat correctly ;-)

Version 1.0: This is the initial release of this document. Comments welcomed.


2. Foreword

Before getting into specifics, let's try to briefly answer some questions about why we need to be concerned about security in the first place.

It is easy to see why an e-commerce site, an on-line bank, or a government agency with sensitive documents would be concerned about security. But what about the average user? Why should even a Linux home Desktop user worry about security?

Anyone connected to the Internet is a target, plain and simple. It makes little difference whether you have a part-time dialup connection, or a full-time connection, though full-time connections make for bigger targets. Larger sites make for bigger targets too, but this does not let small users off the hook since the "small user" may be less skilled and thus an easier victim.

There are those out there that are scanning just for easy victims all the time. If you start logging unwanted connection attempts, you will see this soon enough. There is little doubt that many of these attempts are maliciously motivated and the attacker, in some cases, is looking for Linux boxes to crack. Does someone on the other side of the globe really want to borrow my printer?

What do they want? Often, they just may want your computer, your IP address, and your bandwidth. Then they use you to either attack others, or possibly commit crimes or mischief and are hiding their true identity behind you. This is an all too common scenario. Commercial and high-profile sites are targeted more directly and have bigger worries, but we all face this type of common threat.

With a few reasonable precautions, Linux can be very secure, and with all the available tools, makes for a fantastically fun and powerful Internet connection or server. Most successful break-ins are the result of ignorance or carelessness.

The bottom line is:

These are all real possibilities, unless we take the appropriate precautions.

Warning

If you are reading this because you have already been broken into, or suspect that you have, you cannot trust any of your system utilities to provide reliable information. And the suggestions made in the next several sections will not help you recover your system. Please jump straight to the Have I been Hacked? section, and read that first.


2.2. Before We Start

Before we get to the actual configuration sections, a couple of notes.

First, one of the interesting aspects of Linux, is the different distributions like Caldera, Red Hat, SuSE, and Debian. While these are all "Linux", and may share certain features, there is surely some differences as to what utilities they may install as defaults. Most Linux distributions will write their own system configuration tools as well. And with Linux, there is always more than one way to skin a cat. But for the purposes of our discussion, we will have to use as generic set of tools as we can. Unfortunately, GUI tools don't lend themselves to this type of documentation. We will be using text based, command line tools for the most part. If you are familiar with your distribution's utilities, feel free to substitute those in appropriate places. And if not, you should learn them or suitable alternatives.

The next several sections have been written such that you can perform the recommended procedures as you read along. This is the "Quick Start" in the document title!

To get ready, what you will need for the configuration sections below:

We'll be using a hypothetical system here for examples with the hostname "bigcat". Bigcat is a Linux desktop with a fresh install of the latest/greatest Linux distro running. Bigcat has a full-time, direct Internet connection. Even if your installation is not so "fresh", don't be deterred. Better late than never.


3. Step 1: Which services do we really need?

In this section we will see which services are running on our freshly installed system, decide which we really need, and do away with the rest. If you are not familiar with how servers and TCP connections work, you may want to read the section on servers and ports in the Appendix first. If not familiar with the netstat utility, you may want to read a quick overview of it beforehand. There is also a section in the Appendix on ports, and corresponding services. You may want to look that over too.

Our goal is to turn off as many services as possible. If we can turn them all off, or at least off to outside connections, so much the better. Some rules of thumb we will use to guide us:


3.1. System Audit

So what is really running on our system anyway? Let's not take anything for granted about what "should" be running, or what we "think" is running.

Unfortunately, there is no such things as a standard Linux installation. The wide variety of servers available, coupled with each particular distribution's installation options, make providing a ready made list impossible. The best that can be done is show you how to list all running services, and point you in the right general direction.

Now open an xterm, and su to root. You'll need to widen the window wide so the lines do not wrap. Use this command: netstat -tap |grep LISTEN. This will give us a list of all currently running servers as indicated by the keyword LISTEN, along with the "PID" and "Program Name" that started each particular service.


# netstat -tap |grep LISTEN
  *:exec               *:*        LISTEN    988/inetd          
  *:login              *:*        LISTEN    988/inetd          
  *:shell              *:*        LISTEN    988/inetd          
  *:printer            *:*        LISTEN    988/inetd          
  *:time               *:*        LISTEN    988/inetd          
  *:x11                *:*        LISTEN    1462/X              
  *:http               *:*        LISTEN    1078/httpd          
  bigcat:domain        *:*        LISTEN    956/named           
  bigcat:domain        *:*        LISTEN    956/named           
  *:ssh                *:*        LISTEN    972/sshd            
  *:auth               *:*        LISTEN    388/in.identd
  *:telnet             *:*        LISTEN    988/inetd          
  *:finger             *:*        LISTEN    988/inetd
  *:sunrpc             *:*        LISTEN    1290/portmap
  *:ftp                *:*        LISTEN    988/inetd
  *:smtp               *:*        LISTEN    1738/sendmail: accepting connections 
  *:1694               *:*        LISTEN    1319/rpc.mountd
  *:netbios-ssn        *:*        LISTEN    422/smbd

 

Note the first three columns are cropped above for readability. If your list is as long as the example, you have some work ahead of you! It is highly unlikely that you really need anywhere near this number of servers running.

Please be aware that the example above is just one of many, many possible system configurations. Yours probably does look very different.

You don't understand what any of this is telling you? Hopefully then, you've read the netstat tutorial in the Appendix, and understand how it works. Understanding exactly what each server is in the above example, and what it does, is beyond the scope of this document. You will have to check your system's documentation (e.g. Installation Guide, man pages, etc) if that service is important to you. For example, does "exec", "login", and "shell" sound important? Yes, but these are not what they may sound like. They are actually rexec, rlogin, and rsh, the "r" (for remote) commands. These are antiquated, unnecessary, and in fact, are very dangerous if exposed to the Internet.

Let's make a few quick assumptions about what is necessary and unnecessary, and therefore what goes and what stays on bigcat. Since we are running a desktop on bigcat, X11 of course needs to stay. If bigcat were a dedicated server of some kind, then X11 would be unnecessary. If there is a printer physically attached, the printer (lp) daemon should stay. Otherwise, it goes. Print servers may sound harmless, but are potential targets too since they can hold ports open. If we plan on logging in to bigcat from other hosts, sshd (Secure SHell Daemon) would be necessary. If we have Microsoft hosts on our LAN, we probably want Samba, so smbd should stay. Otherwise, it is completely unnecessary. Everything else in this example is optional and not required for a normally functioning system, and should probably go. See anything that you don't recognize? Not sure about? It goes!

To sum up: since bigcat is a desktop with a printer attached, we will need "x11", "printer". bigcat is on a LAN with MS hosts, and shares files and printing with them, so "netbios-ssn" (smbd) is desired. We will also need "ssh" so we can login from other machines. Everything else is unnecessary for this particular case.

Nervous about this? If you want, you can make notes of any changes you make or save the list of servers you got from netstat, with this command: netstat -tap |grep LISTEN > ~/services.lst. That will save it your home directory with the name of "services.lst" for future reference.

This is to not say that the ones we have decided to keep are inherently safe. Just that we probably need these. So we will have to deal with these via firewalling or other means (addressed below).

It is worth noting that the telnet and ftp daemons in the above example are servers, aka "listeners". These accept incoming connections to you. You do not need, or want, these just to use ftp or telnet clients. For instance, you can download files from an FTP site with just an ftp client. Running an ftp server on your end is not required at all, and has serious security implications.

There may be individual situations where it is desirable to make exceptions to the conclusions reached above. See below.


3.2. The Danger Zone (or r00t m3 pl34s3)

The following is a list of services that should not be run over the Internet. Either disable these (see below), uninstall, or if you really do need these services running locally, make sure they are the current, patched versions and that they are effectively firewalled. And if you don't have a firewall in place now, turn them off until it is up and verified to be working properly. These are potentially insecure by their very nature, and as such are prime cracker targets.

This is not necessarily a definitive list. Just some common services that are sometimes started on default Linux installations. And conversely, this does not imply that other services are inherently safe.


3.3. Stopping Services

The next step is to find where each server on our kill list is being started. If it is not obvious from the netstat output, use ps, find, grep or locate to find more information from the "Program name" or "PID" info in the last column. There is examples of this in the Process Owner section in the netstat Tutorial of the Appendix. If the service name or port number do not look familiar to you, you might get a real brief explanation in your /etc/services file.

Skeptical that we are going to break your system, and the pieces won't go back together again? If so, take this approach: turn off everything listed above in "The Danger Zone", and run your system for a while. OK? Try stopping one of the ones we found to be "unnecessary" above. Then, run the system for a while. Keep repeating this process, until you get to the bare minimum. If this works, then make the changes permanent (see below).

The ultimate objective is not just to stop the service now, but to make sure it is stopped permanently! So whatever steps you take here, be sure to check after your next reboot.

There are various places and ways to start system services. Let's look at the most common ways this is done, and is probably how your system works. System services are typically either started by "init" scripts, or by inetd (or its replacement xinetd) on most distributions. (The location of the init scripts may vary from distribution to distribution.)


3.3.1. Stopping Init Services

Init services are typically started automatically during the boot process, or during a runlevel change. There is a naming scheme that uses symlinks to determine which services are to be started, or stopped, at any given runlevel. The scripts themselves should be in /etc/init.d/ (or possibly /etc/rc.d/init.d/ ). This init style is used by Red Hat, SuSE, Mandrake, Debian, Conectiva, and most Linuxes. Slackware is one notable exception (though recent versions have an option for this)! Typically on Slackware system services are all configured in one file: /etc/rc.d/rc.inet2.

You can get a listing of these scripts:


  # ls -l /etc/init.d/ | less 

 

Or use whichever tools your distribution provides for this.

To stop a running service now, as root (on SysVinit style systems, which is pretty much everybody):


 # /etc/init.d/<$SERVICE_NAME> stop

 

Where "$SERVICE_NAME" is the name of the init script, which is often, but not always, the same as the service name itself. This should do the trick on most distributions. Older Red Hat versions may use the path /etc/rc.d/init.d/ instead.

This only stops this particular service now. It will restart again on the next reboot, or runlevel change, unless additional steps are taken. So this is really a two step process for init type services.

Your distribution will have utilities available for controlling which services are started at various runlevels. Debian based systems have update-rc.d for this, and Red Hat based systems have chkconfig. If you are familiar with these tools, do it now, and then check again after the next reboot. If you are not familiar with these tools, see the man pages and learn it now! This is something that you need to know. For Debian (where $SERVICE_NAME is the init script name):

 
  # update-rc.d -f $SERVICE_NAME remove
 
 

And Red Hat:

 
 # chkconfig $SERVICE_NAME off
 
 

Another option here is to uninstall a package if you know you do not need it. This is a pretty sure-fire, permanent fix. This also alleviates the potential problem of keeping all installed packages updated and current (Step 2). And, package management systems like RPM or DEB make it very easy to re-install a package should you change your mind.


3.3.2. Inetd

Inetd is called a "super-daemon" because it is used to spawn sub-daemons. inetd itself will generally be started via init scripts, and will "listen" on the various ports as determined by which services are enable in its configuration file, /etc/inetd.conf. Any service listed here will be under the control of inetd. Likewise, any of the listening servers in netstat output that list "inetd" in the last column under "Program Name", will have been started by inetd. You will have to adjust the inetd configuration to stop these services. xinetd is an enhanced inetd replacement, and is configured differently (see next section below).

Below is a partial snippet from a typical inetd.conf. Any service with a "#" at the beginning of the line is "commented out", and thus ignored by inetd, and consequently disabled.


#
# inetd.conf  This file describes the services that will be available
#    through the INETD TCP/IP super server.  To re-configure
#    the running INETD process, edit this file, then send the
#    INETD process a SIGHUP signal.
#
# Version:  @(#)/etc/inetd.conf  3.10  05/27/93
#
# Authors:  Original taken from BSD UNIX 4.3/TAHOE.
#    Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
#
# Modified for Debian Linux by Ian A. Murdock <imurdock@shell.portal.com>
#
# Echo, discard, daytime, and chargen are used primarily for testing.
#
# To re-read this file after changes, just do a 'killall -HUP inetd'
#
#echo  stream  tcp  nowait  root  internal
#echo  dgram  udp   wait    root  internal
#discard  stream  tcp  nowait  root  internal
#discard  dgram  udp   wait    root  internal
#daytime  stream tcp   nowait  root  internal
#daytime  dgram  udp   wait    root  internal
#chargen  stream tcp   nowait  root  internal
#chargen  dgram  udp   wait    root  internal
time  stream    tcp   nowait  root  internal
#
# These are standard services.
#
#ftp     stream  tcp   nowait  root  /usr/sbin/tcpd  in.ftpd -l -a
#telnet  stream  tcp   nowait  root  /usr/sbin/tcpd  in.telnetd
#
# Shell, login, exec, comsat and talk are BSD protocols.
#
#shell  stream  tcp  nowait  root  /usr/sbin/tcpd  in.rshd
#login  stream  tcp  nowait  root  /usr/sbin/tcpd  in.rlogind
#exec   stream  tcp  nowait  root  /usr/sbin/tcpd  in.rexecd
#comsat dgram   udp  wait    root  /usr/sbin/tcpd  in.comsat
#talk   dgram   udp  wait    root  /usr/sbin/tcpd  in.talkd
#ntalk  dgram   udp  wait    root  /usr/sbin/tcpd  in.ntalkd
#dtalk  stream  tcp  wait    nobody /usr/sbin/tcpd in.dtalkd
#
# Pop and imap mail services et al
#
#pop-2   stream  tcp     nowait  root    /usr/sbin/tcpd  ipop2d
pop-3    stream  tcp     nowait  root    /usr/sbin/tcpd  ipop3d
#imap    stream  tcp     nowait  root    /usr/sbin/tcpd  imapd
#
# The Internet UUCP service.
#
#uucp  stream tcp nowait uucp /usr/sbin/tcpd  /usr/lib/uucp/uucico -l
#

<snip>

 

The above example has two services enabled: time and pop3. To disable these, all we need is to open the file with a text editor, comment out the two services with a "#", save the file, and then restart inetd (as root):


  # /etc/init.d/inetd restart  
 

 

Check your logs for errors, and run netstat again to verify all went well.

A quicker way of getting the same information, using grep:


 $ grep  -v '^#' /etc/inetd.conf
 time     stream  tcp     nowait  root  internal
 pop-3    stream  tcp     nowait  root  /usr/sbin/tcpd  ipop3d

 

Again, do you see anything there that you don't know what it is? Then in all likelihood you are not using it, and it should be disabled.

Unlike the init services configuration, this is a lasting change so only the one step is required.

Let's expose one myth that gets tossed around: you shouldn't disable a service by commenting out, or removing, entries from /etc/services. This may have the desired effect in some cases, but is not the right way to do it, and may interfere with the normal operation of other system utilities.


3.3.3. Xinetd

xinetd is an inetd replacement with enhancements. It essentially serves the same purpose as inetd, but the configuration is different. The configuration can be in the file /etc/xinetd.conf, or individual files in the directory /etc/xinetd.d/. Turning off xinetd services is done by either deleting the corresponding configuration section, or file. Or by using your text editor and simply setting disable = yes for the appropriate service. Then, xinetd will need to be restarted. See man xinetd and man xinetd.conf for syntax and configuration options. A sample xinetd configuration:


 # default: on
 # description: The wu-ftpd FTP server serves FTP connections. It uses \
 #       normal, unencrypted usernames and passwords for authentication.
 service ftp
 {
        disable                 = no
        socket_type             = stream
        wait                    = no
        user                    = root
        server                  = /usr/sbin/in.ftpd
        server_args             = -l -a
        log_on_success          += DURATION USERID
        log_on_failure          += USERID
        nice                    = 10
 }

 

You can get a quick list of enabled services:


 $ grep disable /etc/xinetd.d/* |grep no
 /etc/xinetd.d/finger:   disable = no
 /etc/xinetd.d/rexec:    disable = no
 /etc/xinetd.d/rlogin:   disable = no
 /etc/xinetd.d/rsh:      disable = no
 /etc/xinetd.d/telnet:   disable = no
 /etc/xinetd.d/wu-ftpd:  disable = no

 

At this point, the above output should raise some red flags. In the overwhelming majority of systems, all the above can be disabled without any adverse impact. Not sure? Try it without that service. After disabling unnecessary services, then restart xinetd:


  # /etc/init.d/xinetd restart  
 

 


3.3.4. When All Else Fails

OK, if you can't find the "right" way to stop a service, or maybe a service is being started and you can't find how or where, you can "kill" the process. To do this, you will need to know the PID (Process I.D.). This can be found with ps, top, fuser or other system utilities. For top and ps, this will be the number in the first column. See the Port and Process Owner section in the Appendix for examples.

Example (as root):


 # kill 1163

 

Then run top or ps again to verify that the process is gone. If not, then:


 # kill -KILL 1163

 

Note the second "KILL" in there. This must be done either by the user who owns the process, or root. Now go find where and how this process got started ;-)

The /proc filesystem can also be used to find out more information about each process. Armed with the PID, we can find the path to a mysterious process:


 $ /bin/ps ax|grep tcpgate
  921 ?   S    0:00        tcpgate

 


 # ls -l /proc/921/exe
 lrwxrwxrwx 1 root  root  0 July 21 12:11 /proc/921/exe -> /usr/local/bin/tcpgate

 


3.4. Exceptions

Above we used the criteria of turning off all unnecessary services. Sometimes that is not so obvious. And sometimes what may be required for one person's configuration is not the same for another's. Let's look at a few common services that fall in this category.

Again, our rule of thumb is if we don't need it, we won't run it. It's that simple. If we do need any of these, they are prime candidates for some kind of restrictive policies via firewall rules or other mechanisms (see below).


4. Step 2: Updating

OK, this section should be comparatively short, simple and straightforward compared to the above, but no less important.

The very first thing after a new install you should check your distribution's updates and security notices and apply all patches . Only a year old you say? That's a long time actually, and not current enough to be safe. Only a few months or few weeks? Check anyway. A day or two? Better safe than sorry. It is quite possible that security updates have been released during the pre-release phase of the development and release cycle. If you can't take this step, disable any publicly accessible services until you can.

Linux distributions are not static entities. They are updated with new, patched packages as the need arises. The updates are just as important as the original installation. Even more so, since they are fixes. Sometimes these updates are bug fixes, but quite often they are security fixes because some hole has been discovered. Such "holes" are immediately known to the cracker community, and they are quick to exploit them on a large scale. Once the hole is known, it is quite simple to get in through it, and there will be many out there looking for it. And Linux developers are also equally quick to provide fixes. Sometimes the same day as the hole has become known!

Keeping all installed packages current with your release is one of the most important steps you can take in maintaining a secure system. It can not be emphasized enough that all installed packages should be kept updated -- not just the ones you use. If this is burdensome, consider uninstalling any unused packages. Actually this is a good idea anyway.

But where to get this information in a timely fashion? There are a number of web sites that offer the latest security news. There are also a number of mailing lists dedicated to this topic. In fact, your vendor most likely has such a list where vulnerabilities and the corresponding fix is announced. This is an excellent way to stay abreast of issues effecting your release, and is highly recommended. http://linuxsecurity.com is a good site for Linux only issues. They also have weekly newsletters available: http://www.linuxsecurity.com/general/newsletter.html.

Also, many distributions have utilities that will automatically update your installed packages via ftp. This can be run as a cron job on a regular basis and is a painless way to go if you have ready Internet access.

This is not a one time process -- it is ongoing. It is important to stay current. So watch those security notices. And subscribe to your vendor's security mailing list today! If you have cable modem, DSL, or other full time connection, there is no excuse not to do this religiously. All distributions make this easy enough!

One last note: any time a new package is installed, there is also a chance that a new or revised configuration has been installed as well. Which means that if this package is a server of some kind, it may be enabled as a result of the update. This is bad manners, but it can happen, so be sure to run netstat or comparable to verify your system is where you want it after any updates or system changes. In fact, do it periodically even if there are no such changes.


5. Step 3: Firewalls and Setting Access Policies

So what is a "firewall"? It's a vague term that can mean anything that acts as a protective barrier between us and the outside world. This can be a dedicated system, or a specific application that provides this functionality. Or it can be a combination of components, including various combinations of hardware and software. Firewalls are built from "rules" that are used to define what is allowed to enter and exit a given system or network. Let's look at some of the possible components that are readily available for Linux, and how we might implement a reasonably safe firewalling strategy.

In Step 1 above, we have turned off all services we don't need. In our example, there were a few we still needed to have running. In this section, we will take the next step here and decide which we need to leave open to the world. And which we might be able to restrict in some way. If we can block them all, so much the better, but this is not always practical.


5.2. Packet Filters -- Ipchains and Iptables

"Packet filters" (like ipchains) have the ability to look at individual packets, and make decisions based on what they find. These can be used for many purposes. One common purpose is to implement a firewall.

Common packet filters on Linux are ipchains which is standard with 2.2 kernels, and iptables which is available with the more recent 2.4 kernels. iptables has more advanced packet filtering capabilities and is recommended for anyone running a 2.4 kernel. But either can be effective for our purposes. ipfwadm is a similar utility for 2.0 kernels (not discussed here).

If constructing your own ipchains or iptables firewall rules seems a bit daunting, there are various sites that can automate the process. See the Links section. Also the included examples may be used as a starting point. And your distribution may be including a utility of some kind for generating a firewall script. This may be adequate, but it is still recommended to know the proper syntax and how the various mechanisms work as such tools rarely do more than a few very simple rules.

Note

Various examples are given below. These are presented for illustrative purposes to demonstrate some of the concepts being discussed here. While they might also be useful as a starting point for your own script, please note that they are not meant to be all encompassing. You are strongly encouraged to understand how the scripts work, so you can create something even more tailored for your own situation.

The example scripts are just protecting inbound connections to one interface (the one connected to the Internet). This may be adequate for many simple home type situations, but, conversely, this approach is not adequate for all situations!


5.2.1. ipchains

ipchains can be used with either 2.2 or 2.4 kernels. When ipchains is in place, it checks every packet that moves through the system. The packets move across different "chains", depending where they originate and where they are going. Think of "chains" as rule sets. In advanced configurations, we could define our own custom chains. The three default built-in chains are input, which is incoming traffic, output, which is outgoing traffic, and forward, which is traffic being forwarded from one interface to another (typically used for "masquerading"). Chains can be manipulated in various ways to control the flow of traffic in and out of our system. Rules can be added at our discretion to achieve the desired result.

At the end of every "chain" is a "target". The target is specified with the -j option to the command. The target is what decides the fate of the packet and essentially terminates that particular chain. The most common targets are mostly self-explanatory: ACCEPT, DENY, REJECT, and MASQ. MASQ is for "ipmasquerading". DENY and REJECT essentially do the same thing, though in different ways. Is one better than the other? That is the subject of much debate, and depends on other factors that are beyond the scope of this document. For our purposes, either should suffice.

ipchains has a very flexible configuration. Port (or port ranges), interfaces, destination address, source address can be specified, as well as various other options. The man page explains these details well enough that we won't get into specifics here.

Traffic entering our system from the Internet, enters via the input chain. This is the one that we need as tight as we can make it.

Below is a brief example script for a hypothetical system. We'll let the comments explain what this script does. Anything starting with a "#" is a comment. ipchains rules are generally incorporated into shell scripts, using shell variables to help implement the firewalling logic.


#!/bin/sh
#
# ipchains.sh
#
# An example of a simple ipchains configuration. 
#
# This script allows ALL outbound traffic, and denies 
# ALL inbound connection attempts from the outside.
#
###################################################################
# Begin variable declarations and user configuration options ######
#
IPCHAINS=/sbin/ipchains
# This is the WAN interface, that is our link to the outside world.
# For pppd and pppoe users.
# WAN_IFACE="ppp0"
WAN_IFACE="eth0"

## end user configuration options #################################
###################################################################

# The high ports used mostly for connections we initiate and return
# traffic.
LOCAL_PORTS=`cat /proc/sys/net/ipv4/ip_local_port_range |cut -f1`:\
`cat /proc/sys/net/ipv4/ip_local_port_range |cut -f2`

# Any and all addresses from anywhere.
ANYWHERE="0/0"

# Let's start clean and flush all chains to an empty state.
$IPCHAINS -F  

# Set the default policies of the built-in chains. If no match for any 
# of the rules below, these will be the defaults that ipchains uses.
$IPCHAINS -P forward DENY
$IPCHAINS -P output ACCEPT
$IPCHAINS -P input DENY 

# Accept localhost/loopback traffic.
$IPCHAINS -A input -i lo -j ACCEPT

# Get our dynamic IP now from the Inet interface. WAN_IP will be our
# IP address we are protecting from the outside world. Put this
# here, so default policy gets set, even if interface is not up
# yet.
WAN_IP=`ifconfig $WAN_IFACE |grep inet |cut -d : -f 2 |cut -d \  -f 1`

# Bail out with error message if no IP available! Default policy is 
# already set, so all is not lost here.
[ -z "$WAN_IP" ] && echo "$WAN_IFACE not configured, aborting." && exit 1

# Accept non-SYN TCP, and UDP connections to LOCAL_PORTS. These are
# the high, unprivileged ports (1024 to 4999 by default). This will
# allow return connection traffic for connections that we initiate
# to outside sources. TCP connections are opened with 'SYN' packets.
$IPCHAINS -A input -p tcp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS ! -y -j ACCEPT 

# We can't be so selective with UDP since that protocol does not
# know about SYNs.
$IPCHAINS -A input -p udp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS -j ACCEPT 

## ICMP (ping)
#
# ICMP rules, allow the bare essential types of ICMP only. Ping
# request is blocked, ie we won't respond to someone else's pings,
# but can still ping out. 
$IPCHAINS -A input  -p icmp  --icmp-type echo-reply \
   -s $ANYWHERE -i $WAN_IFACE -j ACCEPT
$IPCHAINS -A input  -p icmp  --icmp-type destination-unreachable \
   -s $ANYWHERE -i $WAN_IFACE -j ACCEPT
$IPCHAINS -A input  -p icmp  --icmp-type time-exceeded \
   -s $ANYWHERE -i $WAN_IFACE -j ACCEPT

###################################################################
# Set the catchall, default rule to DENY, and log it all. All other
# traffic not allowed by the rules above, winds up here, where it is
# blocked and logged. This is the default policy for this chain
# anyway, so we are just adding the logging ability here with '-l'.
# Outgoing traffic is allowed as the default policy for the 'output'
# chain. There are no restrictions on that.

$IPCHAINS -A input -l -j DENY

echo "Ipchains firewall is up `date`."

##-- eof ipchains.sh

 

To use the above script would require that it is executable (i.e. chmod +x ipchains.sh), and run by root to build the chains, and hence the firewall.

To summarize what this example did was to start by setting some shell variables in the top section, to be used later in the script. Then we set the default rules (ipchains calls these "policies") of denying all inbound and forwarded traffic, and of allowing all our own outbound traffic. We had to open some holes in the high, unprivileged ports so that we could have return traffic from connections that bigcat initiates to outside addresses. If we connect to someone's web server, we want that HTML data to be able to get back to us, for instance. The same applies to other network traffic. We then allowed a few specific types of the ICMP protocol (most are still blocked). We are also logging any inbound traffic that violates any of our rules so we know who is doing what. Notice that we are only using IP address here, not hostnames of any kind. This is so that our firewall works, even in situation where there may be DNS failures. Also, to prevent any kind of DNS spoofing.

See the ipchains man page for a full explanation of syntax. The important ones we used here are:

 -A input: Adds a rule to the "input" chain. The default chains are input, output, and forward.

 -p udp: This rule only applies to the "UDP" "protocol". The -p option can be used with tcp, udp or icmp protocols.

 -i $WAN_IFACE: This rule applies to the specified interface only, and applies to whatever chain is referenced (input, output, or forward).

 -s <IP address> [port]: This rule only applies to the source address as specified. It can optionally have a port (e.g. 22) immediately afterward, or port range, e.g. 1023:4999.

 -d <IP address> [port]: This rule only applies to the destination address as specified. Also, it may include port or port range.

 -l : Any packet that hits a rule with this option is logged (lower case "L").

 -j ACCEPT: Jumps to the "ACCEPT" "target". This effectively terminates this chain and decides the ultimate fate for this particular packet, which in this example is to "ACCEPT" it. The same is true for other -j targets like DENY.

By and large, the order in which command line options are specified is not significant. The chain name (e.g. input) must come first though.

Remember in Step 1 when we ran netstat, we had both X and print servers running among other things. We don't want these exposed to the Internet, even in a limited way. These are still happily running on bigcat, but are now safe and sound behind our ipchains based firewall. You probably have other services that fall in this category as well.

The above example is a simplistic all or none approach. We allow all our own outbound traffic (not necessarily a good idea), and block all inbound connection attempts from outside. It is only protecting one interface, and really just the inbound side of that interface. It would more than likely require a bit of fine tuning to make it work for you. For a more advanced set of rules, see the Appendix. And you might want to read http://tldp.org/HOWTO/IPCHAINS-HOWTO.html.

Whenever you have made changes to your firewall, you should verify its integrity. One step to make sure your rules seem to be doing what you intended, is to see how ipchains has interpreted your script. You can do this by opening your xterm very wide, and issuing the following command:


 # ipchains -L -n -v | less

 

The output is grouped according to chain. You should also find a way to scan yourself (see the Verifying section below). And then keep an eye on your logs to make sure you are blocking what is intended.


5.2.2. iptables

iptables is the next generation packet filter for Linux, and requires a 2.4 kernel. It can do everything ipchains can, but has a number of noteworthy enhancements. The syntax is similar to ipchains in many respects. See the man page for details.

The most noteworthy enhancement is "connection tracking", also known as "stateful inspection". This gives iptables more knowledge of the state of each packet. Not only does it know if the packet is a TCP or UDP packet, or whether it has the SYN or ACK flags set, but also if it is part of an existing connection, or related somehow to an existing connection. The implications for firewalling should be obvious.

The bottom line is that it is easier to get a tight firewall with iptables, than with ipchains. So this is the recommended way to go.

Here is the same script as above, revised for iptables:


#!/bin/sh
#
# iptables.sh
#
# An example of a simple iptables configuration. 
#
# This script allows ALL outbound traffic, and denies 
# ALL inbound connection attempts from the Internet interface only.
#
###################################################################
# Begin variable declarations and user configuration options ######
#
IPTABLES=/sbin/iptables
# Local Interfaces
# This is the WAN interface that is our link to the outside world.
# For pppd and pppoe users.
# WAN_IFACE="ppp0"
WAN_IFACE="eth0"
#

## end user configuration options #################################
###################################################################

# Any and all addresses from anywhere.
ANYWHERE="0/0"

# This module may need to be loaded:
modprobe ip_conntrack_ftp

# Start building chains and rules #################################
#
# Let's start clean and flush all chains to an empty state.
$IPTABLES -F  

# Set the default policies of the built-in chains. If no match for any 
# of the rules below, these will be the defaults that IPTABLES uses.
$IPTABLES -P FORWARD DROP
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P INPUT DROP

# Accept localhost/loopback traffic.
$IPTABLES -A INPUT -i lo -j ACCEPT

## ICMP (ping)
#
# ICMP rules, allow the bare essential types of ICMP only. Ping
# request is blocked, ie we won't respond to someone else's pings,
# but can still ping out.
$IPTABLES -A INPUT  -p icmp  --icmp-type echo-reply \
   -s $ANYWHERE -i $WAN_IFACE -j ACCEPT
$IPTABLES -A INPUT  -p icmp  --icmp-type destination-unreachable \
   -s $ANYWHERE -i $WAN_IFACE -j ACCEPT
$IPTABLES -A INPUT  -p icmp  --icmp-type time-exceeded \
   -s $ANYWHERE -i $WAN_IFACE -j ACCEPT

###################################################################
# Set the catchall, default rule to DENY, and log it all. All other
# traffic not allowed by the rules above, winds up here, where it is
# blocked and logged. This is the default policy for this chain
# anyway, so we are just adding the logging ability here with '-j
# LOG'. Outgoing traffic is allowed as the default policy for the
# 'output' chain. There are no restrictions on that.

$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i ! $WAN_IFACE -j ACCEPT
$IPTABLES -A INPUT -j LOG -m limit --limit 30/minute --log-prefix "Dropping: "

echo "Iptables firewall is up `date`."

##-- eof iptables.sh

 

The same script logic is used here, and thus this does pretty much the same exact thing as the ipchains script in the previous section. There are some subtle differences as to syntax. Note the case difference in the chain names for one (e.g. INPUT vs input). Logging is handled differently too. It has its own "target" now (-j LOG), and is much more flexible.

There are some very fundamental differences as well, that might not be so obvious. Remember this section from the ipchains script:


# Accept non-SYN TCP, and UDP connections to LOCAL_PORTS. These are the high,
# unprivileged ports (1024 to 4999 by default). This will allow return
# connection traffic for connections that we initiate to outside sources.
# TCP connections are opened with 'SYN' packets. We have already opened 
# those services that need to accept SYNs for, so other SYNs are excluded here
# for everything else.
$IPCHAINS -A input -p tcp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS ! -y -j ACCEPT 

# We can't be so selective with UDP since that protocol does not know 
# about SYNs.
$IPCHAINS -A input -p udp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS -j ACCEPT 

 

We jumped through hoops here with ipchains so that we could restrict unwanted, incoming connections as much as possible. A bit of a kludge, actually.

That section is missing from the iptables version. It is not needed as connection tracking handles this quite nicely, and then some. This is due to the "statefulness" of iptables. It knows more about each packet than ipchains. For instance, it knows whether the packet is part of a "new" connection, or an "established" connection, or a "related" connection. This is the so-called "stateful inspection" of connection tracking.

There are many, many features of iptables that are not touched on here. For more reading on the Netfilter project and iptables, see http://netfilter.samba.org. And for a more advanced set of rules, see the Appendix.


5.3. Tcpwrappers (libwrap)

Tcpwrappers provides much the same desired results as ipchains and iptables above, though works quite differently. Tcpwrappers actually intercepts the connection attempt, then examines its configurations files, and decides whether to accept or reject the request. Tcpwrappers controls access at the application level, rather than the socket level like iptables and ipchains. This can be quite effective, and is a standard component on most Linux systems.

Tcpwrappers consists of the configuration files /etc/hosts.allow and /etc/hosts.deny. The functionality is provided by the libwrap library.

Tcpwrappers first looks to see if access is permitted in /etc/hosts.allow, and if so, access is granted. If not in /etc/hosts.allow, the file /etc/hosts.deny is then checked to see if access is not allowed. If so, access is denied. Else, access is granted. For this reason, /etc/hosts.deny should contain only one uncommented line, and that is: ALL: ALL. Access should then be permitted through entries in /etc/hosts.allow, where specific services are listed, along with the specific host addresses allowed to access these services. While hostnames can be used here, use of hostnames opens the limited possibility for name spoofing.

Tcpwrappers is commonly used to protect services that are started via inetd (or xinetd). But also any program that has been compiled with libwrap support, can take advantage of it. Just don't assume that all programs have built in libwrap support -- they do not. In fact, most probably don't. So we will only use it in our examples here to protect services start via inetd. And then rely on our packet filtering firewall, or other mechanism, to protect non-(x)inetd services.

Below is a small snippet from a typical inetd.conf file:


 # Pop and imap mail services et al
 #
 #pop-2   stream  tcp     nowait  root    /usr/sbin/tcpd ipop2d
 #pop-3   stream  tcp     nowait  root    /usr/sbin/tcpd ipop3d
 #imap    stream  tcp     nowait  root    /usr/sbin/tcpd imapd
 #

 

The second to last column is the tcpwrappers daemon -- /usr/sbin/tcpd. Immediately after is the daemon it is protecting. In this case, POP and IMAP mail servers. Your distro probably has already done this part for you. For the few applications that have built-in support for tcpwrappers via the libwrap library, specifying the daemon as above is not necessary.

We will use the same principles here: default policy is to deny everything, then open holes to allow the minimal amount of traffic necessary.

So now with your text editor, su to root and open /etc/hosts.deny. If it does not exist, then create it. It is just a plain text file. We want the following line:


 ALL: ALL

 

If it is there already, fine. If not, add it in and then save and close file. Easy enough. "ALL" is one of the keywords that tcpwrappers understands. The format is $SERVICE_NAME : $WHO, so we are denying all connections to all services here. At least all services that are using tcpwrappers. Remember, this will primarily be inetd services. See man 5 hosts_access for details on the syntax of these files. Note the "5" there!

Now let's open up just the services we need, as restrictively as we can, with a brief example:


 ALL: 127.0.0.1
 sshd,ipop3d: 192.168.1.
 sshd: .myworkplace.com, hostess.mymomshouse.com 

 

The first line allows all "localhost" connections. You will need this. The second allows connections to the sshd and ipop3d services from IP addresses that start with 192.168.1., in this case the private address range for our hypothetical home LAN. Note the trailing ".". It's important. The third line allows connections to only our sshd daemon from any host associated with .myworkplace.com. Note the leading "." in this example. And then also, the single host hostess.mymomshouse.com. In summary, localhost and all our LAN connections have access to any and all tcpwrappered services on bigcat. But only our workplace addresses, and our mother can use sshd on bigcat from outside connections. Everybody else is denied by the default policy in /etc/hosts.deny.

The types of wild cards above (.myworkplace.com and 192.168.1.) are not supported by ipchains and iptables, or most other Linux applications for that matter. Also, tcpwrappers can use hostnames in place of IP addresses which is quite handy in some situations. This does not work with ipchains and iptables.

You can test your tcpwrappers configuration with the included tcpdchk utility (see the man page). Note that at this time this does not work with xinetd, and may not even be included in this case.

There is nothing wrong with using both tcpwrappers and a packet filtering firewall like ipchains. In fact, it is recommended to use a "layered" approach. This helps guard against accidental misconfigurations. In this case, each connection will be tested by the packet filter rules first, then tcpwrappers.

Remember to make backup copies before editing system configuration files, restart the daemon afterward, and then check the logs for error messages.


5.3.1. xinetd

As mentioned, xinetd is an enhanced inetd . It has much of the same functionality, with some notable enhancements. One is that tcpwrappers support can be compiled in, eliminating the need for explicit references to tcpd. Which means /etc/hosts.allow and /etc/hosts.deny are automatically in effect. Don't assume this is the case though. A little testing, then viewing the logs should be able to tell you whether tcpwrappers support is automatic or not.

Some of xinetd's other enhancements: specify IP address to listen on, which is a very effective method of access control; limit the rate of incoming connections and the total number of simultaneous connections; limit services to specific times of day. See the xinetd and xinetd.conf man pages for more details.

The syntax is quite different though. An example from /etc/xinetd.d/tftp:


 service tftp
 {
        socket_type     = dgram
        bind            = 192.168.1.1
        instances       = 2
        protocol        = udp
        wait            = yes
        user            = nobody
        only_from       = 192.168.1.0
        server          = /usr/sbin/in.tftpd
        server_args     = /tftpboot
        disable         = no
 }

 

Notice the bind statement. We are only listening on, or "binding" to, the private, LAN interface here. No outside connections can be made since the outside port is not even opened. We are also only accepting connections from 192.168.1.0, our LAN. For xinetd's purposes, this denotes any IP address beginning with "192.168.1". Note that the syntax is different from inetd. The server statement in this case is the tftp daemon, in.tftpd. Again, this assumes that libwrap/tcpwrappers support is compiled into xinetd. The user running the daemon will be "nobody". Yes, there is a user account called "nobody", and it is wise to run such daemons as non-root users whenever possible. Lastly, the disable statement is xinetd's way of turning services on or off. In this case, it is "on". This is on here only as an example. Do NOT run tftp as a public service as it is unsafe.


5.4. PortSentry

Portsentry works quite differently than the other tools discussed so far. Portsentry does what its name implies -- it guards ports. Portsentry is configured with the /etc/portsentry/portsentry.conf file.

Unlike the other applications discussed above, it does this by actually becoming the listening server on those ports. Kind of like baiting a trap. Running netstat -taup as root while portsentry is running, will show portsentry as the LISTENER on whatever ports portsentry is configured for. If portsentry senses a connection attempt, it blocks it completely. And then goes a step further and blocks the route to that host to stop all further traffic. Alternately, ipchains or iptables can be used to block the host completely. So it makes an excellent tool to stop port scanning of a range of ports.

But portsentry has limited flexibility as to whether it allows a given connection. It is pretty much all or nothing. You can define specific IP addresses that it will ignore in /etc/portsentry/portsentry.ignore. But you cannot allow selective access to individual ports. This is because only one server can bind to a particular port at the same time, and in this case that is portsentry itself. So it has limited usefulness as a stand-alone firewall. As part of an overall firewall strategy, yes, it can be quite useful. For most of us, it should not be our first line of defense, and we should only use it in conjunction with other tools.

Suggestion on when portsentry might be useful:

  • As a second layer of defense, behind either ipchains or iptables. Packet filtering will catch the packets first, so that anything that gets to portsentry would indicate a misconfiguration. Do not use in conjunction with inetd services -- it won't work. They will butt heads.

  • As a way to catch full range ports scans. Open a pinhole or two in the packet filter, and let portsentry catch these and re-act accordingly.

  • If you are very sure you have no exposed public servers at all, and you just want to know who is up to what. But do not assume anything about what portsentry is protecting. By default it does not watch all ports, and may even leave some very commonly probed ports open. So make sure you configure it accordingly. And make sure you have tested and verified your set up first, and that nothing is exposed.

All in all, the packet filters make for a better firewall.


5.5. Proxies

The dictionary defines "proxy" as "the authority or power to act on behalf of another". This pretty well describes software proxies as well. It is an intermediary in the connection path. As an example, if we were using a web proxy like "squid" (http://www.squid-cache.org/), every time we browse to a web site, we would actually be connecting to our locally running squid server. Squid in turn, would relay our request to the ultimate, real destination. And then squid would relay the web pages back to us. It is a go-between. Like "firewalls", a "proxy" can refer to either a specific application, or a dedicated server which runs a proxy application.

Proxies can perform various duties, not all of which have much to do with security. But the fact that they are an intermediary, makes them a good place to enforce access control policies, limit direct connections through a firewall, and control how the network behind the proxy looks to the Internet. So this makes them strong candidates to be part of an overall firewall strategy. And, in fact, are sometimes used instead of packet filtering firewalls. Proxy based firewalls probably make more sense where many users are behind the same firewall. And it probably is not high on the list of components necessary for home based systems.

Configuring and administering proxies can be complex, and is beyond the scope of this document. The Firewall and Proxy Server HOWTO, http://tldp.org/HOWTO/Firewall-HOWTO.html, has examples of setting up proxy firewalls. Squid usage is discussed at http://squid-docs.sourceforge.net/latest/html/book1.htm


5.6. Individual Applications

Some servers may have their own access control features. You should check this for each server application you run. We'll only look at a few of the common ones in this section. Man pages, and other application specific documentation, is your friend here. This should be done whether you have confidence in your firewall or not. Again, layers of protection is always best.

As always, anytime you make system changes, backup the configuration file first, restart the appropriate daemon afterward, and then check the appropriate logs for error messages.


5.7. Verifying

The final step after getting your firewall in place, is to verify that it is doing what you intended. You would be wise to do this anytime you make even minor changes to your system configuration.

So how to do this? There are several things you can do.

For our packet filters like ipchains and iptables, we can list all our rules, chains, and associated activity with iptables -nvL | less (substitute ipchains if appropriate). Open your xterm as wide as possible to avoid wrapping long lines.

This should give you an idea if your chains are doing what you think they should. You may want to perform some of the on-line tasks you normally do first: open a few web pages, send and retrieve mail, etc. This will, of course, not give you any information on tcpwrappers or portsentry. tcpdchk can be used to verify tcpwrappers configuration (except with xinetd).

And then, scan yourself. nmap is the scanning tool of choice and may be available via your distribution , or from http://www.insecure.org/nmap/nmap_download.html. nmap is very flexible, and essentially is a "port prober". In other words, it looks for open ports, among other things. See the nmap man page for details.

If you do run nmap against yourself (e.g. nmap localhost), this should tell you what ports are open -- and visible locally only! Which hopefully by now, is quite different from what can be seen from the outside. So, scan yourself, and then find a trusted friend, or site (see the Links section), to scan you from the outside. Make sure you are not violating your ISPs Terms of Service by port scanning. It may not be allowed, even if the intentions are honorable. Scanning from outside is the best way to know how the rest of the world sees you. This should tell you how well that firewall is working. See the nmap section in the Appendix for some examples on nmap usage.

One caveat on this: some ISPs may filter some ports, and you will not know for sure how well your firewall is working. Conversely, they make it look like certain ports are open by using web, or other, proxies. The scanner may see the web proxy at port 80 and mis-report it as an open port on your system.

Another option is to find a website that offers full range testing. http://www.hackerwhacker.com is one such site. Make sure that any such site is not just scanning a relatively few well known ports.

Repeat this procedure with every firewall change, every system upgrade or new install, and when any key components of your system changes.

You may also want to enable logging all the denied traffic. At least temporarily. Once the firewall is verified to be doing what you think it should, and if the logs are hopelessly overwhelming, you may want to disable logging.

If relying on portsentry at all, please read the documentation. Depending on your configuration it will either drop the route to the scanner, or implement a ipchains/iptables rule doing the same thing. Also, since it "listens" on the specified ports, all those ports will show as "open". A false alarm in this case.


5.8. Logging

Linux does a lot of logging. Usually to more than one file. It is not always obvious what to make of all these entries -- good, bad or indifferent? Firewall logs tend to generate a fair amount of each. Of course, you are wanting to stop only the "bad", but you will undoubtedly catch some harmless traffic as well. The 'net has a lot of background noise.

In many cases, knowing the intentions of an incoming packet are almost impossible. Attempted intrusion? Misbehaved protocol? Mis-typed IP address? Conclusions can be drawn based on factors such as destination port, source port, protocol, and many other variables. But there is no substitute for experience in interpreting firewall logs. It is a black art in many cases.

So do we really need to log? And how much should we be trying to log? Logging is good in that it tells us that the firewall is functional. Even if we don't understand much of it, we know it is doing "something". And if we have to, we can dig into those logs and find whatever data might be called for.

On the other hand, logging can be bad if it is so excessive, it is difficult to find pertinent data, or worse, fills up a partition. Or if we over re-act and take every last entry as an all out assault. Some perspective is a great benefit, but something that new users lack almost by definition. Again, once your firewall is verified, and you are perplexed or overwhelmed, home desktop users may want to disable as much logging as possible. Anyone with greater responsibilities should log, and then find ways to extract the pertinent data from the logs by filtering out extraneous information.

Not sure where to look for log data? This could conceivably be many places depending on how your distribution configured the various daemons and syslogd. Most logging is done in /var/log/*. Check that directory with ls -l /var/log/ and see if you can tell the most active logs by size and timestamp. Also, look at /etc/syslog.conf to see where the default logs are. /var/log/messages is a good place to look for starters.

Portsentry and tcpwrappers do a certain amount of logging that is not adjustable. xinetd has logging enhancements that can be turned on. Both ipchains and iptables, on the other hand, are very flexible as to what is logged.

For ipchains the -l option can be added to any rule. iptables uses the -j LOG target, and requires its own, separate rule instead. iptables goes a few steps further and allows customized log entries, and rate limiting. See the man page. Presumably, we are more interested in logging blocked traffic, so we'd confine logging to only our DENY and REJECT rules.

So whether you log, and how much you log, and what you do with the logs, is an individual decision, and probably will require some trial and error so that it is manageable. A few auditing and analytical tools can be quite helpful:

Some tools that will monitor your logs for you and notify you when necessary. These likely will require some configuration, and trial and error, to make the most out of them:


5.9. Where to Start

Let's take a quick look at where to run our firewall scripts from.

Portsentry can be run as an init process, like other system services. It is not so important when this is done. Tcpwrappers will be automatically be invoked by inetd or xinetd, so not to worry there either.

But the packet filtering scripts will have to be started somewhere. And many scripts will have logic that uses the local IP address. This will mean that the script must be started after the interface has come up and been assigned an IP address. Ideally, this should be immediately after the interface is up. So this depends on how you connect to the Internet. Also, for protocols like PPP or DHCP that may be dynamic, and get different IP's on each re-connect, it is best to have the scripts run by the appropriate daemon.

For PPP, you probably have an /etc/ppp/ip-up file. This will be executed every time there is a connect or re-connect. You should put the full path to your firewall script here. Check the local documentation for the correct location. Debian use files in /etc/ppp/ip-up.d/, so either put the script itself there, or a symlink to it. Red Hat uses /etc/ppp/ip-up.local for any user defined, local PPP configuration.

For DHCP, it depends on which client. dhcpcd will execute /etc/dhcpcd/dhcpcd-<interface>.exe (e.g. dhcpcd-eth0.exe) whenever a lease is obtained or renewed. So this is where to put a reference to your firewall script. For pump, the main configuration file is /etc/pump.conf. Pump will run whatever script is defined by the "script" statement any time there is a new or renewed lease:


 script /usr/local/bin/ipchains.sh

 

If you have a static IP address (i.e. it never changes), the placement is not so important and should be before the interface comes up!


5.10. Summary and Conclusions for Step 3

In this section we looked at various components that might be used to construct a "firewall". And learned that a firewall is as much a strategy and combination of components, as it is any one particular application or component. We looked at a few of the most commonly available applications that can be found on most, if not all, Linux systems. This is not a definitive list.

This is a lot of information to digest at all at one time and expect anyone to understand it all. Hopefully this can used as a starting point, and used for future reference as well. The packet filter firewall examples can be used as starting points as well. Just use your text editor, cut and paste into a file with an appropriate name, and then run chmod +x against it to make it executable. Some minor editing of the variables may be necessary. Also look at the Links section for sites and utilities that can be used to generate a custom script. This may be a little less daunting.

Now we are done with Steps 1, 2 and 3. Hopefully by now you have already instituted some basic measures to protect your system(s) from the various and sundry threats that lurk on networks. If you haven't implemented any of the above steps yet, now is a good time to take a break, go back to the top, and have at it. The most important steps are the ones above.

A few quick conclusions...

"What is best iptables, ipchains, tcpwrappers, or portsentry?" The quick answer is that iptables can do more than any of the others. So if you are using a 2.4 kernel, use iptables. Then, ipchains if using a 2.2 kernel. The long answer is "it just depends on what you are doing and what the objective is". Sorry. The other tools all have some merit in any given situation, and all can be effective in the right situation.

"Do I really need all these packages?" No, but please combine more than one approach, and please follow all the above recommendations. iptables by itself is good, but in conjunction with some of the other approaches, we are even stronger. Do not rely on any single mechanism to provide a security blanket. "Layers" of protection is always best. As is sound administrative practices. The best iptables script in the world is but one piece of the puzzle, and should not be used to hide other system weaknesses.

"If I have a small home LAN, do I need to have a firewall on each computer?" No, not necessary as long as the LAN gateway has a properly configured firewall. Unwanted traffic should be stopped at that point. And as long as this is working as intended, there should be no unwanted traffic on the LAN. But, by the same token, doing this certainly does no harm. And on larger LANs that might be mixed platform, or with untrusted users, it would be advisable.


6. Intrusion Detection

This section will deal with how to get early warning, how to be alerted after the fact, and how to clean up from intrusion attempts.


6.1. Intrusion Detection Systems (IDS)

Intrusion Detection Systems (IDS for short) are designed to catch what might have gotten past the firewall. They can either be designed to catch an active break-in attempt in progress, or to detect a successful break-in after the fact. In the latter case, it is too late to prevent any damage, but at least we have early awareness of a problem. There are two basic types of IDS: those protecting networks, and those protecting individual hosts.

For host based IDS, this is done with utilities that monitor the filesystem for changes. System files that have changed in some way, but should not change -- unless we did it -- are a dead give away that something is amiss. Anyone who gets in, and gets root, will presumably make changes to the system somewhere. This is usually the very first thing done. Either so he can get back in through a backdoor, or to launch an attack against someone else. In which case, he has to change or add files to the system.

This is where tools like tripwire (http://www.tripwire.org) play a role. Such tools monitor various aspects of the filesystem, and compare them against a stored database. And can be configured to send an alert if any changes are detected. Such tools should only be installed on a known "clean" system.

For home desktops and home LANs, this is probably not an absolutely necessary component of an overall security strategy. But it does give peace of mind, and certainly does have its place. So as to priorities, make sure the Steps 1, 2 and 3 above are implemented and verified to be sound, before delving into this.

RPM users can get somewhat the same results with rpm -Va, which will verify all packages, but without all the same functionality. For instance, it will not notice new files added to most directories. Nor will it detect files that have had the extended attributes changed (e.g. chattr +i, man chattr and man lsattr). For this to be helpful, it needs to be done after a clean install, and then each time any packages are upgraded or added. Example:

 
 # rpm -Va > /root/system.checked

 

Then we have a stored system snapshot that we can refer back to.

Debian users have a similar tool with debsums.

 
 # debsums -s > /root/system.checked

 

Another idea is to run chkrootkit (http://www.chkrootkit.org/) as a weekly cron job. This will detect common "rootkits".


6.2. Have I Been Hacked?

Maybe you are reading this because you've noticed something "odd" about your system, and are suspicious that someone was gotten in? This can be a clue.

The first thing an intruder typically does is install a "rootkit". There are many prepackaged rootkits available on the Internet. The rootkit is essentially a script, or set of scripts, that makes quick work of modifying the system so the intruder is in control, and he is well hidden. He does this by installing modified binaries of common system utilities and tampering with log files. Or by using special kernel modules that achieve similar results. So common commands like ls may be modified so as to not show where he has his files stored. Clever!

A well designed rootkit can be quite effective. Nothing on the system can really be trusted to provide accurate feedback. Nothing! But sometimes the modifications are not as smooth as intended and give hints that something is not right. Some things that might be warning signs: