...making Linux just a little more fun! |
By Vasoo Veerapen |
Introduction.
Automatic firewall hardening is a technique used by many commercial firewalls to prevent invalid packets from reaching protected networks. The objective of this document is to demonstrate how to harden iptables in real-time.
By default, iptables can log messages via the Linux syslogd daemon. Logs by themselves are fine for basic security but do not address advanced security issues. For advanced security a system needs to run custom scripts as soon as illegal operations are logged by the firewall. Depending on the severity of the violations, you can program these scripts to perform various actions such as blocking offending IP addresses. The techniques outlined in this document are not limited to iptables, and can also be modified to process output from any application which logs via syslog e.g. intrusion detection scanners such as SNORT.
The content in this document has been tested against Red Hat 7.2/7.3 only, but then, I live on the island of Mauritius which is a hell of a journey from civilisation, and all of us here are scantily clad Zulu warriors :-) For more info about Mauritius and scuba diving try www.islandsoft.net
An excellent document on the Linux firewall capabilites is the Iptables Tutorial by Oskar Andreasson which you can find at http://iptables-tutorial.haringstad.com/
Linux Reference Books.
Here are some Linux books which you may find interesting. Please open each link in a new window.
Advanced
Linux Networking
Hack
Attacks Revealed: A Complete Reference
Hacking
Linux Exposed
Linux
Firewalls (2nd Edition)
Linux
Routers
Network
Intrusion Detection (An Analysts Handbook, 2nd Edition)
PHP
and PostgreSQL Advanced Web Programming
Real
World Linux Security: Intrusion Prevention, Detection and
Recovery
Red
Hat Linux 7.3 Bible
The Theory.
Linux syslogd incorporates an interesting feature which allows it to redirect its output to user defined pipes instead of log files. I will use a Perl script to process messages coming from syslogd and dynamically reconfigure iptables.
What You Will Need.
The examples in this document use a postgresql server. Most people are familiar with MySQL ,so porting should not be a problem. I prefer Postgres because it has many features present in commercial databases. For more information about PostgreSQL visit http://www.postgresql.org/. You will also need the postgresql-perl, Perl and iptables packages installed on the firewall machine.
On the postgreSQL server create a database called "adaptive" and a table called "iptables". Add the folowing fields.
Basic Security.
TO DO: More detail on MAC addressses and ARP poisoning.
In my opinion, the only services, which should be running on a firewall, are syslog and cron. You should also have a printer logging whatever gets sent to syslog. The reason for having a printer is that if your machine does get hacked, and the cracker overwrites the logs, you will still be able to see how the exploit was performed. Your firewall should also preferably be running off a CD-ROM and loading its ruleset from a write protected floppy disk.
Knowing the MAC addresses present on your network is very important. The firewall must be aware of any rogue MAC addresses, which may be originating from a machine which, may have been unlawfully introduced into your network.
Locking Down The Firewall During The Boot Process.
The first step that you will want to take is to secure your firewall while it is booting. By default, iptables allows unrestricted packet movement on the INPUT, OUTPUT and FORWARD chains. This poses a security threat while your machine is booting, and opens up your network to various types of assault. To avoid this, you must instruct iptables to block all packet movement BEFORE the network interfaces start up.
On the Redhat distributions the link "S10network" found in "/etc/rc.d/rc3.d" is responsible for starting the network. You may also have "S08iptables" found in "/etc/rc.d/rc3.d". This link is responsible for initialising the firewall routines. I prefer to delete the default "S08iptables" link and create my own link starting with "S08". The link starting with "S08" gets executed before the one starting with "S10" thus ensuring that no packets get through.
There are various kernel options which you can set to enhance security. A few of them are set in the example below.
In order to secure the firewall during boot, do the following:
The rc.autofwinit script |
#!/bin/sh # # rc.autofwinit - Initialises firewall on boot # # Copyright (C) 2001,2002 Vasoo Veerapen ([email protected]); # http://www.islandsoft.net/veerapen.html # # This program is free software; you can distribute it and/or modify it under the terms of # the GNU General Public License as published by the Free Software Foundation; version 2 # of the License. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program # or from the site that you downloaded it from; if not, write to # the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA # # # Maybe you are more interested in scuba diving, marine conservation or my # homeland, the paradise island of Mauritius where the Dodo used to live? # Its simply http://www.islandsoft.net/ # # ---------------------------------------------------------------------- echo "Initialising firewalling...Dropping all packets" IPT=/sbin/iptables #Block ICMP redirects for CONF in /proc/sys/net/ipv4/conf/*/accept_redirects; do echo 0 > $CONF done # Block IP Source Routing for CONF in /proc/sys/net/ipv4/conf/*/accept_source_route; do echo 0 > $CONF done # Block IP spoofing for CONF in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $CONF done # Clear tables for TABLE in filter nat; do $IPT -t $TABLE F $IPT -t $TABLE X done # Drop all packets $IPT -P INPUT DROP $IPT -P OUTPUT DROP $IPT -P FORWARD DROP echo "Done initialising." sleep 2 |
Defining an Iptables Script.
Once the firewall boot process is secured you must create the firewall script which will log invalid packets to syslog. The iptables script presented below is very basic. If you wanted to be more adventurous, then you could use the DMZ script from the "Iptables Tutorial" found at http://iptables-tutorial.haringstad.com/ and enhance it.
The rc.autofwrules script |
#!/bin/sh # # rc.autofwrules - Firewall script for automatic firewall hardening # # Copyright (C) 2001,2002 Vasoo Veerapen ([email protected]) # http://www.islandsoft.net/veerapen.html # # This program is free software; you can distribute it and/or modify it under the terms of # the GNU General Public License as published by the Free Software Foundation; version 2 # of the License. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program # or from the site that you downloaded it from; if not, write to # the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA # # Maybe you are more interested in scuba diving, marine conservation or my # homeland, the paradise island of Mauritius where the Dodo used to live? # Its simply http://www.islandsoft.net/ # # ---------------------------------------------------------------------- IPT="/sbin/iptables" INT_IF="eth0" EXT_IF="ppp0" LOG_LEVEL="notice" # $IPT -P INPUT ACCEPT $IPT -P OUTPUT ACCEPT $IPT -P FORWARD ACCEPT #******************************************************************************* #FILTER_FLAGS #******************************************************************************* echo Entering FILTER_FLAGS $IPT -N FILTER_FLAGS $IPT -F FILTER_FLAGS ##----------------------------------------------------------------------------## $IPT -A FILTER_FLAGS -p tcp --tcp-flags ALL FIN -m limit \ --limit 5/minute -j LOG --log-level $LOG_LEVEL \ --log-prefix "iptables:SCAN:" $IPT -A FILTER_FLAGS -p tcp --tcp-flags ALL FIN -j DROP ##----------------------------------------------------------------------------## echo Leaving FILTER_FLAGS #******************************************************************************* # BANNED #******************************************************************************* echo Entering BANNED $IPT -N BANNED $IPT -F BANNED ##----------------------------------------------------------------------------## # Leave blank ##----------------------------------------------------------------------------## echo Leaving BANNED $IPT -A INPUT -j BANNED $IPT -A INPUT -j FILTER_FLAGS $IPT -A OUTPUT -j BANNED $IPT -A OUTPUT -j FILTER_FLAGS #------------- End firewall script |
Creating a Named Pipe.
The named pipe is the interface between syslog and the blocking script.
For more info, "man mknod" is your friend.
Setting Up a Blocking Script.
Once iptables and the named pipe are set up, it is time to create a script that will handle messages coming from the syslog daemon. The script is the core of the automatic hardening process. The example below demonstrates how to automatically lock out machines, and communicate with a database server running PostgreSQL.
The rc.autofwharden script |
#!/usr/bin/perl w # # rc.autofwharden - Processes messages from syslogd # # Copyright (C) 2001,2002 Vasoo Veerapen ([email protected]); # http://www.islandsoft.net/veerapen.html # # This program is free software; you can distribute it and/or modify it under the terms of # the GNU General Public License as published by the Free Software Foundation; version 2 # of the License. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program # or from the site that you downloaded it from; if not, write to # the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA # # # Maybe you are more interested in scuba diving, marine conservation or my # homeland, the paradise island of Mauritius where the Dodo used to live? # Its simply http://www.islandsoft.net/ # # ---------------------------------------------------------------------- use Pg; use strict; my $log_datetime=""; my $log_address=""; my @parms = (); my $msgSource = ""; my $sourceIP = ""; my $sourcefile = "dump"; my $tmprec = ""; my $conn=""; my $result=""; my $temp=""; #Open the database first $conn=Pg::connectdb("dbname=adaptive user=postgres password=password"); ( PGRES_CONNECTION_OK eq $conn->status ) and print "Pg::connectdb ok:\n" or die "Pg::connectdb failed: ", $conn->errorMessage, "\n"; #Open a named pipe #open(FIFO, "< /etc/rc.d/syslog_auth") or die $!; #printf "Pipe opened. \n"; #while(<FIFO>) { #Or maybe you want to open a test file instead of a pipe? open(SOURCE, "< $sourcefile") or die $!; printf "File opened. \n"; while (<SOURCE>) { @parms = split(/ /, $_); $msgSource = $parms[5]; if ($msgSource eq "iptables:SCAN:") { #Set date and time $log_datetime="$parms[1]-$parms[0]-2002 $parms[2]"; #Set source address $temp = $parms[9]; $log_address = substr($temp, 4, length($temp) -4); printf "Adding address %s to database. \n", $log_address; $result = $conn->exec("INSERT INTO iptables (ipaddress, severity, time) VALUES ('$log_address', '1','$log_datetime')"); die $conn->errorMessage unless PGRES_COMMAND_OK eq $result->resultStatus; $temp = "/sbin/iptables -A BANNED -s $log_address -j DROP"; printf "%s \n", $temp; system($temp); } } #close(FIFO); #Close the test file instead. close(SOURCE); $result=$conn->exec("DROP DATABASE adaptive"); die $conn->errorMessage unless PGRES_COMMAND_OK eq $result->resultStatus; #--------------- End of rc.autofwharden PERL Script; |
Configuring Syslogd.
The final step is to configure the syslog daemon. Normally, syslog echoes messages to a tty and the file "/var/log/messages". We will instruct syslog to echo messages to the named pipe instead.
Look for an entry starting
like
*.info;mail.none;authpriv.none
If you can't/can find the
line then add/change the line to look like
*.info;mail.none;authpriv.none |/etc/rc.d/syslog_auth
Viewing the Results.
From a remote system run nmap available from http://www.insecure.org/nmap with the Fin scan option.
On the firewall machine, run the command "/sbin/iptables -L" and note the difference in the "Banned" chain.
To view the firewall database, login as a postgresql user and type in
This should give you a list of all banned addresses added to the database.
Adaptive Firewall FAQ.
Q. How safe is the adaptive firewalling code in this document?
A. The hardening script in this tutorial is very basic. Since the script automatically bans machines, you can imagine what would happen if someone managed to spoof the source addresses. In this case, legitimate IP addresses would get blocked. However, during a legitimate attack, you could identify which domain was the most offending, and ban any machine attempting to connect from it.
Q. Why is my firewall continuously logging ACK, FIN, URGP=0 ?
A. In 99.99% cases this is normal behaviour. This is due to the connection state matching code in Iptables which by default tracks each connection for 60 seconds. Once a connection is inactive for 60 seconds, Iptables wipes it from its tracking table, but the server at the other end does not know that. When the server tries to close the connection from its end, it sends a packet with this TCP flag sequence which gets intercepted by the firewall.
Acknowledgments.
I would like to thank the following people for contributing towards this document.
Oskar Andreasson