Webserver install - Part 3 - Hardening II. - Debian Lenny

This tutorial is part of The LAB project.

 

Network hardening

The first step of network hardening is disabling the IPv6 protocol. I know that the IPv4 addresses are almost "depricated" but in our country it is still the standard and as I know it still standard everywhere. Maybe later I'll create an IPv6 config but now I don't really have an environment to test it.

 

Disable IPv6

There are several ways you can do this. I chose one that worked for me and for many other people.

The main thing is to disable this feature in modprobe.d. You have to create the /etc/modprobe.d/00local file to make this the first thing in the chain to be run. Three lines will be put into this file like this:

echo "blacklist ipv6" > /etc/modprobe.d/00local
echo "alias net-pf-10 off" >> /etc/modprobe.d/00local
echo "alias ipv6 off" >> /etc/modprobe.d/00local

In the /etc/hosts file the settings should also be disabled. Comment out everything that is ipv6 related:

nano /etc/hosts

I had to comment out the following lines:

#::1     localhost ip6-localhost ip6-loopback
#fe00::0 ip6-localnet
#ff00::0 ip6-mcastprefix
#ff02::1 ip6-allnodes
#ff02::2 ip6-allrouters
#ff02::3 ip6-allhosts

You should also disable IPv6 in the other services configs like exim, ssh... if you want to do so.

 

To make the changes effective you have to reboot, however I won't do that right now because I want to set some kernel parameters before that.


 

Kernel network parameters hardening

There are two ways to change the settings for the kernel.

  1. Modify /etc/sysctl.conf - this applies to all network interfaces at boot time
  2. Modify /etc/init.d/networking - this can be customized and different to the different interfaces at ethenet initialization time

I chose the 2nd one in this guide because it is more complicated than the first one and more custom. You could choose the first one if you prefer and than you just have to modify the same settings in the sysctl.conf.

 

To be very secure I change the file permission of the sysctl.conf file:

chmod 0600 /etc/sysctl.conf

The first step is to create a script that will run at interface-up time. This script will only work for ipv4 as you can see it.

nano /etc/network/interface-secure

Copy the followings to the file. Of course you should check and customize all settings to your needs before proceeding.

#!/bin/sh -e
# Script-name: /etc/network/interface-secure
#
# Modifies some default behavior in order to secure against 
# some TCP/IP spoofing & attacks for a given interface.
# 
IFACE=$1
if [ -z "$IFACE" ] ; then
	echo "$0: Interface name must be given as argument!"
	echo "Usage: $0 <interface>"
	exit 1
fi
 
if [ ! -e /proc/sys/net/ipv4/conf/$IFACE/ ]; then
	echo "$0: Interface $IFACE does not exit (cannot find /proc/sys/net/ipv4/conf/)"
	exit 1
fi
 
#
# IP spoofing protection.
echo 1 > /proc/sys/net/ipv4/conf/$IFACE/rp_filter
#echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
 
echo 1 > /proc/sys/net/ipv4/tcp_syncookies 
# TCP syn cookies protection enabled.
# Set backlog below according to this.
 
echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog
# increase this if there is overload (min 256MB RAM needed). 
# Syncookies has to
# be enabled to use this variable
# CIS benchmark suggests 4096
# change TCP_SYNQ_HSIZE in include/net/tcp.h
# to keep TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog
# and then you need to recompile kernel
 
echo 0 > /proc/sys/net/ipv4/conf/$IFACE/forwarding
# IP packet forwarding disabled.
 
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 
# Broadcast echo protection enabled.
 
echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses 
# Bad error message protection enabled.
 
# Disable ICMP redirect acceptance.
echo 0 > /proc/sys/net/ipv4/conf/$IFACE/accept_redirects
echo 0 > /proc/sys/net/ipv4/conf/$IFACE/send_redirects
 
# Disable source routed packets.
echo 0 > /proc/sys/net/ipv4/conf/$IFACE/accept_source_route
 
echo 0 >/proc/sys/net/ipv4/conf/$IFACE/log_martians 
# Log strange packets.
 
exit 0

Save the file, exit from nano, change permissions and make it executable.

chmod 0744 /etc/network/interface-secure

Edit the network config file /etc/network/interfaces and modify it:

nano /etc/network/interfaces

Add this line to the end of your network interface config:

    pre-up /etc/network/interface-secure eth0

My settings look like this now:

# The loopback network interface
auto lo
iface lo inet loopback
 
auto eth0
iface eth0 inet static
        address 20.0.0.10
        netmask 255.255.255.0
        network 20.0.0.0
        broadcast 20.0.0.255
        gateway 20.0.0.100
        pre-up /etc/network/interface-secure eth0

If your interface is not eth0 you can simply change it in the above config to yours.


 

Setting up iptables firewall permanently

Previously I have created a script but it was temporary. After reboot it will disappear. Now I create a permanent iptables config. The first thing is to create the rules than save them to a file which will be executed at interface initialization time.

Create the script to generate the rules:

nano iptables_rules.sh

Copy-paste your rules, or my rules to the file. As you can see there are some ports open because they will be needed for the update, package download or something else... . Incoming SSH (remote login) traffic, outgoing NTP (time sync), HTTP, HTTPS, FTP (updates) and the DNS (updates) in both directions are enbaled.

