Monday, November 30, 2009

Setting up a personal iptables firewall

Linux has many protections available, from account security to selinux to apparmor, but one of the most over looked protections available is iptables. iptables is a program for creating a firewall to do whatever you need, when a lot of people think of a firewall they think a machine sitting between their router and computer that stops access attempts and that is true, it is a firewall. However you can also have a firewall on just the local machine to protect you directly regardless of what other protections or lack-there-of are available on the network. A few simple rules and you can protect yourself from outside intrusion quite easily. You can do creative things like limit how many connects to a particular port you'll allow before denying that IP range connection, or deny establishment of connections from outside entirely. You can set it up to allow only the hosts you specify. It's a very versatile tool and I'm going to show you the basics of how to use it on your local machine to increase your security.

First lets start by making a simple iptables bash script we can execute. Change to the root user and create a basic script in your home directory called iptables.sh

#!/bin/bash
IPT=/sbin/iptables
ETH="eth0"

$IPT -F

$IPT -P INPUT DROP
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

$IPT -A OUTPUT DROP
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

$IPT -P FORWARD DROP

This is about the most basic set of protection you can make with iptables, when I say basic I don't mean it's weak protection, to the contrary this will deny almost all outside connections to you that weren't established by you previously. Lets review exactly what we're doing here. There are 4 basic sections relating to iptables:

This section flushes the current iptables so you're working from a blank slate:
$IPT -F

This section describes how to handle input to the machine from the network, the rules we define here-- we accept all local traffic and we accept traffic that has a state of established or related (eg: we initiated the traffic).
$IPT -P INPUT DROP
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

This section describes how to handle output from the machine to the network, the rules we define here-- we accept all local traffic and we accept any out bound traffic in the new, established, or related states which means that we can start new connections outward.
$IPT -A OUTPUT DROP
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

This section describes forwarding rules, for the most part unless you're the machine doing NAT/Masquerading you can ignore requests for forwarding, so we just drop all traffic since our script is meant to protect this individual machine.
$IPT -P FORWARD DROP

Now this is pretty basic and likely not exactly what you're looking for, it will prevent all connection originating from outside from going through at all. One thing you probably want to do is open up the ssh port so you can access your machine from outside, this is an easy process to do. We just add a line to the input section. What this line says is accept input on the destination port 22 which is the port ssh runs on.
$IPT -A INPUT -p tcp -m tcp --destination-port 22 -j ACCEPT

If you're running a web-server you may want to open up port 80 (http) and 443 (https).
$IPT -A INPUT -p tcp -m tcp --destination-port 80 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 443 -j ACCEPT

If you want to open up ftp for examine you need to open both port 20 (ftp) and 21 (ftp-data).
$IPT -A INPUT -p tcp -m tcp --destination-port 20 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 21 -j ACCEPT

So now we have a fairly complete personal protection script that allows ftp, ssh, and both http and https.
#!/bin/bash
IPT=/sbin/iptables
ETH="eth0"

$IPT -F

$IPT -P INPUT DROP
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 22 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 80 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 443 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 20 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 21 -j ACCEPT

$IPT -A OUTPUT DROP
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

$IPT -P FORWARD DROP

With your firewall setup like this one of the things you're going to note fairly quickly if you examine the logs is that there will be a lot of brute-force ssh attacks on your server, and if you have a good password they'll likely never break your password, however it's also not good to allow them to continually attack your server as it takes up resources to handle the incoming requests and it takes up bandwidth. So lets slow them down to a trickle and most will quickly move onto a better target. This is very easy to do, we simply add the following into our INPUT chain at the end. What this does is watches for NEW state connections on the input chain to the ssh port, it counts them and if it hits three from a single ip address in 6m it will drop that ip address. After it has been 6m without any activity from the specific ip address it will clear the dropped address (this prevents you from being locked out of your own server for more than 6m.)
$IPT -A INPUT -i $ETH -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 360 --hitcount 3 --name SSHATTEMPTS --rsource -j DROP
$IPT -A INPUT -i $ETH -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSHATTEMPTS --rsource

That brings us to a basic iptables setup for your local machine that looks like this--
#!/bin/bash
IPT=/sbin/iptables
ETH="eth0"

$IPT -F

$IPT -P INPUT DROP
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 22 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 80 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 443 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 20 -j ACCEPT
$IPT -A INPUT -p tcp -m tcp --destination-port 21 -j ACCEPT
$IPT -A INPUT -i $ETH -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 360 --hitcount 3 --name SSHATTEMPTS --rsource -j DROP
$IPT -A INPUT -i $ETH -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSHATTEMPTS --rsource

$IPT -A OUTPUT DROP
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

$IPT -P FORWARD DROP

You could move this script to /usr/local/sbin and call it from rc.local or you could add in the additional hooks required to call it from your distribution's /etc/init.d or you could just add the script itself to the rc.local. As long as it is called on start-up. This covers a basic introduction to using iptables for protection of your local machine with a minimum of inconvenience to yourself and maximized protection. If this isn't a machine that you're directly protecting but a firewall for the network you could setup dhcp on the machine and network address translation (NAT) and route specific ports to specific machines. The possibilities are endless and I hope this article opened your eyes to some of the potential that iptables has for securing your network. Good Luck

No comments:

Post a Comment