Navigation:

Search



Related Articles

Our Friends

Articles Introduction to Security Basics
 

Introduction to Security Basics

A four-step guide to securing a new Linux installation.

This was written by Sonny Rao, Josh Litherland and given on Thu Jan 24 2002.

Table of Contents


1. Step 1: Eliminate Unneeded Programs

Identify programs that are running, particularly those that are accepting connections from the network, and eliminate unneeded ones. To see a list of open services and what processes are providing them, use:

netstat -tulp

Sample output:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address      Foreign Address State  PID/Program
tcp        0      0 mummu.localnet:ssh *:*             LISTEN 7142/sshd
tcp        0      0 *:time             *:*             LISTEN 157/inetd
tcp        0      0 *:daytime          *:*             LISTEN 157/inetd
tcp        0      0 *:discard          *:*             LISTEN 157/inetd
udp        0      0 *:discard          *:*                    157/inetd

Most of these fields are self-explanitory. The 'Local Address' field displays what port and IP address the service is listening on; an IP of 0.0.0.0 means that the service is listening on all valid IPs for this machine. The last field identifies the process ID and name of the process that has this service open. (note: only root will be able to see this information). If you want to see the numeric IP addresses and port numbers, add 'n' to the list of arguments to netstat. The complete listing of services that netstat uses to apply these names is in /etc/services.

Notice that the process named 'inetd' is providing numerous services. inetd, and its successor xinetd, are called 'superservers'. Their role is to listen on numerous ports on behalf of a variety of simple services, set in /etc/inetd.conf and /etc/xinetd.conf respectively. When a connection comes in on one of these ports, (x)inetd will fire up the appropriate server and hand off the connection to it, and in most cases the server will handle that one connection and then quit.

Sample inetd.conf entries:

discard     stream  tcp nowait  root    internal
discard     dgram   udp wait    root    internal
#ircd       stream  tcp wait    root    /usr/local/sbin/ircd ircd -i

These entries describe the following services:

  1. listen on the discard tcp AND udp ports (found by looking in /etc/services). When a connection comes in, use the internal handler (built into inetd) for this protocol.
  2. (commented out - inactive) listen on the ircd tcp port. When a connection comes in, run /usr/local/sbin/ircd -i, with the privileges of the user 'root'

The xinetd config file works in a similar way, but allows slightly more flexibility in the specification of the service.

Both inetd and xinetd utilize 'tcp wrappers', a very rudimentary but useful security tool written for Linux by Wietse Venema. This system uses information in the files /etc/hosts.allow and /etc/hosts.deny to allow or block services to clients based solely on IP address (this system is weak since IP addresses can easily be spoofed, but it can defeat unsophisticated attacks). Newer versions of tcp wrappers have a semi-complex grammar with which to express who is allowed to connect to what services, so read

man hosts_access

to learn how to configure these filters.

You probably have a service called 'portmap' running on your system. This is an extremely simple service that is a sort of registry server for programs that use Sun's RPC (remote procedure calling) network interface. The most common end-user services that need portmap/RPC to be running are NFS and NIS, which are a networked filesystem and a networked login system, respectively. If you are using neither of these (odds are you aren't, and if you want to run a secure system, you should probably not be anyway) then you can safely disable portmap.

Another port that is commonly open that does not need to be is the X-window server. This will be a tcp port in the range of 6000+. It is only needed if you run X processes on remote machine that display to the local machine, and this is better done with SSH port forwarding anyway. More commonly, it gives an attacker an easy way of snooping on what you are doing in X, including keystroke logging, or popping up random windows on your desktop. If you decide you don't need this port to be open, add the option

'-nolisten tcp'

to your X-server startup params. If you use startx to fire up your X desktop, this will be located in

/etc/X11/xinit/xserverrc

If you use one of the graphical login managers (xdm, gdm, or kdm are most common), then the parameters will be found in the config files for whichever one you use, probably under /etc/X11 somewhere. If you decide you DO need to have remote X capability, then learn to use the xhost command to set who can connect to your server by IP-only authentication. For local users sharing an X-server (like when you startx as your normal user but then su to root.) it's better to copy the .Xauthority token out of the user's home directory who owns the server, into the home of whomever needs access to the server.

2. Step 2: SSH - The Secure Shell and so much more
2.1. What is SSH?

SSH is a flexible set of protocols for encrypting interactive and bulk traffic between two hosts. SSH is the preferred interactive login utility on Linux and UNIX systems. Its predecessor, telnet, is shunned because it sends passwords over the network in plaintext. So, anyone who sees the traffic between you and your destination system can easily grab your passwords and watch everything you do.

