Dec 20 2009

Script for securing server with IPTables

Category: Articles,Linux administrationFractalizeR @ 7:31 pm


Here is a script, which I use on my production servers to secure them a bit. I hope it will be useful to you. Script logs all dropped packets so that you can easily find out tye clutch should there be any. Additional FTP server setup will be necessary. For ProFTPD add the following line to /etc/proftpd.conf:

PassivePorts 65400 65534

# FractalizeR's network and firewall configuration script
# This script has been collected line by line from many internet resources and improved
# by me. If you have something to say about it, please don't hesitate to contact me
# at
#Uncomment to turn debugging on.
set -x
#Comment to disable exit-on-error
set -e
#Checking if you are root
if [ `id -u` != 0 ]; then
 echo "You need to be root to setup iptables!"
 exit 1
#===================================== Kernel settings =======================================
# Disable response to ping.
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
# Disable response to broadcasts. You don't want yourself becoming a Smurf amplifier, right?
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Don't accept source routed packets. Attackers can use source routing to generate
# traffic pretending to be from inside your network, but which is routed back along
# the path from which it came, namely outside, so attackers can compromise your
# network. Source routing is rarely used for legitimate purposes.
echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route
# Disable ICMP redirect acceptance. ICMP redirects can be used to alter your routing
# tables, possibly to a bad end.
echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects
# Enable bad error message protection.
echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
# Log spoofed packets, source routed packets, redirect packets.
echo "1" > /proc/sys/net/ipv4/conf/all/log_martians
# Make sure that IP forwarding is turned off. We only want this for a multi-homed host.
echo "0" > /proc/sys/net/ipv4/ip_forward
#Enabling SYN-flood protection via SYN-cookies
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
#Disabling the acception of ICMP-redirect messages
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
#===================================== Initial firewall configuration ==========================
#This is the network interface for the internet
#This is for automatically find out the IP address for the internet network interface
FR_INET_IFACE_ADDR=`ifconfig $FR_INET_IFACE | grep inet | grep -v inet6 | cut -d ":" -f 2 | cut -d " " -f 1`
#Firewall binary name
#Limit this number of packets for logging purposes (keep your log file from growing too fast)
FR_LOGGING_LIMIT="-m limit --limit 5/min"
#Logging level for FR_IPTables
#Network subnet classes
#LOOPBACK adapter classs
#Traceroute source and destination ports
#Loading iptables kernel modules now and by default on system startup
FR_IPT_KERNEL_MODULES="modprobe ip_tables modprobe ip_conntrack modprobe ip_conntrack_ftp ipt_LOG ip_nat_ftp"
echo $FR_IPT_KERNEL_MODULES > /etc/modprobe.d/fr_iptables.conf
#Clearing existing firewall rules
#Creating our own firewall chains
$FR_IPT -N syn-flood
$FR_IPT -N bad-packets
$FR_IPT -N logndrop
#Allow all local (FR_LOOPBACK) traffic
#Accept packets for already established or related (like passive-ftp) connections
#================================= Firewall Protection section ================================
#Anti syn-flood. Disabled temporarily as this can lead to DoS quickly
#$FR_IPT -A INPUT -i $FR_INET_IFACE -p tcp --syn -m limit --limit 100/s --limit-burst 1000 -j syn-flood
#$FR_IPT -A syn-flood $FR_LOGGING_LIMIT -j LOG --log-prefix "{fw}SYN flood: "
#$FR_IPT -A syn-flood -j DROP
#Preventing spoofing (sending RST as a response to SYN/ACK to all newly arriving packets)
$FR_IPT -A INPUT -p tcp --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Spoofing: "
$FR_IPT -A bad-packets -p tcp --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j REJECT --reject-with tcp-reset
#Dropping all packets except SYN, that are new with logging
$FR_IPT -A INPUT -p tcp ! --syn -m conntrack --ctstate NEW -j bad-packets
$FR_IPT -A bad-packets -p tcp ! --syn -m conntrack --ctstate NEW $FR_LOGGING_LIMIT -j LOG --log-prefix "{fw}New not syn:"
#Enable outgoing ping
$FR_IPT -A INPUT -p icmp -m icmp -i $FR_INET_IFACE --icmp-type echo-reply -j ACCEPT
$FR_IPT -A OUTPUT -p icmp -m icmp -o $FR_INET_IFACE --icmp-type echo-request -j ACCEPT
# Detecting port scanning from nmap and such
$FR_IPT -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags ALL FIN,URG,PSH $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth scan: "
$FR_IPT -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth XMAS-PSH scan: "
$FR_IPT -A INPUT -p tcp --tcp-flags ALL ALL -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags ALL ALL $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth XMAS-ALL scan: "
$FR_IPT -A INPUT -p tcp --tcp-flags ALL FIN -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags ALL FIN $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth FIN scan: "
$FR_IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags SYN,RST SYN,RST $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth SYN/RST scan: "
$FR_IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags SYN,FIN SYN,FIN $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth SYN/FIN scan(?): "
$FR_IPT -A INPUT -p tcp --tcp-flags ALL NONE -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-flags ALL NONE $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Stealth Null scan: "
#Logging and dropping packets with invalid TCP options
$FR_IPT -A INPUT -p tcp --tcp-option 64 -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-option 64  $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Bad TCP flag(64): "
$FR_IPT -A INPUT -p tcp --tcp-option 128 -j bad-packets
$FR_IPT -A bad-packets -p tcp --tcp-option 128  $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Bad TCP flag(128): "
#Detecting OS fingerprinting attempts.
$FR_IPT -A INPUT -p tcp --dport 0 -j bad-packets
$FR_IPT -A bad-packets -p tcp --dport$FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}TCP0-OS fingerprint: "
$FR_IPT -A INPUT -p udp --dport 0 -j bad-packets
$FR_IPT -A bad-packets -p udp --dport$FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}UDP0-OS fingerprint: "
#Dropping fragmented packets
# Sending lots of non-first fragments was what allowed Jolt2 to effectively "drown"
# Firewall-1. Fragments can be overlapped, and the subsequent interpretation of such
# fragments is very OS-dependent (see this paper for details).
# I am not going to trust any fragments.
# Log fragments just to see if we get any, and deny them too.
$FR_IPT -A INPUT -f -j bad-packets
$FR_IPT -A bad-packets -f $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Fragments: "
# Refuse spoofed packets pretending to be from your IP address.
$FR_IPT -A bad-packets -i $FR_INET_IFACE -s $FR_INET_IFACE_ADDR $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingL: "
# Refuse packets claiming to be from a Class A private network.
$FR_IPT -A INPUT -i $FR_INET_IFACE -s $FR_CLASS_A -j bad-packets
$FR_IPT -A bad-packets -i $FR_INET_IFACE -s $FR_CLASS_A $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingA: "
# Refuse packets claiming to be from a Class B private network.
$FR_IPT -A INPUT -i $FR_INET_IFACE -s $FR_CLASS_B -j bad-packets
$FR_IPT -A bad-packets -i $FR_INET_IFACE -s $FR_CLASS_B $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingB: "
# Refuse packets claiming to be from a Class C private network.
$FR_IPT -A INPUT -i $FR_INET_IFACE -s $FR_CLASS_C -j bad-packets
$FR_IPT -A bad-packets -i $FR_INET_IFACE -s $FR_CLASS_C $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingC: "
# Refuse Class D multicast addresses. Multicast is illegal as a source address.
$FR_IPT -A bad-packets -i $FR_INET_IFACE -s $FR_CLASS_D_MULTICAST $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingD: "
# Refuse Class E reserved IP addresses.
$FR_IPT -A bad-packets -i $FR_INET_IFACE -s $FR_CLASS_E_RESERVED_NET $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingE: "
# Refuse packets claiming to be to the FR_LOOPBACK interface.
# Refusing packets claiming to be to the FR_LOOPBACK interface protects against
# source quench, whereby a machine can be told to slow itself down by an icmp source
# quench to the FR_LOOPBACK.
$FR_IPT -A INPUT -i $FR_INET_IFACE -d $FR_LOOPBACK -j bad-packets
$FR_IPT -A bad-packets -i $FR_INET_IFACE -d $FR_LOOPBACK $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}SpoofingLP: "
# Refuse broadcast address packets.
$FR_IPT -A INPUT -i $FR_INET_IFACE -m pkttype --pkt-type broadcast -j bad-packets
$FR_IPT -A bad-packets -i $FR_INET_IFACE -m pkttype --pkt-type broadcast $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Broadcast: "
## AUTH server
# Reject ident probes with a tcp reset.
# Need to do this for a broken mailhost that won't accept mail if just drop its ident probe.
$FR_IPT -A INPUT -i $FR_INET_IFACE -p tcp --dport 113 -j bad-packets
$FR_IPT -A bad-packets -i $FR_INET_IFACE -p tcp --dport 113 $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}IdentProbe: "
$FR_IPT -A bad-packets -i $FR_INET_IFACE -p tcp --dport 113 -j REJECT --reject-with tcp-reset
# Outgoing traceroute anywhere.
# The reply to a traceroute is an icmp time-exceeded which is dealt with by the next rule.
$FR_IPT -A OUTPUT -o $FR_INET_IFACE -p udp --sport $FR_TR_SRC_PORTS --dport $FR_TR_DEST_PORTS -m conntrack --ctstate NEW -j ACCEPT
# We always allow icmp out.
#===================================== Bad packets chain actions =========================
# Unmatched rule if we made a mistake in setting logging up
$FR_IPT -A bad-packets $FR_LOGGING_LIMIT -j LOG --log-prefix "{fw}UNKNOWN:"
# Dropping bad packets
$FR_IPT -A bad-packets -j DROP
#===================================== Server software ACCEPT section ====================
#DNS client
$FR_IPT -A OUTPUT -p tcp -m tcp -o $FR_INET_IFACE --dport 53 -j ACCEPT
$FR_IPT -A OUTPUT -p udp -m udp -o $FR_INET_IFACE --dport 53 -j ACCEPT
$FR_IPT -A INPUT -p udp -m udp -i $FR_INET_IFACE --dport 53 -j ACCEPT
#DNS server
$FR_IPT -A OUTPUT -p udp -m udp -o $FR_INET_IFACE --dport 53 -j ACCEPT
$FR_IPT -A INPUT -p udp -m udp -i $FR_INET_IFACE --dport 53 -j ACCEPT
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 53 -j ACCEPT
#SMTP server (25)
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 25 -j ACCEPT
$FR_IPT -A OUTPUT -p tcp -m tcp -o $FR_INET_IFACE --dport 25 -j ACCEPT
#POP3 server (110)
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 110 -j ACCEPT
#IMAP4 server(143)
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 143 -j ACCEPT
#SSH server (22)
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 22 -j ACCEPT
#Prevent SSH bruteforcing
#$FR_IPT -A INPUT -p tcp --dport 25671 -m recent --set --name ssh --rsource
#$FR_IPT -A INPUT -p tcp --dport 25671 -m recent ! --rcheck --seconds 60 --hitcount 4 --name ssh --rsource -j ACCEPT
#FTP server(21)
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 21 -j ACCEPT #Main FTP port
$FR_IPT -A OUTPUT -p tcp -m tcp -o $FR_INET_IFACE --sport 20 -j ACCEPT #Active FTP port
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 65400:65534 -j ACCEPT #Passive FTP
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE --dport 10000 -j ACCEPT
#HTTP/HTTPS server (80, 443)
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE -j ACCEPT --dport 80
$FR_IPT -A INPUT -p tcp -m tcp -i $FR_INET_IFACE -j ACCEPT --dport 443
$FR_IPT -A OUTPUT -p tcp -m tcp -o $FR_INET_IFACE -j ACCEPT --dport 80
$FR_IPT -A INPUT -p udp -m udp  --destination-port 123 -j ACCEPT
# Allow telnet outbound.
$FR_IPT -A OUTPUT -o $FR_INET_IFACE -p tcp --dport 23 -j ACCEPT
#NTPD Time Synchronization
$FR_IPT -A OUTPUT -o $FR_INET_IFACE -p udp --dport 123 -m conntrack --ctstate NEW -j ACCEPT
$FR_IPT -A INPUT -i $FR_INET_IFACE -p udp --dport 123 -m conntrack --ctstate NEW -j ACCEPT
#===================================== Finalizing actions ================================
#Dropping invalid packets, not related to the rules above
$FR_IPT -A INPUT -m conntrack --ctstate INVALID -j bad-packets
$FR_IPT -A bad-packets -m conntrack --ctstate INVALID $FR_LOGGING_LIMIT -j LOG --log-level $FR_LOGLEVEL --log-prefix "{fw}Invalid: "
# Redirecting all traffic not matching our rules to logndrop chain to log & drop it
$FR_IPT -A INPUT $FR_LOGGING_LIMIT -j logndrop#Logging all other dropped packets just for info
$FR_IPT -A logndrop -p tcp $FR_LOGGING_LIMIT -j LOG --log-prefix "Denied TCP: " --log-level $FR_LOGLEVEL
$FR_IPT -A logndrop -p udp $FR_LOGGING_LIMIT -j LOG --log-prefix "Denied UDP: " --log-level $FR_LOGLEVEL
$FR_IPT -A logndrop -p icmp $FR_LOGGING_LIMIT -j LOG --log-prefix "Denied ICMP: " --log-level $FR_LOGLEVEL
$FR_IPT -A logndrop -j DROP
#Setting default chain policy just to be sure of 😉

Tags: , , ,

Leave a Reply

You must be logged in to post a comment. Login now.