Server based firewalling under Linux

by Harry Hoffman
Copyright (C) 2005

Whenever you run a public service on a computer there is always a chance that it may get compromised. If this happens then an attacker can start doing things like: attacking other systems, pulling down software to run on your system, copying off various config files, running a shell to connect to, etc.

What if you could ensure that even if your system was compromised that the attacker couldn't start up other processes to allow inbound connection and also would not be able to startup other outbound connections?

Would you feel a bit safer? I would (at least against your average script kiddie).

Here is how we are going to do it. The following assumes a redhat-like system but it easily adaptable:

The ruleset is defined as follows:

# Start by defining out default policies to drop everything
/sbin/iptables -P INPUT DROP
/sbin/iptables -P OUTPUT DROP
/sbin/iptables -P FORWARD DROP
# Make sure we can always talk on the loopback device
/sbin/iptables -A INPUT -i lo -j ACCEPT
/sbin/iptables -A OUTPUT -o lo -j ACCEPT
# Control what actually comes back into the host
/sbin/iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
/sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A INPUT -m state --state INVALID -j DROP
# For a webserver
/sbin/iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
# Log and block everything else
/sbin/iptables -A INPUT -m limit --limit 10/minute --limit-burst 5 -j LOG --log-level warn --log-prefix "INPUT "
/sbin/iptables -A INPUT -j DROP
# Now for stuff going back out
# Allow already established connections back in
/sbin/iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow root connections outbound
/sbin/iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 0 -j ACCEPT
# Allow certain icmp types out
/sbin/iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
# Allow DNS requests out (from any user)
/sbin/iptables -A OUTPUT -p udp -m udp --dst "yourdnsserver" --dport 53 -j ACCEPT
# Allow NTP out
/sbin/iptables -A OUTPUT -p udp -m udp --dst "yourntpserver" --dport 123 -j ACCEPT
# Log and block the rest
/sbin/iptables -A OUTPUT -m limit --limit 10/minute --limit-burst 5 -j LOG --log-level warn --log-prefix "OUTPUT "
/sbin/iptables -A OUTPUT -j DROP
# All done


After these commands are entered, and you're satisfied, you can use iptables-save to save them to a file so that you don't have to retype them each time. To get iptables to start on boot the following steps need to be performed (on Redhat based systems):

/sbin/iptables-save > /etc/sysconfig/iptables
chkconfig --level 2345 iptables on

Ok, so here is the cool bit. You can block all outgoing connections so that even if your webserver gets compromised only processes owned by the user root will be allowed to get through the host based firewall! (that's the rule with the --uid-owner flag)

If that doesn't excite you then I'm not quite sure what will! ;-P