Typically, one of the first steps in securing a Linux system is to diable telnet access and enable SSH access. In modern Linux distributions this may be done for you. Also, the ssh server is not typically run under inetd, although that is certainly possible. See previous sections for information on integration into a secure system.

The preferred software for ssh and its associated sever, "sshd", is called OpenSSH. It is developed by the OpenBSD group and is ported to many other UNIX variants including Linux. OpenSSH currently supports all of the features supported in the SSH1 and SSH2 protocols including, secure port forwarding, X Window server proxying, and ssh-key fowarding and authentication to name a few.

2.2. The Basics of How SSH works

SSH uses two forms of encryption through the lifetime of a connection, symmetric to encrypt the traffic, and asymmetric to exchange the symmetric keys. When one sees messages about "host keys" this is referring to the permanent (asymmetric) public and private keys. These should not change for any given host. I'll spare you the details on how this works, but just know that in order to talk to a ssh server, you must have it's public (host) key. Usually, ssh will ask you if you trust a new host key when you first try to connect. It is referring to the host public key in either RSA or DSA key format.

When one connects to a new server, the server's public key must then be transmitted to you. This is where ssh is most vulnerable to outside attack since you are assuming that you are talking to the correct machine the first time. If this assumption is not correct, then someone else has conducted what is called a "man-in-the-middle" attack, where they sent you their public key instead of the server you wanted to communicate with and can from there possiblly obtain your password and monitor your session. This is why it is important to keep your host keys safe and verify public keys when you first connect to a new server.

Also, I must note that SSH protocol 2 is far more resistant to potential attacks than SSH protocol 1 and should alway be used. In OpenSSH the "-2" switch will force version two, also you may edit your configuration files to make it default.

2.3. How to Move Files

Probably the second most used feature in SSH is secure copy or "scp" for short. You can use scp to move files between two hosts and have the transfer be encrypted. The syntax of the command is as follows:

(case 1, moving a local file to a remote computer)

scp /tmp/local_file sonny@acme.gatech.edu:/home/gte000/

Notice the user@hostname:path format in the second argument this tells scp what machine to connect to, what user to authenticate, and where to put the destination file.

(case 2, moving a remote file to the local machine)

scp sonny@moefo.net:/home/sonny/blarg /tmp

The syntax is very similar to the first case, use the same format for the remote machine.

2.4. For More Information

For more detailed information on SSH see Moshe Jacobson's presentation at the LUG website.

http://www.lugatgt.org/articles/using_ssh/

of course "man ssh"

3. Step 3: Logs

Linux has a very flexible, simple system for handling system event logs. The process 'syslogd' collects messages from all other processes on the system, usually through the special file /dev/log, and decides how to handle them based on the configuration in /etc/syslog.conf. Syslogd's companion program, klogd, snarfs up messages that are printed out by the kernel and feeds them to syslogd.

There are two values that syslogd uses to determine how to handle a particular message: that message's "priority" and "facility". The facility of a message specifies what type of event it is reporting; for instance, kern is the facility of all messages from the kernel, mail from the mail system, lpr for the printing system and so on. The priority of a message is a relative measure of how severe the message is, ranging from 'debug' for relatively trivial messages to 'panic' for serious problems. Common handling of these messages is to do one or more of the following:

  1. Write the message to a file in /var/log. /var/log/messages is a popular place to stuff the bulk of messages an admin will typically want to see, /var/log/syslog is also a likely place to look.
  2. Write the message to a particular user's terminal. This is typically reserved for serious, immediate issues that need prompt attention
  3. Send the events to a syslogd running on another machine. This allows very easy centralized log-reading for large numbers of machines. Unfortunately, the messages are not encrypted with the normal Linux syslogd, so this is inadequate for the paranoid among us. SmileThere are add-on syslogd replacements that provide this feature.

It is also trivial to pipe the text of the message to another program for handling; a common use is to email critical messages to the admin or even to send the text to a pager.

man syslog.conf

for information on how to tune all this.

4. Step 4: Firewalls

A firewall is a list of rules that determine what packets are and are not allowed to enter, leave, or pass through your system. In Linux, the firewall system to use is called 'iptables'. iptables divides packets into INPUT (those coming from the outside into your system), OUTPUT (those coming from your system bound for the outside), and FORWARD (those passing through your system, using it as a router) chains, and each chain has its own set of rules. If you have NAT (network address translation) support in your kernel, then you also have chains called PREROUTING and POSTROUTING, which are the first to affect any packets coming into your system, and the last to affect any going out, respectively. One of the big improvements of iptables over its predecessor, ipchains, is 'statefulness'. That means that it logically groups all packets into 'sessions', so you don't have to worry about allowing response packets going in the opposite direction if you have already allowed the beginning of the session, for instance. All you have to do is specify what types of sessions you want to be allowed through. (technically, iptables marks each packet as either NEW, ESTABLISHED, RELATED, or INVALID depending on how it relates to preexisting sessions).