#!/bin/sh
#
#############################################################################
#
# File: iptables.sh
#
# Purpose: To build a basic iptables policy with default log and drop rules.
#          This script was written for the book "Linux Firewalls: Attack
#          Detection and Response" published by No Starch Press.
#
#############################################################################
#
 
IPTABLES=/sbin/iptables
MODPROBE=/sbin/modprobe
INT_NET=20.0.0.0/24
 
### flush existing rules and set chain policy setting to DROP
echo "[+] Flushing existing iptables rules..."
$IPTABLES -F
$IPTABLES -F -t nat
$IPTABLES -X
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -P FORWARD DROP
 
### load connection-tracking modules
$MODPROBE ip_conntrack
$MODPROBE ip_conntrack_ftp
 
###### INPUT chain ######
#
echo "[+] Setting up INPUT chain..."
 
### state tracking rules
$IPTABLES -A INPUT -m state --state INVALID -j LOG --log-prefix "DROP INVALID " --log-ip-options --log-tcp-options
$IPTABLES -A INPUT -m state --state INVALID -j DROP
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
 
### ACCEPT rules
$IPTABLES -A INPUT -i eth0 -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
 
### default INPUT LOG rule
$IPTABLES -A INPUT -i ! lo -j LOG --log-prefix "DROP " --log-ip-options --log-tcp-options
 
### make sure that loopback traffic is accepted
$IPTABLES -A INPUT -i lo -j ACCEPT
 
###### OUTPUT chain ######
#
echo "[+] Setting up OUTPUT chain..."
 
### state tracking rules
$IPTABLES -A OUTPUT -m state --state INVALID -j LOG --log-prefix "DROP INVALID " --log-ip-options --log-tcp-options
$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
 
### ACCEPT rules for allowing connections out
$IPTABLES -A OUTPUT -p tcp --dport 21 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 80 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 443 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p udp --sport 123 --dport 123 -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
### default OUTPUT LOG rule
$IPTABLES -A OUTPUT -o ! lo -j LOG --log-prefix "DROP " --log-ip-options --log-tcp-options
 
### make sure that loopback traffic is accepted
$IPTABLES -A OUTPUT -o lo -j ACCEPT
 
###### FORWARD chain ######
#
echo "[+] NO FORWARD chain..."
 
###### NAT rules ######
#
echo "[+] NO NAT rules..."
 
###### forwarding ######
#
echo "[+] NO IP forwarding..."
 
exit
### EOF ### 

Change file permissions and make the script executable:

chmod 0700 iptables_rules.sh

To make the configuration effective run the script. It will disconnect you when it flushes the rules than you can reconnect back.

./iptables_rules.sh

You can check the applied rules with the following command:

iptables -L

If everything is ok you have to save the applied rules to a file (can be custom, I chose /etc/iptables_rules):

iptables-save > /etc/iptables.rules

This config file will be initiated at interface initialization time. For this we have to edit /etc/network/interfaces again:

nano /etc/network/interfaces

Put the following line to the end of the interface config:

pre-up iptables-restore < /etc/iptables.rules

Now my file looks like this:

auto lo
iface lo inet loopback
 
auto eth0
iface eth0 inet static
        address 20.0.0.10
        netmask 255.255.255.0
        network 20.0.0.0
        broadcast 20.0.0.255
        gateway 20.0.0.100
        pre-up /etc/network/interface-secure eth0
        pre-up iptables-restore < /etc/iptables.rules

Save the file and close it.

 

Now just reboot the system to make the changes effective and test them.

reboot

Cron hardening

Cron hardening is a controversial thing. I was thinking about the effect of the suggested hardenings and there are some side effects. CIS suggests to make it only accesible to root however I know from heart at least 5 applications that require the read permission in order to check their "maintenance" tasks schedule. I am a security guy so I accept some inconvinience but remember when you see cron errors to search them here:).

 

"cron" and "at" are the primary targets for hackers when there is no other way to execute a script therefore they must be protected very strictly. The thing I will do is restrict access to crons config files to be accessible only by root.

Do the followings:

cd /etc
echo root > cron.allow
echo root > at.allow
chown root:root cron.allow at.allow
chmod 400 cron.allow at.allow
 
chown root:root /etc/crontab
chmod 400 /etc/crontab
 
chown -R root:root /var/spool/cron
chmod -R go-rwx /var/spool/cron
ls | grep cron | xargs chown -R root:root
ls | grep cron | xargs chmod -R go-rwx

 

Install NTP

It is very important to have the correct time on the server for several reasons. Linux systems do not like big gaps in the time continuum and it is much more hard to trace something in the logs if the time is not continous or there is a big difference to the real time.

 

To synchronize the time of the server with NTP servers you have to install ntp daemon. This tool will smoothly corrigate time so there will be no gaps in the logs. ntpdate is another tool to sync from commandline.

Install the tools from the Debian repository.

aptitude install ntp ntpdate

The following additional packages will be installed:

libcap1 lockfile-progs

You can modify the ntp settings and the time servers here:

nano /etc/ntp.conf

Links:

Scripts: http://www.cipherdyne.org/LinuxFirewalls/

The BOOK: http://www.nostarch.com/firewalls_mr.htm

Kernel parameters: http://www.frozentux.net/ipsysctl-tutorial/chunkyhtml/tcpvariables.html

 

The next tutorial is: Webserver install - Part 4 - Hardening III. - Debian Lenny