The following firewall scripts will help you secure your web and db servers placed on the internet. The scenario is such that the MySQL db server is desired to receive db connections / traffic only from the web server. The following is the list of services running on each server: Web Server (200.10.20.31): FTP, SSH, HTTP, HTTPS, SMTP, POP3, IMAP, POP3S, IMAPS, MySQL (for some local services[qmail/vpopmail]) DB Server (200.10.20.32): SSH, HTTP, HTTPS, MySQL (only to receive traffic from Web Server) The following scripts are currently implemented on live servers so they are 100% tested. Still, USE THEM AT YOUR OWN RISK. Below are two scripts (create as /etc/firewall.sh), one for Web Server and one for DB server. And below them, a startup (init.d) script common for both. WebServer :- vi /etc/firewall.sh 1 / 12
!/bin/bash Author: Muhammad Kamran Azeem (kamran _at_ wbitt _dot_ com) Created: 20080410 Revision History: 20080706, 20080412 Proposed implementation: On StandAlone web servers Current Implementation: StandAlone web server Various tools: nmap -su publichost scans UDP ports The following reports total number of connections netstat -anp grep 'tcp udp' awk '{print $5}' cut -d: -f1 sort uniq -c sort -n Once system is secured, test your firewall with nmap or hping2 command: nmap -v -f FIREWALL-IP nmap -v -sx FIREWALL-IP nmap -v -sn FIREWALL-IP nmap -v -ss FIREWALL-IP hping2 -X FIREWALL-IP ping -f FIREWALL_IP ping -s 65507 192.168.0.230 User configurable parameters - START - The Public interface of this server towards Internet:- PUBLICIF=eth0 The Public IP of this server (on $PUBLICIF) visible/accessable from the Internet:- PUBLICIP=200.10.20.31 The full path to the iptables program:- IPTABLES=/sbin/iptables 2 / 12
User configurable parameters - END - Load Modules - Start Load FTP connection tracking module. Without it, FTP to this server will NOT work. Because we have DROPed all INPUT packets at the end of this firewall. modprobe ip_conntrack_ftp modprobe ip_conntrack Load Modules - End Kernel Parameters - Start Various Kernel paramters which you can (also) setup in /etc/sysctl.conf This following enables source address verification,, which is inbuilt into Linux kernel itself. net.ipv4.conf.all.rp_filter = 1 echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter Kernel Parameters - End $IPTABLES -F $IPTABLES -t nat -F ports list: 22/tcp - SSH 25/tcp - SMTP 53/tcp - DNS 53/udp - DNS 80/tcp - HTTP 443/tcp - HTTPS 110/tcp - POP3 995/tcp - POP3S 143/tcp - IMAP 993/tcp - IMAPS 123/tcp - NTP 123/udp - NTP 199/tcp - SNMP 161/UDP - SNMP 3 / 12
3306/tcp - MySQL 8443/tcp - Plesk Setup default INPUT policy as DROP. This is dangerous incase of flushing the rules. Instead, look at the end of this file for other method. $IPTABLES -P INPUT DROP <---- Don't use this method. allow packets coming from the machine $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT allow outgoing traffic $IPTABLES -A OUTPUT -o $PUBLICIF -j ACCEPT Allow the following traffic only:- $IPTABLES -A INPUT -i $PUBLICIF -p tcp -m multiport --dport 21,22,25,53,80,443,110,995,143,993 -j ACCEPT $IPTABLES -A INPUT -i $PUBLICIF -p udp -m multiport --dport 53 -j ACCEPT Block spoofing $IPTABLES -A INPUT -s 127.0.0.0/8 -i! lo -j DROP More sophisticated / wide ranged method is below:- Add your IP range/ips here, Yes, I am sure that the last address has 16 bit subnet for a VALID reason SPOOFLIST="0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/16 192.168.0.0/16 224.0.0.0/3" for ip in $SPOOFLIST do $IPTABLES -A INPUT -i $PUBLICIF -s $ip -j DROP done Stop bad packets $IPTABLES -A INPUT -m state --state INVALID -j DROP Stop NMAP FIN/URG/PSH $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP Stop Xmas Tree type scanning $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL ALL -j DROP 4 / 12
$IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP Stop null scanning $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL NONE -j DROP Stop SYN/RST $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags SYN,RST SYN,RST -j DROP Stop SYN/FIN $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP If the incoming SYN packets are not NEW, we need to DROP them:- $IPTABLES -A INPUT -p tcp! --syn -m state --state NEW -j DROP Stop ping flood attack DROP ICMP packets size larger than 56(84) bytes iptables -A INPUT -p icmp --icmp-type echo-request -m length --length 85: -j REJECT --reject-with icmp-host-prohibited The above works! See two outputs below: [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 56 PING yourdomain.com (1.2.3.4) 56(84) bytes of data. 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=1 ttl=42 time=1140 ms 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=2 ttl=42 time=799 ms... Just by increasing one byte in the packet size has resulted in packet DROPs. Alhumdulillah. [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 57 PING yourdomain.com (1.2.3.4) 57(85) bytes of data. From www.yourdomain.com (1.2.3.4) icmp_seq=1 Destination Host Prohibited From www.yourdomain.com (1.2.3.4) icmp_seq=2 Destination Host Prohibited... Allow maximum two incoming ICMP packets per second iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT Hopefuly spamassassin, NTP, Razor, DNS, DCCIFD, etc will keep working properly, because of the following two rules. $IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 5 / 12
Setup the default INPUT policy as DROP. Note that -P for POLICY is NOT used below. Instead, since all desired traffic is allowed before these lines, we will just drop all of the other packets coming on $PUBLICIF $IPTABLES -A INPUT -i eth0 -j DROP exit 0 DB Server :- vi /etc/firewall.sh!/bin/bash Author: Muhammad Kamran Azeem (kamran _at_ wbitt _dot_ com) Created: 20080410 Revision History: 20080706, 20080513 Implemented on this server: 20080513 Proposed implementation: On db servers Current implementation: Customized for this DB server Various tools: nmap -su PUBLIChost scans UDP ports The following reports total number of connections netstat -anp grep 'tcp udp' awk '{print $5}' cut -d: -f1 sort uniq -c sort -n Once system is secured, test your firewall with nmap or hping2 command: nmap -v -f FIREWALL-IP nmap -v -sx FIREWALL-IP nmap -v -sn FIREWALL-IP nmap -v -ss FIREWALL-IP 6 / 12
hping2 -X FIREWALL-IP ping -f FIREWALL_IP ping -s 65507 FIREWALL_IP User configurable parameters - START - The Public interface of this server towards Internet:- PUBLICIF=eth0 The Public IP of this server (on $PUBLICIF) visible/accessable from the Internet. (Use ifconfig to find out):- PUBLICIP=200.10.20.32 The IP of WebServer accessing this machine/db server WEBSERVERIP=200.10.20.31 The full path to the iptables program:- IPTABLES=/sbin/iptables User configurable parameters - END - Load Modules - Start Load FTP connection tracking module. Witihout it, FTP to this server will NOT work. Because we have DROPed all INPUT packets at the end of this firewall. modprobe ip_conntrack_ftp modprobe ip_conntrack Load Modules - End Kernel Parameters - Start 7 / 12
Various Kernel paramters which you can (also) setup in /etc/sysctl.conf This following enables source address verification,, which is inbuilt into Linux kernel itself. net.ipv4.conf.all.rp_filter = 1 echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter Kernel Parameters - End $IPTABLES -F $IPTABLES -t nat -F ports list: 22/tcp - SSH 25/tcp - SMTP 80/tcp - HTTP 443/tcp - HTTPS 110/tcp - POP3 995/tcp - POP3S 143/tcp - IMAP 993/tcp - IMAPS 123/tcp - NTP 123/udp - NTP 199/tcp - SNMP 161/UDP - SNMP 3306/tcp - MySQL Setup default INPUT policy as DROP. This is dangerous incase of flushing the rules. Instead, look at the end of this file for other method. $IPTABLES -P INPUT DROP <---- Don't use this method. allow packets coming from the machine $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT allow outgoing traffic $IPTABLES -A OUTPUT -o $PUBLICIF -j ACCEPT Allow the following traffic only:- The following are allowed to get traffic from all over the world:- $IPTABLES -A INPUT -i $PUBLICIF -p tcp -m multiport --dport 21,22,80,443 -j ACCEPT 8 / 12
And the following ports are only allowed to get traffic from $WEBSERVERIP $IPTABLES -A INPUT -i $PUBLICIF -p tcp -s $WEBSERVERIP --dport 3306 -j ACCEPT Block spoofing $IPTABLES -A INPUT -s 127.0.0.0/8 -i! lo -j DROP OR more sophisticated / wide ranged method is below:- Add your IP range/ips here, Yes I am sure that the last address has 16 bit subnet for a VALID reason SPOOFLIST="0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/16 192.168.0.0/16 224.0.0.0/3" for ip in $SPOOFLIST do $IPTABLES -A INPUT -i $PUBLICIF -s $ip -j DROP done Stop bad packets $IPTABLES -A INPUT -m state --state INVALID -j DROP Stop NMAP FIN/URG/PSH $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP Stop Xmas Tree type scanning $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL ALL -j DROP $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP Stop null scanning $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags ALL NONE -j DROP Stop SYN/RST $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags SYN,RST SYN,RST -j DROP Stop SYN/FIN $IPTABLES -A INPUT -i $PUBLICIF -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP If the incoming SYN packets are not NEW, we need to DROP them:- $IPTABLES -A INPUT -p tcp! --syn -m state --state NEW -j DROP Stop ping flood attack 9 / 12
DROP ICMP packets size larger than 56(84) bytes :- iptables -A INPUT -p icmp --icmp-type echo-request -m length --length 85: -j REJECT --reject-with icmp-host-prohibited The above works! See two outputs below: [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 56 PING yourdomain.com (1.2.3.4) 56(84) bytes of data. 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=1 ttl=42 time=1140 ms 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=2 ttl=42 time=799 ms... Just by increasing one byte in the packet size has resulted in packet DROPs. Alhumdulillah. [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 57 PING yourdomain.com (1.2.3.4) 57(85) bytes of data. From www.yourdomain.com (1.2.3.4) icmp_seq=1 Destination Host Prohibited From www.yourdomain.com (1.2.3.4) icmp_seq=2 Destination Host Prohibited... Allow maximum two incoming ICMP packets per second iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 2/s -j ACCEPT Hopefuly spamassassin, NTP, Razor, DNS, DCCIFD, etc will keep working properly, because of the following two rules. $IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT Setup the default INPUT policy as DROP. Note that -P for POLICY is NOT used below. Instead, since all desired traffic is allowed before these lines, we will just drop all of the other packets coming on $PUBLICIF $IPTABLES -A INPUT -i eth0 -j DROP exit 0 And now the startup (init.d) script to be used on both servers:- 10 / 12
Create as /etc/init.d/firewall vi /etc/init.d/firewall!/bin/bash firewall Startup script for our personal firewall chkconfig: - 01 99 description: Our own custom built firewall setup processname: firewall Source function library.. /etc/rc.d/init.d/functions prog=/etc/firewall.sh lockfile=/var/lock/subsys/firewall RETVAL=0 start() { echo -n "Starting $prog: ". /etc/firewall.sh RETVAL=$? echo [ $RETVAL = 0 ] && touch ${lockfile} return $RETVAL } stop() { echo -n $"Stopping $prog: " /sbin/iptables -F /sbin/iptables -t nat -F /sbin/iptables -P INPUT ACCEPT /sbin/iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT RETVAL=$? echo [ $RETVAL = 0 ] && rm -f ${lockfile} } See how we were called. case "$1" in start) start ;; stop) 11 / 12
stop ;; status) /sbin/iptables -L ;; restart) stop start ;; *) echo $"Usage: $prog {start stop status restart}" RETVAL=3 esac exit $RETVAL Final steps:- Make the three scripts executable by: chmod +x /etc/firewall.sh /etc/init.d/firewall.sh chkconfig --level 35 firewall on That should be all. 12 / 12