Without further ado, here are some examples of iptables scripts.

Basic firewall, allow anything going out, but nothing coming in:

#!/bin/bash

PATH=/usr/sbin

# These three lines flush all the old rules out
# of the iptables system, resetting it to its initial
# state.
iptables -F
iptables -X
iptables -Z

# These three lines set the default rule (or 'policy') to simply
# throw away any packets that aren't dealt with explicitly by
# another rule
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

# This line says to immediately accept any packets that are
# part of a preexisting session
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# These two lines log and drop anything that is trying to look
# like part of a session, but is invalid for some reason.  This
# is something that shouldn't happen very often

iptables -A INPUT -m state --state INVALID -j LOG \
                           --log-prefix "Invalid: "
iptables -A INPUT -m state --state INVALID -j DROP

# After this point, we don't waste time checking the state
# anymore, because the only state left is NEW.  And, since we
# want to allow nothing on the inbound...

iptables -A INPUT -j LOG --log-prefix "Input: "
iptables -A INPUT -j DROP

# We allow anything outgoing (we trust ourselves and our users,
# and aren't terribly worried about trojans/virii hijacking
# our systems.)

iptables -A OUTPUT -j ACCEPT

# We don't let anybody use us as a router (yet)

iptables -A FORWARD -j LOG --log-prefix "Forward: "
iptables -A FORWARD -j DROP

# -=-= END OF SCRIPT =-=-

Basic example of having a natted subnet (192.168.0.0/24) behind this machine which is the router:

#!/bin/bash

PATH=/usr/sbin:/bin

# We now need to specify the internal and external cards
EXT_CARD=eth0
INT_CARD=eth1
    
# All our internal machines will appear to the world to come from
# our one real IP, so we specify that as well
EXT_ADDR=128.121.10.11

# This is important, and a common source of errors; by default,
# Linux forwards nothing.  Flipping this bit makes it forward
# everything.  We refine below ;-)

echo 1 </proc/sys/net/ipv4/ip_forward

iptables -F
iptables -X
iptables -Z

# We'll be using the nat table, so clear it out too.
iptables -t nat -F
iptables -t nat -X
iptables -t nat -Z

iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state INVALID -j LOG \
                           --log-prefix "Invalid: "
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -j LOG --log-prefix "Input: "
iptables -A INPUT -j DROP

iptables -A OUTPUT -j ACCEPT
# We now need to split forwarded packets into incoming, and
# outgoing, based on what cards they are coming from and bound
# to.  Any packet that tries to go out the same card it came
# in is probably up to something (trying to use us to spoof) so
# log and drop those

iptables -N INCOMING  # Create a new chain named INCOMING
iptables -N OUTGOING
iptables -A FORWARD -i ${INT_CARD} -o ${EXT_CARD} -j OUTGOING
iptables -A FORWARD -i ${EXT_CARD} -o ${INT_CARD} -j INCOMING
# Split passing-through packets based on what cards they are
# coming from and going to.
iptables -A FORWARD -j LOG --log-prefix "Forward: "
iptables -A FORWARD -j DROP

iptables -A OUTGOING -j ACCEPT

iptables -A INCOMING -j LOG --log-prefix "Incoming: "
iptables -A INCOMING -j DROP

# This line's the clincher:  for anything that's leaving, use
# Source NAT to set the source IP address to our real IP, so
# that responses get back to us.

iptables -t nat -A POSTROUTING -o ${EXT_CARD} -j SNAT \
         --to-source ${EXT_ADDR}

# -=-= END OF SCRIPT =-=-

To allow incoming www requests to our real IP to go to the server running on an internal machine with the IP 192.168.0.100, first put a line in PREROUTING to change the packet's destination IP address before the FORWARD chain looks at it:

iptables -t nat -A PREROUTING -i ${EXT_CARD} -p tcp --dport www \
         -j DNAT --to 192.168.0.100

and then allow the packets through:

iptables -A INCOMING -p tcp --dport www -d 192.168.0.100 \
         -j ACCEPT

To fool port-scanners into thinking that we're not filtering at all, but just that there's nothing there, create a new chain called PISSOFF, and make any packets sent there that we don't like behave just as if there was no filtering taking place:

iptables -N PISSOFF
iptables -A PISSOFF -p tcp -j REJECT --reject-with tcp-reset
iptables -A PISSOFF -p udp -j REJECT
iptables -A PISSOFF -j DROP

Then jump to PISSOFF instead of just DROP whenever you want to get rid of a packet.