Introduction to Security Basics
Table of Contents
- 1. Step 1: Eliminate Unneeded Programs
- 2. Step 2: SSH – The Secure Shell and so much more
- 2.1. What is SSH?
- 2.2. The Basics of How SSH works
- 2.3. How to Move Files
- 2.4. For More Information
- 3. Step 3: Logs
- 4. Step 4: Firewalls
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
tcp
tcp
tcp
tcp
udp
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
discard
#ircd
These entries describe the following services:
- 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. - (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:
- 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. - Write the message to a particular user’s terminal. This is typically
reserved for serious, immediate issues that need prompt attention - 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.
There 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.
# is something that shouldn't happen very often
iptables -A INPUT -m state --state INVALID -j LOG \
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.
# 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.
# everything.
echo 1
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 \
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.
# in is probably up to something (trying to use us to spoof) so
# log and drop those
iptables -N 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:
# 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 \
# -=-= 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 \
and then allow the packets through:
iptables -A INCOMING -p tcp --dport www -d 192.168.0.100 \
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.